aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-09-25 01:54:38 +0000
committerAnders Carlsson <andersca@mac.com>2009-09-25 01:54:38 +0000
commita4c6081abd5582515b110bdcb576b4b85536467b (patch)
treeb2b49afc3a3bb59884fbcc9d6c177360cdf632b2
parenta180529e3d5d08dff2e2154d6a33a6c09f6af959 (diff)
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
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp35
-rw-r--r--lib/AST/RecordLayoutBuilder.h4
-rw-r--r--lib/Frontend/ASTConsumers.cpp3
-rw-r--r--test/SemaCXX/empty-class-layout.cpp16
4 files changed, 57 insertions, 1 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 09a2eff54c..2cf5925d39 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -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);
}
}
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index 0f83661cd9..82b64fe568 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -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.
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 5ef5c0e6f0..5925112145 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -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;
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
index fbe2cbe6b4..09e7e4e373 100644
--- a/test/SemaCXX/empty-class-layout.cpp
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -28,4 +28,18 @@ SA(4, sizeof(I) == 2);
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);