]> granicus.if.org Git - clang/commitdiff
Who would have thought that empty classes were so tricky? Handle cases where an empty...
authorAnders Carlsson <andersca@mac.com>
Fri, 25 Sep 2009 01:54:38 +0000 (01:54 +0000)
committerAnders Carlsson <andersca@mac.com>
Fri, 25 Sep 2009 01:54:38 +0000 (01:54 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82746 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 09a2eff54ca43d371bdd7518e64871ed086a0d3a..2cf5925d39def2fe55b7a9aefe1b3bd6743cf827 100644 (file)
@@ -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<RecordType>()) {
+    if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+      UpdateEmptyClassOffsets(RD, Offset);
+      return;
+    }
+  }
+  
+  if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
+    QualType ElemTy = Ctx.getBaseElementType(AT);
+    const RecordType *RT = ElemTy->getAs<RecordType>();
+    if (!RT)
+      return;
+    const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(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);
     }
   }
 
index 0f83661cd9a8862e1f0fcd5eb88dcb44efce843d..82b64fe568a8f0d883b2e4d33fc0d60c5df54800 100644 (file)
@@ -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.
index 5ef5c0e6f05db5d75f1ba7d66ca814a9ab9d6ed7..59251121453f8bf491ed6265ca752a0835953595 100644 (file)
@@ -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;
index fbe2cbe6b464eb2f4fc88b86e052ec4310827f2d..09e7e4e37332e165fe3284b676881e8d26cd2d10 100644 (file)
@@ -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<int N> struct Derived : Empty, Derived<N - 1> { 
+};
+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);