Who would have thought that empty classes were so tricky? Handle cases where an empty virtual base class needs to be moved aside because it conflicts with the first field.

llvm-svn: 82746
This commit is contained in:
Anders Carlsson 2009-09-25 01:54:38 +00:00
parent 0cf155174e
commit e1883100a3
4 changed files with 57 additions and 1 deletions

View File

@ -307,6 +307,39 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
// FIXME: Update fields and virtual bases. // FIXME: Update fields and virtual bases.
} }
void
ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t Offset) {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
UpdateEmptyClassOffsets(RD, Offset);
return;
}
}
if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
QualType ElemTy = Ctx.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return;
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return;
const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
unsigned ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
UpdateEmptyClassOffsets(RD, ElementOffset);
ElementOffset += Info.getSize();
}
}
}
uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
@ -527,6 +560,8 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
// We can't try again. // We can't try again.
FieldOffset += FieldAlign; FieldOffset += FieldAlign;
} }
UpdateEmptyClassOffsets(D, FieldOffset);
} }
} }

View File

@ -112,6 +112,10 @@ class ASTRecordLayoutBuilder {
/// EmptyClassOffsets map if the class is empty or has any empty bases or /// EmptyClassOffsets map if the class is empty or has any empty bases or
/// fields. /// fields.
void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset); void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset);
/// UpdateEmptyClassOffsets - Called after a field has been placed at the
/// given offset.
void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
/// FinishLayout - Finalize record layout. Adjust record size based on the /// FinishLayout - Finalize record layout. Adjust record size based on the
/// alignment. /// alignment.

View File

@ -540,6 +540,9 @@ public:
if (RD->isImplicit()) if (RD->isImplicit())
continue; continue;
if (RD->isDependentType())
continue;
// FIXME: Do we really need to hard code this? // FIXME: Do we really need to hard code this?
if (RD->getQualifiedNameAsString() == "__va_list_tag") if (RD->getQualifiedNameAsString() == "__va_list_tag")
continue; continue;

View File

@ -28,4 +28,18 @@ SA(4, sizeof(I) == 2);
struct J : Empty { struct J : Empty {
Empty e[2]; Empty e[2];
}; };
SA(5, sizeof(J) == 3); SA(5, sizeof(J) == 3);
template<int N> struct Derived : Empty, Derived<N - 1> {
};
template<> struct Derived<0> : Empty { };
struct S1 : virtual Derived<10> {
Empty e;
};
SA(6, sizeof(S1) == 24);
struct S2 : virtual Derived<10> {
Empty e[2];
};
SA(7, sizeof(S2) == 24);