/// (either a base or a member). Will be zero if the class doesn't contain
/// any empty subobjects.
CharUnits SizeOfLargestEmptySubobject;
-
- /// VBPtrOffset - Virtual base table offset.
+
+ /// VFPtrOffset - Virtual function table offset (Microsoft-only).
+ CharUnits VFPtrOffset;
+
+ /// VBPtrOffset - Virtual base table offset (Microsoft-only).
CharUnits VBPtrOffset;
/// PrimaryBase - The primary base info for this record.
// Constructor for C++ records.
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
ASTRecordLayout(const ASTContext &Ctx,
- CharUnits size, CharUnits alignment, CharUnits vbptroffset,
+ CharUnits size, CharUnits alignment,
+ CharUnits vfptroffset, CharUnits vbptroffset,
CharUnits datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
return CXXInfo->SizeOfLargestEmptySubobject;
}
+ /// getVFPtrOffset - Get the offset for virtual function table pointer.
+ /// This is only meaningful with the Microsoft ABI.
+ CharUnits getVFPtrOffset() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return CXXInfo->VFPtrOffset;
+ }
+
+ /// getVBPtrOffset - Get the offset for virtual base table pointer.
+ /// This is only meaningful with the Microsoft ABI.
CharUnits getVBPtrOffset() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->VBPtrOffset;
}
};
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
- CharUnits vbptroffset, CharUnits datasize,
+ CharUnits vfptroffset, CharUnits vbptroffset,
+ CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
CharUnits nonvirtualsize,
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
CXXInfo->BaseOffsets = BaseOffsets;
CXXInfo->VBaseOffsets = VBaseOffsets;
+ CXXInfo->VFPtrOffset = vfptroffset;
CXXInfo->VBPtrOffset = vbptroffset;
#ifndef NDEBUG
/// out is virtual.
bool PrimaryBaseIsVirtual;
+ /// VFPtrOffset - Virtual function table offset. Only for MS layout.
+ CharUnits VFPtrOffset;
+
/// VBPtrOffset - Virtual base table offset. Only for MS layout.
CharUnits VBPtrOffset;
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
ZeroLengthBitfield(0), PrimaryBase(0),
- PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)),
+ PrimaryBaseIsVirtual(false),
+ VFPtrOffset(CharUnits::fromQuantity(-1)),
+ VBPtrOffset(CharUnits::fromQuantity(-1)),
FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
void SelectPrimaryVBase(const CXXRecordDecl *RD);
- void EnsureVTablePointerAlignment();
+ void EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign);
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
virtual ~RecordLayoutBuilder() { }
-
- CharUnits GetVBPtrOffset() const { return VBPtrOffset; }
};
} // end anonymous namespace
}
void
-RecordLayoutBuilder::EnsureVTablePointerAlignment() {
- CharUnits UnpackedBaseAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+RecordLayoutBuilder::EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign) {
CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
// The maximum field alignment overrides base align.
}
// Round up the current record size to pointer alignment.
- setDataSize(getDataSize().RoundUpToAlignment(BaseAlign));
+ setSize(getSize().RoundUpToAlignment(BaseAlign));
+ setDataSize(getSize());
// Update the alignment.
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
// Under the Itanium ABI, a dynamic class without a primary base has a
// vtable pointer. It is placed at offset 0.
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
- EnsureVTablePointerAlignment();
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PtrAlign =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ EnsureVTablePointerAlignment(PtrAlign);
setSize(getSize() + PtrWidth);
setDataSize(getSize());
}
// after any base classes.
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PtrAlign =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ PtrAlign = std::max(PtrAlign, Alignment);
if (HasNewVirtualFunction(RD) &&
(!PrimaryBase || !BaseHasVFPtr(PrimaryBase))) {
- EnsureVTablePointerAlignment();
+ EnsureVTablePointerAlignment(PtrAlign);
+ VFPtrOffset = getSize();
setSize(getSize() + PtrWidth);
setDataSize(getSize());
}
if (RD->getNumVBases() &&
(!PrimaryBase || !PrimaryBase->getNumVBases())) {
- EnsureVTablePointerAlignment();
+ EnsureVTablePointerAlignment(PtrAlign);
VBPtrOffset = getSize();
setSize(getSize() + PtrWidth);
setDataSize(getSize());
Builder->Layout(RD);
- TargetAlign = Builder->getAligment();
+ TargetAlign = Builder->NonVirtualAlignment;
if (getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
TargetAlign.getQuantity() > 4) {
// FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
// This does not affect the calculations of MSVC layouts
bool IsPODForThePurposeOfLayout =
- (getTargetInfo().getCXXABI() == CXXABI_Microsoft) ||
+ (getTargetInfo().getCXXABI() != CXXABI_Microsoft) &&
cast<CXXRecordDecl>(D)->isPOD();
// FIXME: This should be done in FinalizeLayout.
NewEntry =
new (*this) ASTRecordLayout(*this, Builder->getSize(),
Builder->Alignment,
- Builder->GetVBPtrOffset(),
+ Builder->VFPtrOffset,
+ Builder->VBPtrOffset,
DataSize,
Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
IndentLevel++;
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ bool HasVfptr = Layout.getVFPtrOffset() != CharUnits::fromQuantity(-1);
bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
// Vtable pointer.
- if (RD->isDynamicClass() && !PrimaryBase) {
+ if (RD->isDynamicClass() && !PrimaryBase &&
+ C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
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) {
Base == PrimaryBase ? "(primary base)" : "(base)",
/*IncludeVirtualBases=*/false);
}
- // vbptr
+
+ // vfptr and vbptr (for Microsoft C++ ABI)
+ if (HasVfptr) {
+ PrintOffset(OS, Offset + Layout.getVFPtrOffset(), IndentLevel);
+ OS << '(' << *RD << " vftable pointer)\n";
+ }
if (HasVbptr) {
PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
OS << '(' << *RD << " vbtable pointer)\n";
{
};
+struct I : public virtual D
+{
+ virtual ~I(){}
+ double q;
+};
+
#pragma pack(pop)
// This needs only for building layouts.
DerivedStruct* v;
H* g;
BaseStruct* u;
+ I* i;
return 0;
}
// CHECK: 0 | class D
-// CHECK-NEXT: 0 | (D vtable pointer)
+// CHECK-NEXT: 0 | (D vftable 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: 0 | (B vftable pointer)
// CHECK-NEXT: 4 | int b_field
// CHECK-NEXT: sizeof=8, dsize=8, align=4
// CHECK: 0 | class A
// CHECK-NEXT: 0 | class B (primary base)
-// CHECK-NEXT: 0 | (B vtable pointer)
+// CHECK-NEXT: 0 | (B vftable pointer)
// CHECK-NEXT: 4 | int b_field
// CHECK-NEXT: 8 | int a_field
// CHECK-NEXT: 12 | char one
// CHECK: 0 | class C
// CHECK-NEXT: 0 | class D (primary base)
-// CHECK-NEXT: 0 | (D vtable pointer)
+// CHECK-NEXT: 0 | (D vftable pointer)
// CHECK-NEXT: 8 | double a
// CHECK-NEXT: 16 | class B (base)
-// CHECK-NEXT: 16 | (B vtable pointer)
+// CHECK-NEXT: 16 | (B vftable pointer)
// CHECK-NEXT: 20 | int b_field
// CHECK-NEXT: 24 | (C vbtable pointer)
// CHECK-NEXT: 32 | double c1_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: 64 | (B vftable 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-NEXT: nvsize=64, 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: 16 | (D vftable pointer)
// CHECK-NEXT: 24 | double a
// CHECK-NEXT: 32 | class B (base)
-// CHECK-NEXT: 32 | (B vtable pointer)
+// CHECK-NEXT: 32 | (B vftable pointer)
// CHECK-NEXT: 36 | int b_field
// CHECK-NEXT: 40 | (C vbtable pointer)
// CHECK-NEXT: 48 | double c1_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: 80 | (B vftable 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-NEXT: nvsize=64, nvalign=8
// CHECK: sizeof=96, dsize=96, align=8
// CHECK-NEXT: nvsize=96, nvalign=8
// 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: 16 | (D vftable pointer)
// CHECK-NEXT: 24 | double a
// CHECK-NEXT: 32 | class B (base)
-// CHECK-NEXT: 32 | (B vtable pointer)
+// CHECK-NEXT: 32 | (B vftable pointer)
// CHECK-NEXT: 36 | int b_field
// CHECK-NEXT: 40 | (C vbtable pointer)
// CHECK-NEXT: 48 | double c1_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: 80 | (B vftable 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-NEXT: nvsize=64, nvalign=8
// CHECK: 96 | int x
// CHECK-NEXT: sizeof=104, dsize=104, align=8
// CHECK-NEXT: sizeof=4, dsize=4, align=4
// CHECK-NEXT: nvsize=4, nvalign=4
-// FIXME: Dump should not be showing vfptr, and vbptr is in the wrong order.
// CHECK: 0 | struct H
-// CHECK-NEXT: 0 | (H vtable pointer)
-// CHECK-NEXT: 4 | (H vbtable pointer)
// CHECK-NEXT: 0 | struct G (base)
// CHECK-NEXT: 0 | int g_field
+// CHECK-NEXT: 4 | (H vbtable pointer)
// CHECK-NEXT: 8 | class D (virtual base)
-// CHECK-NEXT: 8 | (D vtable pointer)
+// CHECK-NEXT: 8 | (D vftable pointer)
// CHECK-NEXT: 16 | double a
// CHECK-NEXT: sizeof=24, dsize=24, align=8
+// CHECK-NEXT: nvsize=8, nvalign=4
+
+// CHECK: 0 | struct I
+// CHECK-NEXT: 0 | (I vftable pointer)
+// CHECK-NEXT: 8 | (I vbtable pointer)
+// CHECK-NEXT: 16 | double q
+// CHECK-NEXT: 24 | class D (virtual base)
+// CHECK-NEXT: 24 | (D vftable pointer)
+// CHECK-NEXT: 32 | double a
+// CHECK-NEXT: sizeof=40, dsize=40, align=8
// CHECK-NEXT: nvsize=24, nvalign=8