forked from OSchip/llvm-project
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:
parent
0cf155174e
commit
e1883100a3
|
@ -307,6 +307,39 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
|
|||
// 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) {
|
||||
const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
|
||||
|
||||
|
@ -527,6 +560,8 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
|
|||
// We can't try again.
|
||||
FieldOffset += FieldAlign;
|
||||
}
|
||||
|
||||
UpdateEmptyClassOffsets(D, FieldOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,10 @@ class ASTRecordLayoutBuilder {
|
|||
/// EmptyClassOffsets map if the class is empty or has any empty bases or
|
||||
/// fields.
|
||||
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
|
||||
/// alignment.
|
||||
|
|
|
@ -540,6 +540,9 @@ public:
|
|||
if (RD->isImplicit())
|
||||
continue;
|
||||
|
||||
if (RD->isDependentType())
|
||||
continue;
|
||||
|
||||
// FIXME: Do we really need to hard code this?
|
||||
if (RD->getQualifiedNameAsString() == "__va_list_tag")
|
||||
continue;
|
||||
|
|
|
@ -28,4 +28,18 @@ SA(4, sizeof(I) == 2);
|
|||
struct J : Empty {
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue