[cfe-commits] r140623 - in /cfe/trunk: include/clang/AST/RecordLayout.h lib/AST/RecordLayout.cpp lib/AST/RecordLayoutBuilder.cpp test/Sema/ms_class_layout.cpp

Eli Friedman eli.friedman at gmail.com
Tue Sep 27 12:12:27 PDT 2011


Author: efriedma
Date: Tue Sep 27 14:12:27 2011
New Revision: 140623

URL: http://llvm.org/viewvc/llvm-project?rev=140623&view=rev
Log:
Some changes to improve compatibility for MSVC-style C++ struct layout. Patch from r4start at gmail.com (with some minor modifications by me).


Added:
    cfe/trunk/test/Sema/ms_class_layout.cpp
Modified:
    cfe/trunk/include/clang/AST/RecordLayout.h
    cfe/trunk/lib/AST/RecordLayout.cpp
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp

Modified: cfe/trunk/include/clang/AST/RecordLayout.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecordLayout.h?rev=140623&r1=140622&r2=140623&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecordLayout.h (original)
+++ cfe/trunk/include/clang/AST/RecordLayout.h Tue Sep 27 14:12:27 2011
@@ -63,6 +63,9 @@
     /// any empty subobjects.
     CharUnits SizeOfLargestEmptySubobject;
     
+    /// VBPtrOffset - Virtual base table offset.
+    CharUnits VBPtrOffset;
+    
     /// PrimaryBase - The primary base info for this record.
     llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
     
@@ -89,7 +92,8 @@
   // Constructor for C++ records.
   typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
   ASTRecordLayout(const ASTContext &Ctx,
-                  CharUnits size, CharUnits alignment, CharUnits datasize,
+                  CharUnits size, CharUnits alignment, CharUnits vbptroffset,
+                  CharUnits datasize,
                   const uint64_t *fieldoffsets, unsigned fieldcount,
                   CharUnits nonvirtualsize, CharUnits nonvirtualalign,
                   CharUnits SizeOfLargestEmptySubobject,
@@ -199,6 +203,10 @@
     assert(CXXInfo && "Record layout does not have C++ specific info!");
     return CXXInfo->SizeOfLargestEmptySubobject;
   }
+
+  CharUnits getVBPtrOffset() const {
+    return CXXInfo->VBPtrOffset;
+  }
 };
 
 }  // end namespace clang

Modified: cfe/trunk/lib/AST/RecordLayout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayout.cpp?rev=140623&r1=140622&r2=140623&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayout.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayout.cpp Tue Sep 27 14:12:27 2011
@@ -13,6 +13,7 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecordLayout.h"
+#include "clang/Basic/TargetInfo.h"
 
 using namespace clang;
 
@@ -42,7 +43,7 @@
 // Constructor for C++ records.
 ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
                                  CharUnits size, CharUnits alignment,
-                                 CharUnits datasize,
+                                 CharUnits vbptroffset, CharUnits datasize,
                                  const uint64_t *fieldoffsets,
                                  unsigned fieldcount,
                                  CharUnits nonvirtualsize,
@@ -67,15 +68,20 @@
   CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
   CXXInfo->BaseOffsets = BaseOffsets;
   CXXInfo->VBaseOffsets = VBaseOffsets;
+  CXXInfo->VBPtrOffset = vbptroffset;
 
 #ifndef NDEBUG
     if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
-      if (isPrimaryBaseVirtual())
+      if (isPrimaryBaseVirtual()) {
+        // Microsoft ABI doesn't have primary virtual base
+        if (Ctx.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
         assert(getVBaseClassOffset(PrimaryBase).isZero() &&
                "Primary virtual base must be at offset 0!");
-      else
+        }
+      } else {
         assert(getBaseClassOffsetInBits(PrimaryBase) == 0 &&
                "Primary base must be at offset 0!");
+      }
     }
 #endif        
 }

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=140623&r1=140622&r2=140623&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Tue Sep 27 14:12:27 2011
@@ -592,6 +592,9 @@
   /// out is virtual.
   bool PrimaryBaseIsVirtual;
 
+  /// VBPtrOffset - Virtual base table offset. Only for MS layout.
+  CharUnits VBPtrOffset;
+
   typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
 
   /// Bases - base classes and their offsets in the record.
@@ -613,16 +616,17 @@
   llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
 
   RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap
-                      *EmptySubobjects)
+                      *EmptySubobjects, CharUnits Alignment)
     : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), 
-      Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
+      Alignment(Alignment), UnpackedAlignment(Alignment),
       Packed(false), IsUnion(false), 
       IsMac68kAlign(false), IsMsStruct(false),
       UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), 
       DataSize(0), NonVirtualSize(CharUnits::Zero()), 
       NonVirtualAlignment(CharUnits::One()), 
       ZeroLengthBitfield(0), PrimaryBase(0), 
-      PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
+      PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)),
+      FirstNearlyEmptyVBase(0) { }
 
   void Layout(const RecordDecl *D);
   void Layout(const CXXRecordDecl *D);
@@ -633,6 +637,8 @@
   void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
                           bool FieldPacked, const FieldDecl *D);
   void LayoutBitField(const FieldDecl *D);
+  void MSLayoutVirtualBases(const CXXRecordDecl *RD);
+  void MSLayout(const CXXRecordDecl *RD);
 
   /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
   llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
@@ -663,7 +669,7 @@
 
   void SelectPrimaryVBase(const CXXRecordDecl *RD);
 
-  virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+  CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
 
   /// LayoutNonVirtualBases - Determines the primary base class (if any) and
   /// lays it out. Will then proceed to lay out all non-virtual base clasess.
@@ -713,6 +719,8 @@
   void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); }
   void setSize(uint64_t NewSize) { Size = NewSize; }
 
+  CharUnits getAligment() const { return Alignment; }
+
   CharUnits getDataSize() const { 
     assert(DataSize % Context.getCharWidth() == 0);
     return Context.toCharUnitsFromBits(DataSize); 
@@ -722,6 +730,11 @@
   void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
   void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
 
+  bool HasVBPtr(const CXXRecordDecl *RD) const;
+  bool HasNewVirtualFunction(const CXXRecordDecl *RD) const;
+
+  /// Add vbptr or vfptr to layout.
+  void AddVPointer();
 
   RecordLayoutBuilder(const RecordLayoutBuilder&);   // DO NOT IMPLEMENT
   void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
@@ -729,6 +742,8 @@
   static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
 
   virtual ~RecordLayoutBuilder() { }
+
+  CharUnits GetVBPtrOffset() const { return VBPtrOffset; }
 };
 } // end anonymous namespace
 
@@ -1046,6 +1061,45 @@
   }
 }
 
+void RecordLayoutBuilder::AddVPointer() {
+  CharUnits PtrWidth = 
+    Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+  setSize(getSize() + PtrWidth);
+  setDataSize(getSize());
+
+  if (Alignment > PtrWidth) {
+    setSize(getSize() + (Alignment - PtrWidth));
+    setDataSize(getSize());
+  }
+}
+
+bool 
+RecordLayoutBuilder::HasNewVirtualFunction(const CXXRecordDecl *RD) const {
+  for (CXXRecordDecl::method_iterator method = RD->method_begin();
+       method != RD->method_end();
+       ++method) {
+    if (method->isVirtual() &&
+      !method->size_overridden_methods()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool
+RecordLayoutBuilder::HasVBPtr(const CXXRecordDecl *RD) const {
+  if (!RD->getNumBases())
+    return false;
+
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    if (!I->isVirtual()) {
+      return false;
+    }
+  }
+  return true;
+}
+
 void
 RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
                                         const CXXRecordDecl *MostDerivedClass) {
@@ -1184,6 +1238,11 @@
 }
 
 void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
+  if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) {
+    MSLayout(RD);
+    return ;
+  }
+
   InitializeLayout(RD);
 
   // Lay out the vtable and the non-virtual bases.
@@ -1674,6 +1733,104 @@
   UpdateAlignment(FieldAlign, UnpackedFieldAlign);
 }
 
+void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
+
+  if (!RD->getNumVBases())
+    return;
+
+  for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+       E = RD->vbases_end(); I != E; ++I) {
+
+    const CXXRecordDecl* BaseDecl = I->getType()->getAsCXXRecordDecl();
+    const BaseSubobjectInfo* BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
+
+    assert(BaseInfo && "Did not find virtual base info!");
+    
+    LayoutVirtualBase(BaseInfo);
+  }
+}
+
+void RecordLayoutBuilder::MSLayout(const CXXRecordDecl *RD) {
+
+  bool IsVBPtrAddedToLayout = false;
+
+  InitializeLayout(RD);
+
+  if (HasVBPtr(RD)) {
+    // If all bases are virtual and the class declares a new virtual function,
+    // MSVC builds a vfptr.
+    if (HasNewVirtualFunction(RD)) {
+      AddVPointer();
+    }
+
+    VBPtrOffset = getSize();
+    AddVPointer();
+    IsVBPtrAddedToLayout = true;
+
+    ComputeBaseSubobjectInfo(RD);
+  } else {
+    LayoutNonVirtualBases(RD);
+  }
+
+  if (RD->getNumVBases() &&
+      !IsVBPtrAddedToLayout) {
+    // Add vbptr.
+    VBPtrOffset = getSize();
+    AddVPointer();
+  }
+
+  LayoutFields(RD);
+
+  NonVirtualSize = Context.toCharUnitsFromBits(
+                           llvm::RoundUpToAlignment(getSizeInBits(),
+                           Context.getTargetInfo().getCharAlign()));
+  NonVirtualAlignment = Alignment;
+
+  if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
+    CharUnits AlignMember = 
+      NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
+
+    setSize(getSize() + AlignMember);
+    setDataSize(getSize());
+
+    NonVirtualSize = Context.toCharUnitsFromBits(
+                             llvm::RoundUpToAlignment(getSizeInBits(),
+                             Context.getTargetInfo().getCharAlign()));
+  }
+
+  MSLayoutVirtualBases(RD);
+
+  VisitedVirtualBases.clear();
+
+  // Finally, round the size of the total struct up to the alignment of the
+  // struct itself.
+  if (!RD->getNumVBases())
+    FinishLayout(RD);
+
+#ifndef NDEBUG
+  // Check that we have base offsets for all bases.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+    E = RD->bases_end(); I != E; ++I) {
+      if (I->isVirtual())
+        continue;
+
+      const CXXRecordDecl *BaseDecl =
+        cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+      assert(Bases.count(BaseDecl) && "Did not find base offset!");
+  }
+
+  // And all virtual bases.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+    E = RD->vbases_end(); I != E; ++I) {
+      const CXXRecordDecl *BaseDecl =
+        cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+      assert(VBases.count(BaseDecl) && "Did not find base offset!");
+  }
+#endif
+}
+
 void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
   // In C++, records cannot be of size 0.
   if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) {
@@ -1840,29 +1997,6 @@
   return Context.getDiagnostics().Report(Loc, DiagID);
 }
 
-namespace {
-  // This class implements layout specific to the Microsoft ABI.
-  class MSRecordLayoutBuilder : public RecordLayoutBuilder {
-  public:
-    MSRecordLayoutBuilder(const ASTContext& Ctx,
-                          EmptySubobjectMap *EmptySubobjects) :
-      RecordLayoutBuilder(Ctx, EmptySubobjects) {}
-
-    virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
-  };
-}
-
-CharUnits
-MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
-  // We should reserve space for two pointers if the class has both
-  // virtual functions and virtual bases.
-  CharUnits PointerWidth = 
-    Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
-  if (RD->isPolymorphic() && RD->getNumVBases() > 0)
-    return 2 * PointerWidth;
-  return PointerWidth;
-}
-
 /// getASTRecordLayout - Get or compute information about the layout of the
 /// specified record (struct/union/class), which indicates its size and field
 /// position information.
@@ -1882,25 +2016,44 @@
   if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
     EmptySubobjectMap EmptySubobjects(*this, RD);
 
-    // When compiling for Microsoft, use the special MS builder.
     llvm::OwningPtr<RecordLayoutBuilder> Builder;
-    switch (Target->getCXXABI()) {
-    default:
-      Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects));
-      break;
-    case CXXABI_Microsoft:
-      Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects));
-    }
+    CharUnits TargetAlign = CharUnits::One();
+
+    Builder.reset(new RecordLayoutBuilder(*this,
+                                          &EmptySubobjects,
+                                          TargetAlign));
+
     // Recover resources if we crash before exiting this method.
     llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
       RecordBuilderCleanup(Builder.get());
     
     Builder->Layout(RD);
 
+    TargetAlign = Builder->getAligment();
+    
+    if (getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
+        TargetAlign.getQuantity() > 4) {
+      // MSVC rounds the vtable pointer to the struct alignment in what must
+      // be a multi-pass operation. For now, let the builder figure out the
+      // alignment and recalculate the layout once its known.
+      Builder.reset(new RecordLayoutBuilder(*this,
+                                            &EmptySubobjects,
+                                            TargetAlign));
+
+      Builder->Layout(RD);
+
+      // Recover resources if we crash before exiting this method.
+      llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
+        RecordBuilderCleanup(Builder.get());
+    }
+
     // FIXME: This is not always correct. See the part about bitfields at
     // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
     // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
-    bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
+    // This does not affect the calculations of MSVC layouts
+    bool IsPODForThePurposeOfLayout = 
+      (getTargetInfo().getCXXABI() == CXXABI_Microsoft) ||
+      cast<CXXRecordDecl>(D)->isPOD();
 
     // FIXME: This should be done in FinalizeLayout.
     CharUnits DataSize =
@@ -1911,6 +2064,7 @@
     NewEntry =
       new (*this) ASTRecordLayout(*this, Builder->getSize(), 
                                   Builder->Alignment,
+                                  Builder->GetVBPtrOffset(),
                                   DataSize, 
                                   Builder->FieldOffsets.data(),
                                   Builder->FieldOffsets.size(),
@@ -1921,7 +2075,7 @@
                                   Builder->PrimaryBaseIsVirtual,
                                   Builder->Bases, Builder->VBases);
   } else {
-    RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+    RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One());
     Builder.Layout(D);
 
     NewEntry =
@@ -1980,7 +2134,7 @@
       return getObjCLayout(D, 0);
   }
 
-  RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+  RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One());
   Builder.Layout(D);
 
   const ASTRecordLayout *NewEntry =
@@ -2020,12 +2174,22 @@
   IndentLevel++;
 
   const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+  bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
 
   // Vtable pointer.
   if (RD->isDynamicClass() && !PrimaryBase) {
     PrintOffset(OS, Offset, IndentLevel);
     OS << '(' << RD << " vtable pointer)\n";
   }
+  
+  if (HasVbptr && !PrimaryBase) {
+    PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
+    OS << '(' << RD << " vbtable pointer)\n";
+
+    // one vbtable per class
+    HasVbptr = false;
+  }
+
   // Dump (non-virtual) bases
   for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
          E = RD->bases_end(); I != E; ++I) {
@@ -2043,6 +2207,11 @@
                         Base == PrimaryBase ? "(primary base)" : "(base)",
                         /*IncludeVirtualBases=*/false);
   }
+  // vbptr
+  if (HasVbptr) {
+    PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
+    OS << '(' << RD << " vbtable pointer)\n";
+  }
 
   // Dump fields.
   uint64_t FieldNo = 0;

Added: cfe/trunk/test/Sema/ms_class_layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/ms_class_layout.cpp?rev=140623&view=auto
==============================================================================
--- cfe/trunk/test/Sema/ms_class_layout.cpp (added)
+++ cfe/trunk/test/Sema/ms_class_layout.cpp Tue Sep 27 14:12:27 2011
@@ -0,0 +1,176 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -cxx-abi microsoft %s 2>&1 \
+// RUN:            | FileCheck %s
+
+#pragma pack(push, 8)
+
+class B {
+public:
+  virtual void b(){}
+  int b_field;
+protected:
+private:
+};
+
+class A : public B {
+public:
+  int a_field;
+  virtual void a(){}
+  char one;
+protected:
+private:
+};
+
+class D {
+public:
+  virtual void b(){}
+  double a;
+};
+
+class C : public virtual A, 
+          public D, public B {
+public:
+  double c1_field;
+  int c2_field;
+  double c3_field;
+  int c4_field;
+  virtual void foo(){}
+  virtual void bar(){}
+protected:
+private:
+};
+
+struct BaseStruct
+{
+    BaseStruct(){}
+    double v0;
+    float v1;
+    C fg;
+};
+
+struct DerivedStruct : public BaseStruct {
+  int x;
+};
+
+struct G
+{
+    virtual ~G(){}
+    int a;
+    double b;
+};
+
+#pragma pack(pop)
+
+// This needs only for building layouts. 
+// Without this clang doesn`t dump record layouts.
+int main() {
+  // This avoid "Can't yet mangle constructors!" for MS ABI.
+  C* c;
+  c->foo();
+  DerivedStruct* v;
+  G* g;
+  BaseStruct* u;
+  return 0;
+}
+
+// CHECK:       0 | class D
+// CHECK-NEXT:  0 |   (D vtable pointer)
+// CHECK-NEXT:  8 |   double a
+
+// CHECK-NEXT: sizeof=16, dsize=16, align=8
+// CHECK-NEXT: nvsize=16, nvalign=8
+
+// CHECK:       0 | class B
+// CHECK-NEXT:  0 |   (B vtable pointer)
+// CHECK-NEXT:  4 |   int b_field
+
+// CHECK-NEXT: sizeof=8, dsize=8, align=4
+// CHECK-NEXT: nvsize=8, nvalign=4
+
+// CHECK:       0 | class A
+// CHECK-NEXT:  0 |   class B (primary base)
+// CHECK-NEXT:  0 |     (B vtable pointer)
+// CHECK-NEXT:  4 |     int b_field
+// CHECK-NEXT:  8 |   int a_field
+// CHECK-NEXT: 12 |   char one
+
+// CHECK-NEXT: sizeof=16, dsize=16, align=4
+// CHECK-NEXT: nvsize=16, nvalign=4
+
+// CHECK:       0 | class C
+// CHECK-NEXT:  0 |   class D (primary base)
+// CHECK-NEXT:  0 |     (D vtable pointer)
+// CHECK-NEXT:  8 |     double a
+// CHECK-NEXT: 16 |   class B (base)
+// CHECK-NEXT: 16 |     (B vtable pointer)
+// CHECK-NEXT: 20 |     int b_field
+// CHECK-NEXT: 24 |   (C vbtable pointer)
+// CHECK-NEXT: 32 |   double c1_field
+// CHECK-NEXT: 40 |   int c2_field
+// CHECK-NEXT: 48 |   double c3_field
+// CHECK-NEXT: 56 |   int c4_field
+// CHECK-NEXT: 64 |   class A (virtual base)
+// CHECK-NEXT: 64 |     class B (primary base)
+// CHECK-NEXT: 64 |       (B vtable pointer)
+// CHECK-NEXT: 68 |       int b_field
+// CHECK-NEXT: 72 |     int a_field
+// CHECK-NEXT: 76 |     char one
+
+// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: nvsize=80, nvalign=8
+ 
+// CHECK:       0 | struct BaseStruct
+// CHECK-NEXT:  0 |   double v0
+// CHECK-NEXT:  8 |   float v1
+// CHECK-NEXT: 16 |   class C fg
+// CHECK-NEXT: 16 |     class D (primary base)
+// CHECK-NEXT: 16 |       (D vtable pointer)
+// CHECK-NEXT: 24 |       double a
+// CHECK-NEXT: 32 |     class B (base)
+// CHECK-NEXT: 32 |       (B vtable pointer)
+// CHECK-NEXT: 36 |       int b_field
+// CHECK-NEXT: 40 |     (C vbtable pointer)
+// CHECK-NEXT: 48 |     double c1_field
+// CHECK-NEXT: 56 |     int c2_field
+// CHECK-NEXT: 64 |     double c3_field
+// CHECK-NEXT: 72 |     int c4_field
+// CHECK-NEXT: 80 |     class A (virtual base)
+// CHECK-NEXT: 80 |       class B (primary base)
+// CHECK-NEXT: 80 |         (B vtable pointer)
+// CHECK-NEXT: 84 |         int b_field
+// CHECK-NEXT: 88 |       int a_field
+// CHECK-NEXT: 92 |       char one
+
+// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: nvsize=80, nvalign=8
+
+// CHECK: sizeof=96, dsize=96, align=8
+// CHECK-NEXT: nvsize=96, nvalign=8
+
+// CHECK:       0 | struct DerivedStruct
+// CHECK-NEXT:  0 |   struct BaseStruct (base)
+// CHECK-NEXT:  0 |     double v0
+// CHECK-NEXT:  8 |     float v1
+// CHECK-NEXT: 16 |     class C fg
+// CHECK-NEXT: 16 |       class D (primary base)
+// CHECK-NEXT: 16 |         (D vtable pointer)
+// CHECK-NEXT: 24 |         double a
+// CHECK-NEXT: 32 |       class B (base)
+// CHECK-NEXT: 32 |         (B vtable pointer)
+// CHECK-NEXT: 36 |         int b_field
+// CHECK-NEXT: 40 |       (C vbtable pointer)
+// CHECK-NEXT: 48 |       double c1_field
+// CHECK-NEXT: 56 |       int c2_field
+// CHECK-NEXT: 64 |       double c3_field
+// CHECK-NEXT: 72 |       int c4_field
+// CHECK-NEXT: 80 |       class A (virtual base)
+// CHECK-NEXT: 80 |         class B (primary base)
+// CHECK-NEXT: 80 |           (B vtable pointer)
+// CHECK-NEXT: 84 |           int b_field
+// CHECK-NEXT: 88 |         int a_field
+// CHECK-NEXT: 92 |         char one
+// CHECK-NEXT: sizeof=80, dsize=80, align=8
+// CHECK-NEXT: nvsize=80, nvalign=8
+
+// CHECK: 96 |   int x
+// CHECK-NEXT: sizeof=104, dsize=104, align=8
+// CHECK-NEXT: nvsize=104, nvalign=8





More information about the cfe-commits mailing list