From: Anders Carlsson Date: Fri, 25 Sep 2009 01:54:38 +0000 (+0000) Subject: Who would have thought that empty classes were so tricky? Handle cases where an empty... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a4c6081abd5582515b110bdcb576b4b85536467b;p=clang 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 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()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + UpdateEmptyClassOffsets(RD, Offset); + return; + } + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs(); + if (!RT) + return; + const CXXRecordDecl *RD = dyn_cast(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 struct Derived : Empty, Derived { +}; +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);