From: Anders Carlsson Date: Tue, 8 Jun 2010 19:09:24 +0000 (+0000) Subject: Correctly handle fields with virtual bases containing empty subobjects. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=45f5b54d67215639ae6585d12df5133e99180c2b;p=clang Correctly handle fields with virtual bases containing empty subobjects. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105628 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 77b6f8a1c3..7c0c8088e8 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -201,7 +201,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, ClassVectorTy& Classes = EmptyClassOffsets[Offset]; assert(std::find(Classes.begin(), Classes.end(), RD) == Classes.end() && "Duplicate empty class detected!"); - + Classes.push_back(RD); // Update the empty class offset. @@ -332,6 +332,19 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, return false; } + if (RD == Class) { + // This is the most derived class, traverse virtual bases as well. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *VBaseDecl = + cast(I->getType()->getAs()->getDecl()); + + uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); + if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset)) + return false; + } + } + // Traverse all member variables. unsigned FieldNo = 0; for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); @@ -402,6 +415,7 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) { void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *Class, uint64_t Offset) { + AddSubobjectAtOffset(RD, Offset); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -419,6 +433,18 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset); } + if (RD == Class) { + // This is the most derived class, traverse virtual bases as well. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *VBaseDecl = + cast(I->getType()->getAs()->getDecl()); + + uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); + UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset); + } + } + // Traverse all member variables. unsigned FieldNo = 0; for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp index bc2d58abd9..0b46bf045a 100644 --- a/test/SemaCXX/empty-class-layout.cpp +++ b/test/SemaCXX/empty-class-layout.cpp @@ -117,4 +117,30 @@ struct B { A a; }; struct C : B, Empty { }; SA(0, sizeof(C) == 2); -} \ No newline at end of file +} + +namespace Test5 { + +// Test that B::Empty isn't laid out at offset 0. +struct Empty { }; +struct Field : virtual Empty { }; +struct A { + Field f; +}; +struct B : A, Empty { }; +SA(0, sizeof(B) == 16); + +} + +namespace Test6 { + +// Test that B::A isn't laid out at offset 0. +struct Empty { }; +struct Field : virtual Empty { }; +struct A { + Field f; +}; +struct B : Empty, A { }; +SA(0, sizeof(B) == 16); + +}