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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82746 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 09a2eff..2cf5925 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -307,6 +307,39 @@
// 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 @@
// We can't try again.
FieldOffset += FieldAlign;
}
+
+ UpdateEmptyClassOffsets(D, FieldOffset);
}
}
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index 0f83661..82b64fe 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -112,6 +112,10 @@
/// 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.
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 5ef5c0e..5925112 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -540,6 +540,9 @@
if (RD->isImplicit())
continue;
+ if (RD->isDependentType())
+ continue;
+
// FIXME: Do we really need to hard code this?
if (RD->getQualifiedNameAsString() == "__va_list_tag")
continue;
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
index fbe2cbe..09e7e4e 100644
--- a/test/SemaCXX/empty-class-layout.cpp
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -28,4 +28,18 @@
struct J : Empty {
Empty e[2];
};
-SA(5, sizeof(J) == 3);
\ No newline at end of file
+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);