r201832 - [MS-ABI] Update to zero-sized padding algorithm

Warren Hunt whunt at google.com
Thu Feb 20 17:40:35 PST 2014


Author: whunt
Date: Thu Feb 20 19:40:35 2014
New Revision: 201832

URL: http://llvm.org/viewvc/llvm-project?rev=201832&view=rev
Log:
[MS-ABI] Update to zero-sized padding algorithm
Slight change to the way zero-sized sub-objects are tracked in the 
presence of virtual bases.
In addition we correctly distinguish between dsize and nvsize.
addresses http://llvm.org/bugs/show_bug.cgi?id=18826
Unit tests are included.


Modified:
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
    cfe/trunk/test/Layout/ms-x86-empty-virtual-base.cpp

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=201832&r1=201831&r2=201832&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Thu Feb 20 19:40:35 2014
@@ -2165,7 +2165,8 @@ public:
   void finalizeLayout(const RecordDecl *RD);
   /// \brief Gets the size and alignment of a base taking pragma pack and
   /// __declspec(align) into account.
-  ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout);
+  ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout,
+                                     bool AsBase = true);
   /// \brief Gets the size and alignment of a field taking pragma  pack and
   /// __declspec(align) into account.  It also updates RequiredAlignment as a
   /// side effect because it is most convenient to do so here.
@@ -2184,7 +2185,9 @@ public:
   const ASTContext &Context;
   /// \brief The size of the record being laid out.
   CharUnits Size;
-  /// \brief The data alignment of the record layout.
+  /// \brief The non-virtual size of the record layout.
+  CharUnits NonVirtualSize;
+  /// \brief The data size of the record layout.
   CharUnits DataSize;
   /// \brief The current alignment of the record layout.
   CharUnits Alignment;
@@ -2236,7 +2239,7 @@ public:
 
 MicrosoftRecordLayoutBuilder::ElementInfo
 MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
-    const ASTRecordLayout &Layout) {
+    const ASTRecordLayout &Layout, bool AsBase) {
   ElementInfo Info;
   Info.Alignment = Layout.getAlignment();
   // Respect pragma pack.
@@ -2250,7 +2253,7 @@ MicrosoftRecordLayoutBuilder::getAdjuste
   // doesn't actually apply to the struct alignment at this point.
   Alignment = std::max(Alignment, Info.Alignment);
   Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment());
-  Info.Size = Layout.getDataSize();
+  Info.Size = AsBase ? Layout.getNonVirtualSize() : Layout.getSize();
   return Info;
 }
 
@@ -2266,10 +2269,11 @@ MicrosoftRecordLayoutBuilder::getAdjuste
       FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RT->getDecl());
     // Get the element info for a layout, respecting pack.
-    Info = getAdjustedElementInfo(Layout);
-    // Nomally getAdjustedElementInfo returns the non-virtual size, which is
-    // correct for bases but not for fields.
-    Info.Size = Context.getTypeInfoInChars(FD->getType()).first;
+    Info = getAdjustedElementInfo(Layout, false);
+    // If the field is an array type, scale it's size properly.
+    if (const ConstantArrayType *CAT =
+        dyn_cast<ConstantArrayType>(FD->getType()))
+      Info.Size = Info.Size * (int64_t)CAT->getSize().getZExtValue();
     // Capture required alignment as a side-effect.
     RequiredAlignment = std::max(RequiredAlignment,
                                  Layout.getRequiredAlignment());
@@ -2317,7 +2321,7 @@ void MicrosoftRecordLayoutBuilder::cxxLa
   layoutNonVirtualBases(RD);
   layoutFields(RD);
   injectVPtrs(RD);
-  DataSize = Size = Size.RoundUpToAlignment(Alignment);
+  NonVirtualSize = Size = Size.RoundUpToAlignment(Alignment);
   RequiredAlignment = std::max(
       RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
   layoutVirtualBases(RD);
@@ -2458,7 +2462,7 @@ void MicrosoftRecordLayoutBuilder::layou
   ElementInfo Info = getAdjustedElementInfo(BaseLayout);
   CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
   Bases.insert(std::make_pair(BaseDecl, BaseOffset));
-  Size = BaseOffset + BaseLayout.getDataSize();
+  Size = BaseOffset + BaseLayout.getNonVirtualSize();
   PreviousBaseLayout = &BaseLayout;
   VBPtrOffset = Size;
 }
@@ -2569,9 +2573,6 @@ void MicrosoftRecordLayoutBuilder::injec
        i != e; ++i)
        if (i->second >= InjectionSite)
          i->second += Offset;
-  // The presence of a vbptr suppresses zero sized objects that are not in
-  // virtual bases.
-  HasZeroSizedSubObject = false;
 }
 
 void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
@@ -2645,17 +2646,17 @@ void MicrosoftRecordLayoutBuilder::injec
     // different from the general case layout but it may have to do with lazy
     // placement of zero sized bases.
     VBPtrOffset = Size;
-    if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) {
+    if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
       VBPtrOffset = Bases[LastBaseDecl];
-      if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero())
+      if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
         VBPtrOffset = Bases[PenultBaseDecl];
     }
     // Once we've located a spot for the vbptr, place it.
     VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
     Size = VBPtrOffset + PointerInfo.Size;
-    if (LastBaseLayout && LastBaseLayout->getDataSize().isZero()) {
+    if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
       // Add the padding between zero sized bases after the vbptr.
-      if (PenultBaseLayout && PenultBaseLayout->getDataSize().isZero())
+      if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
         Size += CharUnits::One();
       Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment());
       Bases[LastBaseDecl] = Size;
@@ -2715,11 +2716,12 @@ void MicrosoftRecordLayoutBuilder::layou
     if (HasVtordisp)
       Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
     // Insert the virtual base.
+    HasZeroSizedSubObject = false;
     ElementInfo Info = getAdjustedElementInfo(BaseLayout);
     CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
     VBases.insert(std::make_pair(BaseDecl,
         ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
-    Size = BaseOffset + BaseLayout.getDataSize();
+    Size = BaseOffset + BaseLayout.getNonVirtualSize();
     PreviousBaseLayout = &BaseLayout;
   }
 }
@@ -2727,6 +2729,7 @@ void MicrosoftRecordLayoutBuilder::layou
 void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
   // Respect required alignment.  Note that in 32-bit mode Required alignment
   // may be 0 nad cause size not to be updated.
+  DataSize = Size;
   if (!RequiredAlignment.isZero()) {
     Alignment = std::max(Alignment, RequiredAlignment);
     Size = Size.RoundUpToAlignment(Alignment);
@@ -2852,8 +2855,8 @@ ASTContext::BuildMicrosoftASTRecordLayou
         *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
         Builder.HasOwnVFPtr,
         Builder.HasOwnVFPtr || Builder.PrimaryBase,
-        Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
-        Builder.FieldOffsets.size(), Builder.DataSize,
+        Builder.VBPtrOffset, Builder.NonVirtualSize, Builder.FieldOffsets.data(),
+        Builder.FieldOffsets.size(), Builder.NonVirtualSize,
         Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase,
         false, Builder.SharedVBPtrBase,
         Builder.HasZeroSizedSubObject, Builder.LeadsWithZeroSizedBase,

Modified: cfe/trunk/test/Layout/ms-x86-empty-virtual-base.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Layout/ms-x86-empty-virtual-base.cpp?rev=201832&r1=201831&r2=201832&view=diff
==============================================================================
--- cfe/trunk/test/Layout/ms-x86-empty-virtual-base.cpp (original)
+++ cfe/trunk/test/Layout/ms-x86-empty-virtual-base.cpp Thu Feb 20 19:40:35 2014
@@ -730,6 +730,40 @@ struct T3 : virtual T1, virtual T0 { lon
 // CHECK-X64-NEXT:      | [sizeof=24, align=8
 // CHECK-X64-NEXT:      |  nvsize=16, nvalign=8]
 
+struct Q0A {};
+struct Q0B { char Q0BField; };
+struct Q0C : virtual Q0A, virtual Q0B { char Q0CField; };
+struct Q0D : Q0C, Q0A {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT:    0 | struct Q0D
+// CHECK-NEXT:    0 |   struct Q0C (base)
+// CHECK-NEXT:    0 |     (Q0C vbtable pointer)
+// CHECK-NEXT:    4 |     char Q0CField
+// CHECK-NEXT:    8 |   struct Q0A (base) (empty)
+// CHECK-NEXT:    8 |   struct Q0A (virtual base) (empty)
+// CHECK-NEXT:    8 |   struct Q0B (virtual base)
+// CHECK-NEXT:    8 |     char Q0BField
+// CHECK-NEXT:      | [sizeof=9, align=4
+// CHECK-NEXT:      |  nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct Q0D
+// CHECK-X64-NEXT:    0 |   struct Q0C (base)
+// CHECK-X64-NEXT:    0 |     (Q0C vbtable pointer)
+// CHECK-X64-NEXT:    8 |     char Q0CField
+// CHECK-X64-NEXT:   16 |   struct Q0A (base) (empty)
+// CHECK-X64-NEXT:   16 |   struct Q0A (virtual base) (empty)
+// CHECK-X64-NEXT:   16 |   struct Q0B (virtual base)
+// CHECK-X64-NEXT:   16 |     char Q0BField
+// CHECK-X64-NEXT:      | [sizeof=24, align=8
+// CHECK-X64-NEXT:      |  nvsize=16, nvalign=8]
+
 int a[
 sizeof(A)+
 sizeof(B)+
@@ -753,4 +787,5 @@ sizeof(S)+
 sizeof(T)+
 sizeof(U)+
 sizeof(V)+
-sizeof(T3)];
+sizeof(T3)+
+sizeof(Q0D)];





More information about the cfe-commits mailing list