summaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorWarren Hunt <whunt@google.com>2014-04-10 23:23:34 +0000
committerWarren Hunt <whunt@google.com>2014-04-10 23:23:34 +0000
commitbb9c3c33e94f3e5a17990b7a8ab9d076d0c7e594 (patch)
treedff6dd016a24937cd5330b91855a8b4da41c743b /clang
parent42d71b990677afc974c404fb0482cb5af176c3d0 (diff)
downloadllvm-bb9c3c33e94f3e5a17990b7a8ab9d076d0c7e594.tar.gz
[MS-ABI] Fix to vbptr injection site calculation.
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. llvm-svn: 206000
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp16
-rw-r--r--clang/test/Layout/ms-x86-alias-avoidance-padding.cpp216
-rw-r--r--clang/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp43
3 files changed, 158 insertions, 117 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 623d164d221f..1ea2be41b3bd 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -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) {
diff --git a/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp b/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
index 94ed031734c9..7a78f8732ca3 100644
--- a/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
+++ b/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp
@@ -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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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
-// 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]
+// 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]
diff --git a/clang/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp b/clang/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
index 5bea872ae115..34ae0cf9dde8 100644
--- a/clang/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
+++ b/clang/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
@@ -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];