diff options
author | Anders Carlsson <andersca@mac.com> | 2010-06-08 19:09:24 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-06-08 19:09:24 +0000 |
commit | 45f5b54d67215639ae6585d12df5133e99180c2b (patch) | |
tree | 3a5606c88e9d6778fa13f646673af2e0101f5806 | |
parent | 55d7d36f48b9b113e30de1721e83a639d14094b0 (diff) |
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
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 28 | ||||
-rw-r--r-- | test/SemaCXX/empty-class-layout.cpp | 28 |
2 files changed, 54 insertions, 2 deletions
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<CXXRecordDecl>(I->getType()->getAs<RecordType>()->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<CXXRecordDecl>(I->getType()->getAs<RecordType>()->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); + +} |