diff options
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 35 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.h | 4 | ||||
-rw-r--r-- | lib/Frontend/ASTConsumers.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/empty-class-layout.cpp | 16 |
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); |