]> granicus.if.org Git - clang/commitdiff
[MS-ABI] Fix to vbptr injection site calculation.
authorWarren Hunt <whunt@google.com>
Thu, 10 Apr 2014 23:23:34 +0000 (23:23 +0000)
committerWarren Hunt <whunt@google.com>
Thu, 10 Apr 2014 23:23:34 +0000 (23:23 +0000)
The vbptr is injected after the last non-virtual base lexographically
rather than the last non-virtual base in layout order.  Test case
included.  Also, some line ending fixes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206000 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/RecordLayoutBuilder.cpp
test/Layout/ms-x86-alias-avoidance-padding.cpp
test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp

index 623d164d221f68e1e8bde4b630718203f5265a34..1ea2be41b3bd3a548c1fcb5846d416cf5dd02ebf 100644 (file)
@@ -2211,8 +2211,6 @@ public:
   bool HasOwnVFPtr : 1;
   /// \brief True if the class has a vbtable pointer.
   bool HasVBPtr : 1;
-  /// \brief Lets us know if we're in 64-bit mode
-  bool Is64BitMode : 1;
   /// \brief True if the last sub-object within the type is zero sized or the
   /// object itself is zero sized.  This *does not* count members that are not
   /// records.  Only used for MS-ABI.
@@ -2310,13 +2308,13 @@ void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
 
 void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
   IsUnion = RD->isUnion();
-  Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64;
   Size = CharUnits::Zero();
   Alignment = CharUnits::One();
   // In 64-bit mode we always perform an alignment step after laying out vbases.
   // In 32-bit mode we do not.  The check to see if we need to perform alignment
   // checks the RequiredAlignment field and performs alignment if it isn't 0.
-  RequiredAlignment = Is64BitMode ? CharUnits::One() : CharUnits::Zero();
+  RequiredAlignment = Context.getTargetInfo().getPointerWidth(0) == 64 ?
+                      CharUnits::One() : CharUnits::Zero();
   // Compute the maximum field alignment.
   MaxFieldAlignment = CharUnits::Zero();
   // Honor the default struct packing maximum alignment flag.
@@ -2402,8 +2400,10 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
     const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
     const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
     // Only lay out bases without extendable VFPtrs on the second pass.
-    if (BaseLayout.hasExtendableVFPtr())
+    if (BaseLayout.hasExtendableVFPtr()) {
+      VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize();
       continue;
+    }
     // If this is the first layout, check to see if it leads with a zero sized
     // object.  If it does, so do we.
     if (CheckLeadingLayout) {
@@ -2412,6 +2412,7 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
     }
     // Lay out the base.
     layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout);
+    VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize();
   }
   // Set our VBPtroffset if we know it at this point.
   if (!HasVBPtr)
@@ -2437,7 +2438,6 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
   Bases.insert(std::make_pair(BaseDecl, BaseOffset));
   Size = BaseOffset + BaseLayout.getNonVirtualSize();
   PreviousBaseLayout = &BaseLayout;
-  VBPtrOffset = Size;
 }
 
 void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
@@ -2542,8 +2542,8 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
     *i += Context.toBits(Offset);
   for (BaseOffsetsMapTy::iterator i = Bases.begin(), e = Bases.end();
        i != e; ++i)
-       if (i->second >= InjectionSite)
-         i->second += Offset;
+    if (i->second >= InjectionSite)
+      i->second += Offset;
 }
 
 void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
index 94ed031734c9595575853bad18566b5581b2eb50..7a78f8732ca3dcc78ff3fbb1883bd5a322e6d55f 100644 (file)
@@ -327,19 +327,19 @@ struct RZ0 : RX0, RY {};
 // CHECK-NEXT:    2 |   struct RY (base) (empty)
 // CHECK-NEXT:      | [sizeof=2, align=1
 // CHECK-NEXT:      |  nvsize=2, nvalign=1]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ0\r
-// CHECK-X64-NEXT:    0 |   struct RX0 (base)\r
-// CHECK-X64-NEXT:    0 |     struct RB (base)\r
-// CHECK-X64-NEXT:    0 |       char c\r
-// CHECK-X64-NEXT:    1 |     struct RA (base) (empty)\r
-// CHECK-X64-NEXT:    2 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=2, align=1\r
-// CHECK-X64-NEXT:      |  nvsize=2, nvalign=1]\r
+// 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: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ0
+// CHECK-X64-NEXT:    0 |   struct RX0 (base)
+// CHECK-X64-NEXT:    0 |     struct RB (base)
+// CHECK-X64-NEXT:    0 |       char c
+// CHECK-X64-NEXT:    1 |     struct RA (base) (empty)
+// CHECK-X64-NEXT:    2 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=2, align=1
+// CHECK-X64-NEXT:      |  nvsize=2, nvalign=1]
 
 struct RZ1 : RX1, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -352,16 +352,16 @@ struct RZ1 : RX1, RY {};
 // CHECK-NEXT:    1 |   struct RY (base) (empty)
 // CHECK-NEXT:      | [sizeof=1, align=1
 // CHECK-NEXT:      |  nvsize=1, nvalign=1]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ1\r
-// CHECK-X64-NEXT:    0 |   struct RX1 (base)\r
-// CHECK-X64-NEXT:    0 |     struct RA (base) (empty)\r
-// CHECK-X64-NEXT:    0 |     struct RB (base)\r
-// CHECK-X64-NEXT:    0 |       char c\r
-// CHECK-X64-NEXT:    1 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |  nvsize=1, nvalign=1]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ1
+// CHECK-X64-NEXT:    0 |   struct RX1 (base)
+// CHECK-X64-NEXT:    0 |     struct RA (base) (empty)
+// CHECK-X64-NEXT:    0 |     struct RB (base)
+// CHECK-X64-NEXT:    0 |       char c
+// CHECK-X64-NEXT:    1 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=1, align=1
+// CHECK-X64-NEXT:      |  nvsize=1, nvalign=1]
 
 struct RZ2 : RX2, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -373,15 +373,15 @@ struct RZ2 : RX2, RY {};
 // CHECK-NEXT:    2 |   struct RY (base) (empty)
 // CHECK-NEXT:      | [sizeof=2, align=1
 // CHECK-NEXT:      |  nvsize=2, nvalign=1]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ2\r
-// CHECK-X64-NEXT:    0 |   struct RX2 (base)\r
-// CHECK-X64-NEXT:    0 |     struct RA (base) (empty)\r
-// CHECK-X64-NEXT:    0 |     char a\r
-// CHECK-X64-NEXT:    2 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=2, align=1\r
-// CHECK-X64-NEXT:      |  nvsize=2, nvalign=1]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ2
+// CHECK-X64-NEXT:    0 |   struct RX2 (base)
+// CHECK-X64-NEXT:    0 |     struct RA (base) (empty)
+// CHECK-X64-NEXT:    0 |     char a
+// CHECK-X64-NEXT:    2 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=2, align=1
+// CHECK-X64-NEXT:      |  nvsize=2, nvalign=1]
 
 struct RZ3 : RX3, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -396,18 +396,18 @@ struct RZ3 : RX3, RY {};
 // CHECK-NEXT:    1 |   struct RY (base) (empty)
 // CHECK-NEXT:      | [sizeof=1, align=1
 // CHECK-NEXT:      |  nvsize=1, nvalign=1]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ3\r
-// CHECK-X64-NEXT:    0 |   struct RX3 (base)\r
-// CHECK-X64-NEXT:    0 |     struct RA (base) (empty)\r
-// CHECK-X64-NEXT:    0 |     struct RB a\r
-// CHECK-X64-NEXT:    0 |       char c\r
-// CHECK-X64-NEXT:      |     [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |      nvsize=1, nvalign=1]\r
-// CHECK-X64-NEXT:    1 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |  nvsize=1, nvalign=1]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ3
+// CHECK-X64-NEXT:    0 |   struct RX3 (base)
+// CHECK-X64-NEXT:    0 |     struct RA (base) (empty)
+// CHECK-X64-NEXT:    0 |     struct RB a
+// CHECK-X64-NEXT:    0 |       char c
+// CHECK-X64-NEXT:      |     [sizeof=1, align=1
+// CHECK-X64-NEXT:      |      nvsize=1, nvalign=1]
+// CHECK-X64-NEXT:    1 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=1, align=1
+// CHECK-X64-NEXT:      |  nvsize=1, nvalign=1]
 
 struct RZ4 : RX4, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -421,17 +421,17 @@ struct RZ4 : RX4, RY {};
 // CHECK-NEXT:    3 |   struct RY (base) (empty)
 // CHECK-NEXT:      | [sizeof=3, align=1
 // CHECK-NEXT:      |  nvsize=3, nvalign=1]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ4\r
-// CHECK-X64-NEXT:    0 |   struct RX4 (base)\r
-// CHECK-X64-NEXT:    0 |     struct RA a (empty)\r
-// CHECK-X64-NEXT:      |     [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |      nvsize=0, nvalign=1]\r
-// CHECK-X64-NEXT:    1 |     char b\r
-// CHECK-X64-NEXT:    3 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=3, align=1\r
-// CHECK-X64-NEXT:      |  nvsize=3, nvalign=1]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ4
+// CHECK-X64-NEXT:    0 |   struct RX4 (base)
+// CHECK-X64-NEXT:    0 |     struct RA a (empty)
+// CHECK-X64-NEXT:      |     [sizeof=1, align=1
+// CHECK-X64-NEXT:      |      nvsize=0, nvalign=1]
+// CHECK-X64-NEXT:    1 |     char b
+// CHECK-X64-NEXT:    3 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=3, align=1
+// CHECK-X64-NEXT:      |  nvsize=3, nvalign=1]
 
 struct RZ5 : RX5, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -448,20 +448,20 @@ struct RZ5 : RX5, RY {};
 // CHECK-NEXT:    2 |   struct RY (base) (empty)
 // CHECK-NEXT:      | [sizeof=2, align=1
 // CHECK-NEXT:      |  nvsize=2, nvalign=1]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ5\r
-// CHECK-X64-NEXT:    0 |   struct RX5 (base)\r
-// CHECK-X64-NEXT:    0 |     struct RA a (empty)\r
-// CHECK-X64-NEXT:      |     [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |      nvsize=0, nvalign=1]\r
-// CHECK-X64-NEXT:    1 |     struct RB b\r
-// CHECK-X64-NEXT:    1 |       char c\r
-// CHECK-X64-NEXT:      |     [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |      nvsize=1, nvalign=1]\r
-// CHECK-X64-NEXT:    2 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=2, align=1\r
-// CHECK-X64-NEXT:      |  nvsize=2, nvalign=1]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ5
+// CHECK-X64-NEXT:    0 |   struct RX5 (base)
+// CHECK-X64-NEXT:    0 |     struct RA a (empty)
+// CHECK-X64-NEXT:      |     [sizeof=1, align=1
+// CHECK-X64-NEXT:      |      nvsize=0, nvalign=1]
+// CHECK-X64-NEXT:    1 |     struct RB b
+// CHECK-X64-NEXT:    1 |       char c
+// CHECK-X64-NEXT:      |     [sizeof=1, align=1
+// CHECK-X64-NEXT:      |      nvsize=1, nvalign=1]
+// CHECK-X64-NEXT:    2 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=2, align=1
+// CHECK-X64-NEXT:      |  nvsize=2, nvalign=1]
 
 struct RZ6 : RX6, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -478,20 +478,20 @@ struct RZ6 : RX6, RY {};
 // CHECK-NEXT:   12 |   struct RV (virtual base) (empty)
 // CHECK-NEXT:      | [sizeof=12, align=4
 // CHECK-NEXT:      |  nvsize=12, nvalign=4]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ6\r
-// CHECK-X64-NEXT:    0 |   struct RX6 (base)\r
-// CHECK-X64-NEXT:    0 |     (RX6 vbtable pointer)\r
-// CHECK-X64-NEXT:    8 |     struct RB a\r
-// CHECK-X64-NEXT:    8 |       char c\r
-// CHECK-X64-NEXT:      |     [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |      nvsize=1, nvalign=1]\r
-// CHECK-X64-NEXT:   17 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:   24 |   struct RV (virtual base) (empty)\r
-// CHECK-X64-NEXT:      | [sizeof=24, align=8\r
-// CHECK-X64-NEXT:      |  nvsize=24, nvalign=8]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ6
+// CHECK-X64-NEXT:    0 |   struct RX6 (base)
+// CHECK-X64-NEXT:    0 |     (RX6 vbtable pointer)
+// CHECK-X64-NEXT:    8 |     struct RB a
+// CHECK-X64-NEXT:    8 |       char c
+// CHECK-X64-NEXT:      |     [sizeof=1, align=1
+// CHECK-X64-NEXT:      |      nvsize=1, nvalign=1]
+// CHECK-X64-NEXT:   17 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:   24 |   struct RV (virtual base) (empty)
+// CHECK-X64-NEXT:      | [sizeof=24, align=8
+// CHECK-X64-NEXT:      |  nvsize=24, nvalign=8]
 
 struct RZ7 : RX7, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -508,20 +508,20 @@ struct RZ7 : RX7, RY {};
 // CHECK-NEXT:    8 |     char c
 // CHECK-NEXT:      | [sizeof=9, align=4
 // CHECK-NEXT:      |  nvsize=8, nvalign=4]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ7\r
-// CHECK-X64-NEXT:    0 |   struct RX7 (base)\r
-// CHECK-X64-NEXT:    0 |     (RX7 vbtable pointer)\r
-// CHECK-X64-NEXT:    8 |     struct RA a (empty)\r
-// CHECK-X64-NEXT:      |     [sizeof=1, align=1\r
-// CHECK-X64-NEXT:      |      nvsize=0, nvalign=1]\r
-// CHECK-X64-NEXT:   16 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:   16 |   struct RW (virtual base)\r
-// CHECK-X64-NEXT:   16 |     char c\r
-// CHECK-X64-NEXT:      | [sizeof=24, align=8\r
-// CHECK-X64-NEXT:      |  nvsize=16, nvalign=8]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ7
+// CHECK-X64-NEXT:    0 |   struct RX7 (base)
+// CHECK-X64-NEXT:    0 |     (RX7 vbtable pointer)
+// CHECK-X64-NEXT:    8 |     struct RA a (empty)
+// CHECK-X64-NEXT:      |     [sizeof=1, align=1
+// CHECK-X64-NEXT:      |      nvsize=0, nvalign=1]
+// CHECK-X64-NEXT:   16 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:   16 |   struct RW (virtual base)
+// CHECK-X64-NEXT:   16 |     char c
+// CHECK-X64-NEXT:      | [sizeof=24, align=8
+// CHECK-X64-NEXT:      |  nvsize=16, nvalign=8]
 
 struct RZ8 : RX8, RY {};
 // CHECK: *** Dumping AST Record Layout
@@ -535,17 +535,17 @@ struct RZ8 : RX8, RY {};
 // CHECK-NEXT:    4 |     char c
 // CHECK-NEXT:      | [sizeof=5, align=4
 // CHECK-NEXT:      |  nvsize=4, nvalign=4]
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64: *** Dumping AST Record Layout\r
-// CHECK-X64-NEXT:    0 | struct RZ8\r
-// CHECK-X64-NEXT:    0 |   struct RX8 (base)\r
-// CHECK-X64-NEXT:    8 |     struct RA (base) (empty)\r
-// CHECK-X64-NEXT:    0 |     (RX8 vbtable pointer)\r
-// CHECK-X64-NEXT:    8 |   struct RY (base) (empty)\r
-// CHECK-X64-NEXT:    8 |   struct RW (virtual base)\r
-// CHECK-X64-NEXT:    8 |     char c\r
-// CHECK-X64-NEXT:      | [sizeof=16, align=8\r
-// CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]\r
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT:    0 | struct RZ8
+// CHECK-X64-NEXT:    0 |   struct RX8 (base)
+// CHECK-X64-NEXT:    8 |     struct RA (base) (empty)
+// CHECK-X64-NEXT:    0 |     (RX8 vbtable pointer)
+// CHECK-X64-NEXT:    8 |   struct RY (base) (empty)
+// CHECK-X64-NEXT:    8 |   struct RW (virtual base)
+// CHECK-X64-NEXT:    8 |     char c
+// CHECK-X64-NEXT:      | [sizeof=16, align=8
+// CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]
 
 
 
index 5bea872ae115ac228c2d4905319c904a5e174642..34ae0cf9dde84aee811928d170aa9ac8dee5ca45 100644 (file)
@@ -766,6 +766,45 @@ struct C2 : public C1, public C0 {};
 // CHECK-X64-NEXT:      | [sizeof=8, align=4
 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=4]
 
+struct JA { char a; };
+struct JB {
+  char a;
+  virtual void f() {}
+};
+struct JC { char a; };
+struct JD : JA, JB, virtual JC {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT:    0 | struct JD
+// CHECK-NEXT:    0 |   struct JB (primary base)
+// CHECK-NEXT:    0 |     (JB vftable pointer)
+// CHECK-NEXT:    4 |     char a
+// CHECK-NEXT:   12 |   struct JA (base)
+// CHECK-NEXT:   12 |     char a
+// CHECK-NEXT:    8 |   (JD vbtable pointer)
+// CHECK-NEXT:   16 |   struct JC (virtual base)
+// CHECK-NEXT:   16 |     char a
+// CHECK-NEXT:      | [sizeof=17, align=4
+// CHECK-NEXT:      |  nvsize=16, 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 JD
+// CHECK-X64-NEXT:    0 |   struct JB (primary base)
+// CHECK-X64-NEXT:    0 |     (JB vftable pointer)
+// CHECK-X64-NEXT:    8 |     char a
+// CHECK-X64-NEXT:   24 |   struct JA (base)
+// CHECK-X64-NEXT:   24 |     char a
+// CHECK-X64-NEXT:   16 |   (JD vbtable pointer)
+// CHECK-X64-NEXT:   32 |   struct JC (virtual base)
+// CHECK-X64-NEXT:   32 |     char a
+// CHECK-X64-NEXT:      | [sizeof=40, align=8
+// CHECK-X64-NEXT:      |  nvsize=32, nvalign=8]
+
 int a[
 sizeof(AA)+
 sizeof(AB)+
@@ -793,4 +832,6 @@ sizeof(AX)+
 sizeof(BX)+
 sizeof(CX)+
 sizeof(DX)+
-sizeof(C2)];
+sizeof(C2)+
+sizeof(JD)+
+0];