Skip to content

Commit 4468720

Browse files
author
Anders Carlsson
committed
Correctly handle fields with virtual bases containing empty subobjects.
llvm-svn: 105628
1 parent e869a18 commit 4468720

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
201201
ClassVectorTy& Classes = EmptyClassOffsets[Offset];
202202
assert(std::find(Classes.begin(), Classes.end(), RD) == Classes.end() &&
203203
"Duplicate empty class detected!");
204-
204+
205205
Classes.push_back(RD);
206206

207207
// Update the empty class offset.
@@ -332,6 +332,19 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
332332
return false;
333333
}
334334

335+
if (RD == Class) {
336+
// This is the most derived class, traverse virtual bases as well.
337+
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
338+
E = RD->vbases_end(); I != E; ++I) {
339+
const CXXRecordDecl *VBaseDecl =
340+
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
341+
342+
uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
343+
if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset))
344+
return false;
345+
}
346+
}
347+
335348
// Traverse all member variables.
336349
unsigned FieldNo = 0;
337350
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
@@ -402,6 +415,7 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) {
402415
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
403416
const CXXRecordDecl *Class,
404417
uint64_t Offset) {
418+
405419
AddSubobjectAtOffset(RD, Offset);
406420

407421
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -419,6 +433,18 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
419433
UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
420434
}
421435

436+
if (RD == Class) {
437+
// This is the most derived class, traverse virtual bases as well.
438+
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
439+
E = RD->vbases_end(); I != E; ++I) {
440+
const CXXRecordDecl *VBaseDecl =
441+
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
442+
443+
uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
444+
UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
445+
}
446+
}
447+
422448
// Traverse all member variables.
423449
unsigned FieldNo = 0;
424450
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();

clang/test/SemaCXX/empty-class-layout.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,30 @@ struct B { A a; };
117117
struct C : B, Empty { };
118118
SA(0, sizeof(C) == 2);
119119

120-
}
120+
}
121+
122+
namespace Test5 {
123+
124+
// Test that B::Empty isn't laid out at offset 0.
125+
struct Empty { };
126+
struct Field : virtual Empty { };
127+
struct A {
128+
Field f;
129+
};
130+
struct B : A, Empty { };
131+
SA(0, sizeof(B) == 16);
132+
133+
}
134+
135+
namespace Test6 {
136+
137+
// Test that B::A isn't laid out at offset 0.
138+
struct Empty { };
139+
struct Field : virtual Empty { };
140+
struct A {
141+
Field f;
142+
};
143+
struct B : Empty, A { };
144+
SA(0, sizeof(B) == 16);
145+
146+
}

0 commit comments

Comments
 (0)