]> granicus.if.org Git - clang/commitdiff
Correctly handle fields with virtual bases containing empty subobjects.
authorAnders Carlsson <andersca@mac.com>
Tue, 8 Jun 2010 19:09:24 +0000 (19:09 +0000)
committerAnders Carlsson <andersca@mac.com>
Tue, 8 Jun 2010 19:09:24 +0000 (19:09 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105628 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/RecordLayoutBuilder.cpp
test/SemaCXX/empty-class-layout.cpp

index 77b6f8a1c3698795b47f1c4f04476178c99b89a5..7c0c8088e830ae6cf87c7ffdcb799d41b6cc9280 100644 (file)
@@ -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();
index bc2d58abd9a2c11cf5ffe69665c299e75bfc7c01..0b46bf045ac002ec26763f4d1342344abfed7b5f 100644 (file)
@@ -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);
+
+}