]> granicus.if.org Git - clang/commitdiff
More improvements with laying out empty bases.
authorAnders Carlsson <andersca@mac.com>
Thu, 24 Sep 2009 05:21:31 +0000 (05:21 +0000)
committerAnders Carlsson <andersca@mac.com>
Thu, 24 Sep 2009 05:21:31 +0000 (05:21 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82682 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 062ce4f5bc2fd09dc8c77b2a6211aab80aa7bb44..dec6402d3699953d2da4d7f7b0c20f5b5748941a 100644 (file)
@@ -230,7 +230,25 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
       return false;
   }
   
-  // FIXME: Bases and fields.
+  const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+  // Check bases.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    if (I->isVirtual())
+      continue;
+    
+    const CXXRecordDecl *Base =
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+    uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
+    
+    if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset))
+      return false;
+  }
+  
+  // FIXME: fields.
+  // FIXME: virtual bases.
   return true;
 }
 
@@ -238,8 +256,23 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
                                                      uint64_t Offset) {
   if (RD->isEmpty())
     EmptyClassOffsets.insert(std::make_pair(Offset, RD));
+  
+  const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+  // Update bases.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    if (I->isVirtual())
+      continue;
+    
+    const CXXRecordDecl *Base =
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
     
-  // FIXME: Update bases and fields.
+    uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
+    UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset);
+  }
+  
+  // FIXME: Update fields and virtual bases.
 }
 
 uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
@@ -248,25 +281,35 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
   // If we have an empty base class, try to place it at offset 0.
   if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
     // We were able to place the class at offset 0.
-    // Since the base is empty we don't have to update the size or alignment.
     UpdateEmptyClassOffsets(RD, 0);
-    
+
+    Size = std::max(Size, BaseInfo.getNonVirtualSize());
+
     return 0;
   }
   
   unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
+  
   // Round up the current record size to the base's alignment boundary.
   uint64_t Offset = llvm::RoundUpToAlignment(Size, BaseAlign);
   
-  // Reserve space for this base.
-  Size = Offset + BaseInfo.getNonVirtualSize();
-  
+  // Try to place the base.
+  while (true) {
+    if (canPlaceRecordAtOffset(RD, Offset))
+      break;
+    
+    Offset += BaseAlign;
+  }
+
   // Remember the next available offset.
-  NextOffset = Size;
+  NextOffset = Offset + BaseInfo.getNonVirtualSize();
+
+  Size = std::max(Size, NextOffset);
   
   // Remember max struct/class alignment.
   UpdateAlignment(BaseAlign);
-  
+
+  UpdateEmptyClassOffsets(RD, Offset);
   return Offset;
 }
 
index 24688fad0736e93120b660a840d30fcec1675dc3..ebbeb38fc96fe5602b45703243bd49ad06d87f7a 100644 (file)
@@ -10,3 +10,10 @@ SA(1, sizeof(B) == 1);
 
 struct C : A, B { };
 SA(2, sizeof(C) == 4);
+
+struct D { };
+struct E : D { };
+struct F : E { };
+
+struct G : E, F { };
+SA(3, sizeof(G) == 2);