aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);