const ASTRecordLayout *&PreviousBaseLayout);
void injectVFPtr(const CXXRecordDecl *RD);
void injectVBPtr(const CXXRecordDecl *RD);
- void injectVPtrs(const CXXRecordDecl *RD);
/// \brief Lays out the fields of the record. Also rounds size up to
/// alignment.
void layoutFields(const RecordDecl *RD);
initializeCXXLayout(RD);
layoutNonVirtualBases(RD);
layoutFields(RD);
- injectVPtrs(RD);
+ injectVBPtr(RD);
+ injectVFPtr(RD);
+ if (HasOwnVFPtr || (HasVBPtr && !SharedVBPtrBase))
+ Alignment = std::max(Alignment, PointerInfo.Alignment);
NonVirtualSize = Size = Size.RoundUpToAlignment(Alignment);
RequiredAlignment = std::max(
RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
i->second += Offset;
}
-void MicrosoftRecordLayoutBuilder::injectVPtrs(const CXXRecordDecl *RD) {
- if (!(HasOwnVFPtr || (HasVBPtr && !SharedVBPtrBase)))
- return;
- if (!Is64BitMode || RequiredAlignment <= CharUnits::fromQuantity(8)) {
- // Note that the VBPtr is injected first. It depends on the alignment of
- // the object *before* the alignment is updated by inserting a pointer into
- // the record.
- injectVBPtr(RD);
- injectVFPtr(RD);
- Alignment = std::max(Alignment, PointerInfo.Alignment);
- return;
- }
- // In 64-bit mode, structs with RequiredAlignment greater than 8 get special
- // layout rules. Likely this is to avoid excessive padding intruced around
- // the vfptrs and vbptrs. The special rules involve re-laying out the struct
- // and inserting the vfptr and vbptr as if they were fields/bases.
- FieldOffsets.clear();
- Bases.clear();
- Size = CharUnits::Zero();
- Alignment = std::max(Alignment, PointerInfo.Alignment);
- if (HasOwnVFPtr)
- Size = PointerInfo.Size;
- layoutNonVirtualBases(RD);
- if (HasVBPtr && !SharedVBPtrBase) {
- const CXXRecordDecl *PenultBaseDecl = 0;
- const CXXRecordDecl *LastBaseDecl = 0;
- // Iterate through the bases and find the last two non-virtual bases.
- for (const auto &I : RD->bases()) {
- if (I.isVirtual())
- continue;
- const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
- if (!LastBaseDecl || Bases[BaseDecl] > Bases[LastBaseDecl]) {
- PenultBaseDecl = LastBaseDecl;
- LastBaseDecl = BaseDecl;
- }
- }
- const ASTRecordLayout *PenultBaseLayout = PenultBaseDecl ?
- &Context.getASTRecordLayout(PenultBaseDecl) : 0;
- const ASTRecordLayout *LastBaseLayout = LastBaseDecl ?
- &Context.getASTRecordLayout(LastBaseDecl) : 0;
- // Calculate the vbptr offset. The rule is different than in the general
- // case layout. Particularly, if the last two non-virtual bases are both
- // zero sized, the site of the vbptr is *before* the padding that occurs
- // between the two zero sized bases and the vbptr potentially aliases with
- // the first of these two bases. We have no understanding of why this is
- // different from the general case layout but it may have to do with lazy
- // placement of zero sized bases.
- VBPtrOffset = Size;
- if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
- VBPtrOffset = Bases[LastBaseDecl];
- 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->getNonVirtualSize().isZero()) {
- // Add the padding between zero sized bases after the vbptr.
- if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
- Size += CharUnits::One();
- Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment());
- Bases[LastBaseDecl] = Size;
- }
- }
- layoutFields(RD);
- // The presence of a vbptr suppresses zero sized objects that are not in
- // virtual bases.
- HasZeroSizedSubObject = false;
-}
-
void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
if (!HasVBPtr)
return;
// CHECK-X64-NEXT: 16 | struct B2 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 32 | (A vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | struct V (virtual base)
-// CHECK-X64-NEXT: 48 | char a
-// CHECK-X64-NEXT: | [sizeof=64, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct V (virtual base)
+// CHECK-X64-NEXT: 64 | char a
+// CHECK-X64-NEXT: | [sizeof=80, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct B : B2, B0, B1, virtual V {
int a;
// CHECK-X64-NEXT: 32 | struct B1 (base)
// CHECK-X64-NEXT: 32 | int a
// CHECK-X64-NEXT: 40 | (B vbtable pointer)
-// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 52 | int a
// CHECK-X64-NEXT: 64 | struct V (virtual base)
// CHECK-X64-NEXT: 64 | char a
// CHECK-X64-NEXT: | [sizeof=80, align=16
// CHECK-X64-NEXT: 4 | struct B0 (base)
// CHECK-X64-NEXT: 4 | int a
// CHECK-X64-NEXT: 8 | (C vbtable pointer)
-// CHECK-X64-NEXT: 16 | int a
-// CHECK-X64-NEXT: 24 | long long a1
-// CHECK-X64-NEXT: 32 | struct V (virtual base)
-// CHECK-X64-NEXT: 32 | char a
-// CHECK-X64-NEXT: | [sizeof=48, align=16
-// CHECK-X64-NEXT: | nvsize=32, nvalign=16]
+// CHECK-X64-NEXT: 24 | int a
+// CHECK-X64-NEXT: 32 | long long a1
+// CHECK-X64-NEXT: 48 | struct V (virtual base)
+// CHECK-X64-NEXT: 48 | char a
+// CHECK-X64-NEXT: | [sizeof=64, align=16
+// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
struct D : B2, B0, virtual V {
int a;
// CHECK-X64-NEXT: 16 | struct B0 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 24 | (D vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
+// CHECK-X64-NEXT: 36 | int a
// CHECK-X64-NEXT: 48 | struct V (virtual base)
// CHECK-X64-NEXT: 48 | char a
// CHECK-X64-NEXT: | [sizeof=64, align=16
// CHECK-X64-NEXT: 16 | struct B0 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 24 | (E vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
+// CHECK-X64-NEXT: 36 | int a
// CHECK-X64-NEXT: 48 | struct V (virtual base)
// CHECK-X64-NEXT: 48 | char a
// CHECK-X64-NEXT: | [sizeof=64, align=16
// CHECK-X64-NEXT: 0 | struct B0 (base)
// CHECK-X64-NEXT: 0 | int a
// CHECK-X64-NEXT: 8 | (F vbtable pointer)
-// CHECK-X64-NEXT: 16 | int a
-// CHECK-X64-NEXT: 60 | (vtordisp for vbase V1)
-// CHECK-X64-NEXT: 64 | struct V1 (virtual base)
-// CHECK-X64-NEXT: 64 | (V1 vftable pointer)
-// CHECK-X64-NEXT: 96 | struct A16 (base) (empty)
-// CHECK-X64-NEXT: | [sizeof=96, align=32
-// CHECK-X64-NEXT: | nvsize=32, nvalign=32]
+// CHECK-X64-NEXT: 32 | int a
+// CHECK-X64-NEXT: 92 | (vtordisp for vbase V1)
+// CHECK-X64-NEXT: 96 | struct V1 (virtual base)
+// CHECK-X64-NEXT: 96 | (V1 vftable pointer)
+// CHECK-X64-NEXT: 128 | struct A16 (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=128, align=32
+// CHECK-X64-NEXT: | nvsize=48, nvalign=32]
struct G : virtual V2, virtual V3 {
int a;
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 20 | int a1
// CHECK-X64-NEXT: 24 | (AX vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
+// CHECK-X64-NEXT: 40 | int a
// CHECK-X64-NEXT: 48 | struct B2X (virtual base)
// CHECK-X64-NEXT: 48 | int a
// CHECK-X64-NEXT: 52 | struct B6X (virtual base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 20 | int a1
// CHECK-X64-NEXT: 32 | (BX vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | struct B2X (virtual base)
-// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: 52 | struct B6X (virtual base)
-// CHECK-X64-NEXT: 52 | int a
-// CHECK-X64-NEXT: 76 | (vtordisp for vbase B3X)
-// CHECK-X64-NEXT: 80 | struct B3X (virtual base)
-// CHECK-X64-NEXT: 80 | (B3X vftable pointer)
-// CHECK-X64-NEXT: 88 | int a
-// CHECK-X64-NEXT: | [sizeof=96, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct B2X (virtual base)
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: 68 | struct B6X (virtual base)
+// CHECK-X64-NEXT: 68 | int a
+// CHECK-X64-NEXT: 92 | (vtordisp for vbase B3X)
+// CHECK-X64-NEXT: 96 | struct B3X (virtual base)
+// CHECK-X64-NEXT: 96 | (B3X vftable pointer)
+// CHECK-X64-NEXT: 104 | int a
+// CHECK-X64-NEXT: | [sizeof=112, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct CX : B5X, virtual B2X, virtual B6X, virtual B3X {
int a;
// CHECK-X64-NEXT: 16 | struct A16 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 32 | (TestFB vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | struct C16 (virtual base)
-// CHECK-X64-NEXT: 48 | (C16 vftable pointer)
-// CHECK-X64-NEXT: 64 | int a
-// CHECK-X64-NEXT: | [sizeof=80, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct C16 (virtual base)
+// CHECK-X64-NEXT: 64 | (C16 vftable pointer)
+// CHECK-X64-NEXT: 80 | int a
+// CHECK-X64-NEXT: | [sizeof=96, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct TestFC : TestFB, A4 {
int a;
// CHECK-X64-NEXT: 16 | struct A16 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 32 | (TestFB vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | struct A4 (base)
// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: 52 | int a
-// CHECK-X64-NEXT: 64 | struct C16 (virtual base)
-// CHECK-X64-NEXT: 64 | (C16 vftable pointer)
-// CHECK-X64-NEXT: 80 | int a
-// CHECK-X64-NEXT: | [sizeof=96, align=16
-// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
+// CHECK-X64-NEXT: 64 | struct A4 (base)
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: 68 | int a
+// CHECK-X64-NEXT: 80 | struct C16 (virtual base)
+// CHECK-X64-NEXT: 80 | (C16 vftable pointer)
+// CHECK-X64-NEXT: 96 | int a
+// CHECK-X64-NEXT: | [sizeof=112, align=16
+// CHECK-X64-NEXT: | nvsize=80, nvalign=16]
struct A16f {
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct F0
// CHECK-X64-NEXT: 0 | (F0 vftable pointer)
-// CHECK-X64-NEXT: 8 | struct A4 (base)
-// CHECK-X64-NEXT: 8 | int a
-// CHECK-X64-NEXT: 16 | struct B (base)
-// CHECK-X64-NEXT: 16 | struct A4 (base)
-// CHECK-X64-NEXT: 16 | int a
-// CHECK-X64-NEXT: 20 | struct Y (base)
-// CHECK-X64-NEXT: 20 | char y
-// CHECK-X64-NEXT: 32 | struct X (base)
-// CHECK-X64-NEXT: 32 | (X vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: 64 | struct A16f (virtual base)
-// CHECK-X64-NEXT: 64 | (A16f vftable pointer)
-// CHECK-X64-NEXT: 80 | int a
-// CHECK-X64-NEXT: | [sizeof=96, align=16
-// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
+// CHECK-X64-NEXT: 16 | struct A4 (base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 32 | struct B (base)
+// CHECK-X64-NEXT: 32 | struct A4 (base)
+// CHECK-X64-NEXT: 32 | int a
+// CHECK-X64-NEXT: 36 | struct Y (base)
+// CHECK-X64-NEXT: 36 | char y
+// CHECK-X64-NEXT: 48 | struct X (base)
+// CHECK-X64-NEXT: 48 | (X vbtable pointer)
+// CHECK-X64-NEXT: 56 | int a
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: 80 | struct A16f (virtual base)
+// CHECK-X64-NEXT: 80 | (A16f vftable pointer)
+// CHECK-X64-NEXT: 96 | int a
+// CHECK-X64-NEXT: | [sizeof=112, align=16
+// CHECK-X64-NEXT: | nvsize=80, nvalign=16]
struct F1 : B, A4 {
int a;
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct F3
// CHECK-X64-NEXT: 0 | (F3 vftable pointer)
-// CHECK-X64-NEXT: 8 | struct A4 (base)
-// CHECK-X64-NEXT: 8 | int a
-// CHECK-X64-NEXT: 16 | (F3 vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
-// CHECK-X64-NEXT: 48 | struct A16f (virtual base)
-// CHECK-X64-NEXT: 48 | (A16f vftable pointer)
-// CHECK-X64-NEXT: 64 | int a
-// CHECK-X64-NEXT: | [sizeof=80, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 16 | struct A4 (base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 24 | (F3 vbtable pointer)
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct A16f (virtual base)
+// CHECK-X64-NEXT: 64 | (A16f vftable pointer)
+// CHECK-X64-NEXT: 80 | int a
+// CHECK-X64-NEXT: | [sizeof=96, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct F4 : A4, B {
__declspec(align(16)) int a;
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct F4
// CHECK-X64-NEXT: 0 | (F4 vftable pointer)
-// CHECK-X64-NEXT: 8 | struct A4 (base)
-// CHECK-X64-NEXT: 8 | int a
-// CHECK-X64-NEXT: 16 | struct B (base)
-// CHECK-X64-NEXT: 16 | struct A4 (base)
-// CHECK-X64-NEXT: 16 | int a
-// CHECK-X64-NEXT: 20 | struct Y (base)
-// CHECK-X64-NEXT: 20 | char y
-// CHECK-X64-NEXT: 32 | struct X (base)
-// CHECK-X64-NEXT: 32 | (X vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: 64 | struct A16f (virtual base)
-// CHECK-X64-NEXT: 64 | (A16f vftable pointer)
-// CHECK-X64-NEXT: 80 | int a
-// CHECK-X64-NEXT: | [sizeof=96, align=16
-// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
+// CHECK-X64-NEXT: 16 | struct A4 (base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 32 | struct B (base)
+// CHECK-X64-NEXT: 32 | struct A4 (base)
+// CHECK-X64-NEXT: 32 | int a
+// CHECK-X64-NEXT: 36 | struct Y (base)
+// CHECK-X64-NEXT: 36 | char y
+// CHECK-X64-NEXT: 48 | struct X (base)
+// CHECK-X64-NEXT: 48 | (X vbtable pointer)
+// CHECK-X64-NEXT: 56 | int a
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: 80 | struct A16f (virtual base)
+// CHECK-X64-NEXT: 80 | (A16f vftable pointer)
+// CHECK-X64-NEXT: 96 | int a
+// CHECK-X64-NEXT: | [sizeof=112, align=16
+// CHECK-X64-NEXT: | nvsize=80, nvalign=16]
struct F5 : A16f, virtual A4 {
int a;
// CHECK-X64-NEXT: 0 | (A16f vftable pointer)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 32 | (F5 vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | struct A4 (virtual base)
-// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: | [sizeof=64, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct A4 (virtual base)
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: | [sizeof=80, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct F6 : virtual A16f, A4, virtual B {
int a;
// CHECK-X64-NEXT: 0 | struct D0 (primary base)
// CHECK-X64-NEXT: 0 | (D0 vftable pointer)
// CHECK-X64-NEXT: 8 | (G vbtable pointer)
-// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 24 | int a
// CHECK-X64-NEXT: 32 | struct C0 (virtual base)
// CHECK-X64-NEXT: 32 | int a
// CHECK-X64-NEXT: 40 | struct B0 (virtual base) (empty)
// CHECK-X64-NEXT: 0 | struct G
// CHECK-X64-NEXT: 0 | struct B8 (base)
// CHECK-X64-NEXT: 0 | char [5] c
-// CHECK-X64-NEXT: 16 | struct B1 (base) (empty)
+// CHECK-X64-NEXT: 21 | struct B1 (base) (empty)
// CHECK-X64-NEXT: 8 | (G vbtable pointer)
-// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 24 | int a
// CHECK-X64-NEXT: 32 | int a1
// CHECK-X64-NEXT: 48 | struct B0 (virtual base) (empty)
// CHECK-X64-NEXT: | [sizeof=48, align=16
// CHECK-X64-NEXT: 0 | struct B1X (base) (empty)
// CHECK-X64-NEXT: 16 | struct B2X (base) (empty)
// CHECK-X64-NEXT: 18 | struct B3X (base) (empty)
-// CHECK-X64-NEXT: 33 | struct B4X (base) (empty)
+// CHECK-X64-NEXT: 35 | struct B4X (base) (empty)
// CHECK-X64-NEXT: 24 | (AX vbtable pointer)
// CHECK-X64-NEXT: 36 | int a
// CHECK-X64-NEXT: 48 | struct B0X (virtual base) (empty)
// CHECK-X64-NEXT: 0 | struct B2X (base) (empty)
// CHECK-X64-NEXT: 1 | struct B1X (base) (empty)
// CHECK-X64-NEXT: 2 | struct B3X (base) (empty)
-// CHECK-X64-NEXT: 17 | struct B4X (base) (empty)
+// CHECK-X64-NEXT: 19 | struct B4X (base) (empty)
// CHECK-X64-NEXT: 8 | (BX vbtable pointer)
// CHECK-X64-NEXT: 20 | int a
// CHECK-X64-NEXT: 32 | struct B0X (virtual base) (empty)
// CHECK-X64-NEXT: 0 | struct B1X (base) (empty)
// CHECK-X64-NEXT: 2 | struct B3X (base) (empty)
// CHECK-X64-NEXT: 32 | struct B2X (base) (empty)
-// CHECK-X64-NEXT: 8 | (CX vbtable pointer)
+// CHECK-X64-NEXT: 16 | (CX vbtable pointer)
// CHECK-X64-NEXT: 32 | int a
// CHECK-X64-NEXT: 48 | struct B0X (virtual base) (empty)
// CHECK-X64-NEXT: | [sizeof=48, align=16
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct A
// CHECK-X64-NEXT: 0 | (A vftable pointer)
-// CHECK-X64-NEXT: 8 | struct B0 (base)
-// CHECK-X64-NEXT: 8 | int a
-// CHECK-X64-NEXT: 16 | (A vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
-// CHECK-X64-NEXT: 48 | struct B1 (virtual base)
-// CHECK-X64-NEXT: 48 | char a
-// CHECK-X64-NEXT: | [sizeof=64, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 16 | struct B0 (base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 24 | (A vbtable pointer)
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct B1 (virtual base)
+// CHECK-X64-NEXT: 64 | char a
+// CHECK-X64-NEXT: | [sizeof=80, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct B : A, B2 { int a; B() : a(0xf000000B) {} virtual void f() { printf("B"); } };
// CHECK-X64-NEXT: 0 | struct B
// CHECK-X64-NEXT: 0 | struct A (primary base)
// CHECK-X64-NEXT: 0 | (A vftable pointer)
-// CHECK-X64-NEXT: 8 | struct B0 (base)
-// CHECK-X64-NEXT: 8 | int a
-// CHECK-X64-NEXT: 16 | (A vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
-// CHECK-X64-NEXT: 48 | struct B2 (base)
-// CHECK-X64-NEXT: 48 | (B2 vbtable pointer)
-// CHECK-X64-NEXT: 56 | int a
-// CHECK-X64-NEXT: 64 | int a
-// CHECK-X64-NEXT: 80 | struct B1 (virtual base)
-// CHECK-X64-NEXT: 80 | char a
-// CHECK-X64-NEXT: | [sizeof=96, align=16
-// CHECK-X64-NEXT: | nvsize=80, nvalign=16]
+// CHECK-X64-NEXT: 16 | struct B0 (base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 24 | (A vbtable pointer)
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct B2 (base)
+// CHECK-X64-NEXT: 64 | (B2 vbtable pointer)
+// CHECK-X64-NEXT: 72 | int a
+// CHECK-X64-NEXT: 80 | int a
+// CHECK-X64-NEXT: 96 | struct B1 (virtual base)
+// CHECK-X64-NEXT: 96 | char a
+// CHECK-X64-NEXT: | [sizeof=112, align=16
+// CHECK-X64-NEXT: | nvsize=96, nvalign=16]
struct C : B4 { int a; C() : a(0xf000000C) {} virtual void f() { printf("C"); } };
// CHECK-X64-NEXT: 16 | struct B3 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 32 | (F vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 48 | struct B0 (virtual base)
-// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: | [sizeof=64, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct B0 (virtual base)
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: | [sizeof=80, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct G : B2, B6, virtual B1 { int a; G() : a(0xf0000010) {} };
// CHECK-X64-NEXT: 0 | struct B0 (base)
// CHECK-X64-NEXT: 0 | int a
// CHECK-X64-NEXT: 8 | (I vbtable pointer)
-// CHECK-X64-NEXT: 16 | int a
-// CHECK-X64-NEXT: 20 | int a1
+// CHECK-X64-NEXT: 20 | int a
+// CHECK-X64-NEXT: 24 | int a1
// CHECK-X64-NEXT: 32 | int a2
// CHECK-X64-NEXT: 48 | struct B1 (virtual base)
// CHECK-X64-NEXT: 48 | char a
// CHECK-X64-NEXT: 16 | struct B3 (base)
// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: 32 | (J vbtable pointer)
-// CHECK-X64-NEXT: 40 | int a
-// CHECK-X64-NEXT: 44 | int a1
-// CHECK-X64-NEXT: 48 | struct B1 (virtual base)
-// CHECK-X64-NEXT: 48 | char a
-// CHECK-X64-NEXT: | [sizeof=64, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 52 | int a1
+// CHECK-X64-NEXT: 64 | struct B1 (virtual base)
+// CHECK-X64-NEXT: 64 | char a
+// CHECK-X64-NEXT: | [sizeof=80, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct K { int a; K() : a(0xf0000013) {} virtual void f() { printf("K"); } };
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct A
// CHECK-X64-NEXT: 0 | (A vftable pointer)
-// CHECK-X64-NEXT: 8 | struct B0 (base)
-// CHECK-X64-NEXT: 8 | int a
-// CHECK-X64-NEXT: 16 | (A vbtable pointer)
-// CHECK-X64-NEXT: 32 | int a
-// CHECK-X64-NEXT: 48 | struct B1 (virtual base)
-// CHECK-X64-NEXT: 48 | int a
-// CHECK-X64-NEXT: | [sizeof=64, align=16
-// CHECK-X64-NEXT: | nvsize=48, nvalign=16]
+// CHECK-X64-NEXT: 16 | struct B0 (base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 24 | (A vbtable pointer)
+// CHECK-X64-NEXT: 48 | int a
+// CHECK-X64-NEXT: 64 | struct B1 (virtual base)
+// CHECK-X64-NEXT: 64 | int a
+// CHECK-X64-NEXT: | [sizeof=80, align=16
+// CHECK-X64-NEXT: | nvsize=64, nvalign=16]
struct B : B2, B0, virtual B1 {
__declspec(align(16)) int a;
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct C
// CHECK-X64-NEXT: 0 | (C vftable pointer)
-// CHECK-X64-NEXT: 8 | struct B3 (base)
-// CHECK-X64-NEXT: 8 | (B3 vbtable pointer)
-// CHECK-X64-NEXT: 16 | struct B0 (base)
-// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 16 | struct B3 (base)
+// CHECK-X64-NEXT: 16 | (B3 vbtable pointer)
+// CHECK-X64-NEXT: 24 | struct B0 (base)
+// CHECK-X64-NEXT: 24 | int a
// CHECK-X64-NEXT: 32 | int a
// CHECK-X64-NEXT: 48 | struct B1 (virtual base)
// CHECK-X64-NEXT: 48 | int a