Implements 64 bit microsoft record layout and adds lit tests to cover

it.  Also removes all of the microsoft C++ ABI related code from the 
itanium layout builder.

Differential Revision: http://llvm-reviews.chandlerc.com/D2003

llvm-svn: 193290
This commit is contained in:
Warren Hunt 2013-10-23 23:53:07 +00:00
parent 79bb266346
commit 55d8e82f86
13 changed files with 1545 additions and 465 deletions

View File

@ -1181,23 +1181,19 @@ Objective-C requiring a call to ``super`` in an override
--------------------------------------------------------
Some Objective-C classes allow a subclass to override a particular method in a
parent class but expect that the overriding method also calls the overridden
method in the parent class. For these cases, we provide an attribute to
designate that a method requires a "call to ``super``" in the overriding
method in the subclass.
parent class but expect that the override chains to calling the same method in
the parent class. In such cases it is useful to be able to mark a method as
requiring this chaining behavior. For these cases, we provide an attribute to
designate that a method requires a "call to ``super``" in the overriden method
in the subclass.
**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only
be placed at the end of a method declaration:
**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only be placed at the end of a method declaration:
.. code-block:: objc
- (void)foo __attribute__((objc_requires_super));
This attribute can only be applied the method declarations within a class, and
not a protocol. Currently this attribute does not enforce any placement of
where the call occurs in the overriding method (such as in the case of
``-dealloc`` where the call must appear at the end). It checks only that it
exists.
This attribute can only be applied the method declarations within a class, and not a protocol.
Note that on both OS X and iOS that the Foundation framework provides a
convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this

View File

@ -604,13 +604,6 @@ protected:
/// pointer, as opposed to inheriting one from a primary base class.
bool HasOwnVFPtr;
/// HasOwnVBPtr - Whether the class provides its own vbtbl
/// pointer, as opposed to inheriting one from a base class. Only for MS.
bool HasOwnVBPtr;
/// VBPtrOffset - Virtual base table offset. Only for MS layout.
CharUnits VBPtrOffset;
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
@ -658,8 +651,6 @@ protected:
NonVirtualAlignment(CharUnits::One()),
PrimaryBase(0), PrimaryBaseIsVirtual(false),
HasOwnVFPtr(false),
HasOwnVBPtr(false),
VBPtrOffset(CharUnits::fromQuantity(-1)),
FirstNearlyEmptyVBase(0) { }
/// Reset this RecordLayoutBuilder to a fresh state, using the given
@ -687,12 +678,6 @@ protected:
return Context.getTargetInfo().getCXXABI();
}
bool isMicrosoftCXXABI() const {
return getCXXABI().isMicrosoft();
}
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
@ -734,21 +719,12 @@ protected:
void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
CharUnits Offset);
bool needsVFTable(const CXXRecordDecl *RD) const;
bool hasNewVirtualFunction(const CXXRecordDecl *RD,
bool IgnoreDestructor = false) const;
bool isPossiblePrimaryBase(const CXXRecordDecl *Base) const;
void computeVtordisps(const CXXRecordDecl *RD,
ClassSetTy &VtordispVBases);
/// LayoutVirtualBases - Lays out all the virtual bases.
void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
/// LayoutVirtualBase - Lays out a single virtual base.
void LayoutVirtualBase(const BaseSubobjectInfo *Base,
bool IsVtordispNeed = false);
void LayoutVirtualBase(const BaseSubobjectInfo *Base);
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in chars.
@ -858,7 +834,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (isPossiblePrimaryBase(Base)) {
if (Base->isDynamicClass()) {
// We found it.
PrimaryBase = Base;
PrimaryBaseIsVirtual = false;
@ -866,12 +842,6 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
}
}
// The Microsoft ABI doesn't have primary virtual bases.
if (isMicrosoftCXXABI()) {
assert(!PrimaryBase && "Should not get here with a primary base!");
return;
}
// Under the Itanium ABI, if there is no non-virtual primary base class,
// try to compute the primary virtual base. The primary virtual base is
// the first nearly empty virtual base that is not an indirect primary
@ -1050,7 +1020,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// If this class needs a vtable/vf-table and didn't get one from a
// primary base, add it in now.
} else if (needsVFTable(RD)) {
} else if (RD->isDynamicClass()) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
@ -1094,38 +1064,6 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
LayoutNonVirtualBase(BaseInfo);
}
// In the MS ABI, add the vb-table pointer if we need one, which is
// whenever we have a virtual base and we can't re-use a vb-table
// pointer from a non-virtual base.
if (isMicrosoftCXXABI() &&
HasDirectVirtualBases && !HasNonVirtualBaseWithVBTable) {
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
CharUnits PtrAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
// MSVC potentially over-aligns the vb-table pointer by giving it
// the max alignment of all the non-virtual objects in the class.
// This is completely unnecessary, but we're not here to pass
// judgment.
//
// Note that we've only laid out the non-virtual bases, so on the
// first pass Alignment won't be set correctly here, but if the
// vb-table doesn't end up aligned correctly we'll come through
// and redo the layout from scratch with the right alignment.
//
// TODO: Instead of doing this, just lay out the fields as if the
// vb-table were at offset zero, then retroactively bump the field
// offsets up.
PtrAlign = std::max(PtrAlign, Alignment);
EnsureVTablePointerAlignment(PtrAlign);
HasOwnVBPtr = true;
VBPtrOffset = getSize();
setSize(getSize() + PtrWidth);
setDataSize(getSize());
}
}
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
@ -1174,38 +1112,6 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
}
}
/// needsVFTable - Return true if this class needs a vtable or vf-table
/// when laid out as a base class. These are treated the same because
/// they're both always laid out at offset zero.
///
/// This function assumes that the class has no primary base.
bool RecordLayoutBuilder::needsVFTable(const CXXRecordDecl *RD) const {
assert(!PrimaryBase);
// In the Itanium ABI, every dynamic class needs a vtable: even if
// this class has no virtual functions as a base class (i.e. it's
// non-polymorphic or only has virtual functions from virtual
// bases),x it still needs a vtable to locate its virtual bases.
if (!isMicrosoftCXXABI())
return RD->isDynamicClass();
// In the MS ABI, we need a vfptr if the class has virtual functions
// other than those declared by its virtual bases. The AST doesn't
// tell us that directly, and checking manually for virtual
// functions that aren't overrides is expensive, but there are
// some important shortcuts:
// - Non-polymorphic classes have no virtual functions at all.
if (!RD->isPolymorphic()) return false;
// - Polymorphic classes with no virtual bases must either declare
// virtual functions directly or inherit them, but in the latter
// case we would have a primary base.
if (RD->getNumVBases() == 0) return true;
return hasNewVirtualFunction(RD);
}
/// Does the given class inherit non-virtually from any of the classes
/// in the given set?
static bool hasNonVirtualBaseInSet(const CXXRecordDecl *RD,
@ -1228,195 +1134,6 @@ static bool hasNonVirtualBaseInSet(const CXXRecordDecl *RD,
return false;
}
/// Does the given method (B::foo()) already override a method (A::foo())
/// such that A requires a vtordisp in B? If so, we don't need to add a
/// new vtordisp for B in a yet-more-derived class C providing C::foo().
static bool overridesMethodRequiringVtorDisp(const ASTContext &Context,
const CXXMethodDecl *M) {
CXXMethodDecl::method_iterator
I = M->begin_overridden_methods(), E = M->end_overridden_methods();
if (I == E) return false;
const ASTRecordLayout::VBaseOffsetsMapTy &offsets =
Context.getASTRecordLayout(M->getParent()).getVBaseOffsetsMap();
do {
const CXXMethodDecl *overridden = *I;
// If the overridden method's class isn't recognized as a virtual
// base in the derived class, ignore it.
ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
it = offsets.find(overridden->getParent());
if (it == offsets.end()) continue;
// Otherwise, check if the overridden method's class needs a vtordisp.
if (it->second.hasVtorDisp()) return true;
} while (++I != E);
return false;
}
/// In the Microsoft ABI, decide which of the virtual bases require a
/// vtordisp field.
void RecordLayoutBuilder::computeVtordisps(const CXXRecordDecl *RD,
ClassSetTy &vtordispVBases) {
// Bail out if we have no virtual bases.
assert(RD->getNumVBases());
// Build up the set of virtual bases that we haven't decided yet.
ClassSetTy undecidedVBases;
for (CXXRecordDecl::base_class_const_iterator
I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *vbase = I->getType()->getAsCXXRecordDecl();
undecidedVBases.insert(vbase);
}
assert(!undecidedVBases.empty());
// A virtual base requires a vtordisp field in a derived class if it
// requires a vtordisp field in a base class. Walk all the direct
// bases and collect this information.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
const ASTRecordLayout &baseLayout = Context.getASTRecordLayout(base);
// Iterate over the set of virtual bases provided by this class.
for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
VI = baseLayout.getVBaseOffsetsMap().begin(),
VE = baseLayout.getVBaseOffsetsMap().end(); VI != VE; ++VI) {
// If it doesn't need a vtordisp in this base, ignore it.
if (!VI->second.hasVtorDisp()) continue;
// If we've already seen it and decided it needs a vtordisp, ignore it.
if (!undecidedVBases.erase(VI->first))
continue;
// Add it.
vtordispVBases.insert(VI->first);
// Quit as soon as we've decided everything.
if (undecidedVBases.empty())
return;
}
}
// Okay, we have virtual bases that we haven't yet decided about. A
// virtual base requires a vtordisp if any the non-destructor
// virtual methods declared in this class directly override a method
// provided by that virtual base. (If so, we need to emit a thunk
// for that method, to be used in the construction vftable, which
// applies an additional 'vtordisp' this-adjustment.)
// Collect the set of bases directly overridden by any method in this class.
// It's possible that some of these classes won't be virtual bases, or won't be
// provided by virtual bases, or won't be virtual bases in the overridden
// instance but are virtual bases elsewhere. Only the last matters for what
// we're doing, and we can ignore those: if we don't directly override
// a method provided by a virtual copy of a base class, but we do directly
// override a method provided by a non-virtual copy of that base class,
// then we must indirectly override the method provided by the virtual base,
// and so we should already have collected it in the loop above.
ClassSetTy overriddenBases;
for (CXXRecordDecl::method_iterator
M = RD->method_begin(), E = RD->method_end(); M != E; ++M) {
// Ignore non-virtual methods and destructors.
if (isa<CXXDestructorDecl>(*M) || !M->isVirtual())
continue;
for (CXXMethodDecl::method_iterator I = M->begin_overridden_methods(),
E = M->end_overridden_methods(); I != E; ++I) {
const CXXMethodDecl *overriddenMethod = (*I);
// Ignore methods that override methods from vbases that require
// require vtordisps.
if (overridesMethodRequiringVtorDisp(Context, overriddenMethod))
continue;
// As an optimization, check immediately whether we're overriding
// something from the undecided set.
const CXXRecordDecl *overriddenBase = overriddenMethod->getParent();
if (undecidedVBases.erase(overriddenBase)) {
vtordispVBases.insert(overriddenBase);
if (undecidedVBases.empty()) return;
// We can't 'continue;' here because one of our undecided
// vbases might non-virtually inherit from this base.
// Consider:
// struct A { virtual void foo(); };
// struct B : A {};
// struct C : virtual A, virtual B { virtual void foo(); };
// We need a vtordisp for B here.
}
// Otherwise, just collect it.
overriddenBases.insert(overriddenBase);
}
}
// Walk the undecided v-bases and check whether they (non-virtually)
// provide any of the overridden bases. We don't need to consider
// virtual links because the vtordisp inheres to the layout
// subobject containing the base.
for (ClassSetTy::const_iterator
I = undecidedVBases.begin(), E = undecidedVBases.end(); I != E; ++I) {
if (hasNonVirtualBaseInSet(*I, overriddenBases))
vtordispVBases.insert(*I);
}
}
/// hasNewVirtualFunction - Does the given polymorphic class declare a
/// virtual function that does not override a method from any of its
/// base classes?
bool
RecordLayoutBuilder::hasNewVirtualFunction(const CXXRecordDecl *RD,
bool IgnoreDestructor) const {
if (!RD->getNumBases())
return true;
for (CXXRecordDecl::method_iterator method = RD->method_begin();
method != RD->method_end();
++method) {
if (method->isVirtual() && !method->size_overridden_methods() &&
!(IgnoreDestructor && method->getKind() == Decl::CXXDestructor)) {
return true;
}
}
return false;
}
/// isPossiblePrimaryBase - Is the given base class an acceptable
/// primary base class?
bool
RecordLayoutBuilder::isPossiblePrimaryBase(const CXXRecordDecl *base) const {
// In the Itanium ABI, a class can be a primary base class if it has
// a vtable for any reason.
if (!isMicrosoftCXXABI())
return base->isDynamicClass();
// In the MS ABI, a class can only be a primary base class if it
// provides a vf-table at a static offset. That means it has to be
// non-virtual base. The existence of a separate vb-table means
// that it's possible to get virtual functions only from a virtual
// base, which we have to guard against.
// First off, it has to have virtual functions.
if (!base->isPolymorphic()) return false;
// If it has no virtual bases, then the vfptr must be at a static offset.
if (!base->getNumVBases()) return true;
// Otherwise, the necessary information is cached in the layout.
const ASTRecordLayout &layout = Context.getASTRecordLayout(base);
// If the base has its own vfptr, it can be a primary base.
if (layout.hasOwnVFPtr()) return true;
// If the base has a primary base class, then it can be a primary base.
if (layout.getPrimaryBase()) return true;
// Otherwise it can't.
return false;
}
void
RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
@ -1466,39 +1183,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
if (!RD->getNumVBases())
return;
ClassSetTy VtordispVBases;
computeVtordisps(RD, VtordispVBases);
// This is substantially simplified because there are no virtual
// primary bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
assert(BaseInfo && "Did not find virtual base info!");
// If this base requires a vtordisp, add enough space for an int field.
// This is apparently always 32-bits, even on x64.
bool vtordispNeeded = false;
if (VtordispVBases.count(BaseDecl)) {
CharUnits IntSize =
CharUnits::fromQuantity(Context.getTargetInfo().getIntWidth() / 8);
setSize(getSize() + IntSize);
setDataSize(getSize());
vtordispNeeded = true;
}
LayoutVirtualBase(BaseInfo, vtordispNeeded);
}
}
void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
bool IsVtordispNeed) {
void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
// Layout the base.
@ -1507,10 +1192,9 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
// Add its base class offset.
assert(!VBases.count(Base->Class) && "vbase offset already exists!");
VBases.insert(std::make_pair(Base->Class,
ASTRecordLayout::VBaseInfo(Offset, IsVtordispNeed)));
ASTRecordLayout::VBaseInfo(Offset, false)));
if (!isMicrosoftCXXABI())
AddPrimaryVirtualBaseOffsets(Base, Offset);
AddPrimaryVirtualBaseOffsets(Base, Offset);
}
CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
@ -1664,24 +1348,8 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
if (isMicrosoftCXXABI()) {
if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
CharUnits AlignMember =
NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
setSize(getSize() + AlignMember);
setDataSize(getSize());
NonVirtualSize = Context.toCharUnitsFromBits(
llvm::RoundUpToAlignment(getSizeInBits(),
Context.getTargetInfo().getCharAlign()));
}
MSLayoutVirtualBases(RD);
} else {
// Lay out the virtual bases and add the primary virtual base offsets.
LayoutVirtualBases(RD, RD);
}
// Lay out the virtual bases and add the primary virtual base offsets.
LayoutVirtualBases(RD, RD);
// Finally, round the size of the total struct up to the alignment
// of the struct itself.
@ -2100,13 +1768,6 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
return;
}
// MSVC doesn't round up to the alignment of the record with virtual bases.
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (isMicrosoftCXXABI() && RD->getNumVBases())
return;
}
// Set the size to the final size.
setSize(RoundedSize);
@ -2345,11 +2006,7 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
}
static bool isMsLayout(const RecordDecl* D) {
// FIXME: Use MS record layout for x64 code and remove MS C++ support from the
// Itanium record layout code.
return D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&
D->getASTContext().getTargetInfo().getTriple().getArch() ==
llvm::Triple::x86;
return D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft();
}
// This section contains an implementation of struct layout that is, up to the
@ -2363,21 +2020,25 @@ static bool isMsLayout(const RecordDecl* D) {
// a non-zero length bitfield is ignored.
// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
// function pointer) and a vbptr (virtual base pointer). They can each be
// shared with a, non-virtual bases. These bases need not be the same. vfptrs always occur at offset 0. vbptrs can occur at an
// shared with a, non-virtual bases. These bases need not be the same. vfptrs
// always occur at offset 0. vbptrs can occur at an
// arbitrary offset and are placed after non-virtual bases but before fields.
// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
// the virtual base and is used in conjunction with virtual overrides during
// construction and destruction.
// * vfptrs are allocated in a block of memory equal to the alignment of the
// fields and non-virtual bases at offset 0.
// fields and non-virtual bases at offset 0 in 32 bit mode and in a pointer
// sized block of memory in 64 bit mode.
// * vbptrs are allocated in a block of memory equal to the alignment of the
// fields and non-virtual bases. This block is at a potentially unaligned offset. If the
// allocation slot is unaligned and the alignment is less than or equal to the
// pointer size, additional space is allocated so that the pointer can be aligned properly. This causes very strange effects on the placement of objects after the allocated block. (see
// the code).
// fields and non-virtual bases. This block is at a potentially unaligned
// offset. If the allocation slot is unaligned and the alignment is less than
// or equal to the pointer size, additional space is allocated so that the
// pointer can be aligned properly. This causes very strange effects on the
// placement of objects after the allocated block. (see the code).
// * vtordisps are allocated in a block of memory with size and alignment equal
// to the alignment of the completed structure (before applying __declspec(
// align())). The vtordisp always occur at the end of the allocation block, immediately prior to the virtual base.
// align())). The vtordisp always occur at the end of the allocation block,
// immediately prior to the virtual base.
// * The last zero sized non-virtual base is allocated after the placement of
// vbptr if one exists and can be placed at the end of the struct, potentially
// aliasing either the first member or another struct allocated after this
@ -2472,7 +2133,11 @@ public:
/// \brief The data alignment of the record layout.
CharUnits DataSize;
/// \brief The alignment of the non-virtual portion of the record layout
/// including. Only used for C++ layouts.
/// without the impact of the virtual pointers.
/// Only used for C++ layouts.
CharUnits BasesAndFieldsAlignment;
/// \brief The alignment of the non-virtual portion of the record layout
/// Only used for C++ layouts.
CharUnits NonVirtualAlignment;
/// \brief The additional alignment imposed by the virtual bases.
CharUnits VirtualAlignment;
@ -2496,6 +2161,11 @@ public:
CharUnits PointerAlignment;
/// \brief Holds an empty base we haven't yet laid out.
const CXXRecordDecl *LazyEmptyBase;
/// \brief Lets us know if the last base we laid out was empty. Only used
/// when adjusting the placement of a last zero-sized base in 64 bit mode.
bool LastBaseWasEmpty;
/// \brief Lets us know if we're in 64-bit mode
bool Is64BitMode;
};
} // namespace
@ -2548,6 +2218,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
IsUnion = RD->isUnion();
Is64BitMode = RD->getASTContext().getTargetInfo().getTriple().getArch() ==
llvm::Triple::x86_64;
Size = CharUnits::Zero();
Alignment = CharUnits::One();
@ -2601,6 +2273,7 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
SharedVBPtrBase = 0;
PrimaryBase = 0;
VirtualAlignment = CharUnits::One();
AlignAfterVBases = Is64BitMode;
// If the record has a dynamic base class, attempt to choose a primary base
// class. It is the first (in direct base class order) non-virtual dynamic
@ -2638,6 +2311,7 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
// behavior correct and is not actually very expensive.
layoutFields(RD);
Size = CharUnits::Zero();
BasesAndFieldsAlignment = Alignment;
FieldOffsets.clear();
}
@ -2656,17 +2330,21 @@ void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) {
if (!HasVFPtr)
return;
// MSVC potentially over-aligns the vf-table pointer by giving it
// the max alignment of all the non-virtual data in the class. The resulting
// layout is essentially { vftbl, { nvdata } }. This is completely
// MSVC 32 (but not 64) potentially over-aligns the vf-table pointer by giving
// it the max alignment of all the non-virtual data in the class. The
// resulting layout is essentially { vftbl, { nvdata } }. This is completely
// unnecessary, but we're not here to pass judgment.
updateAlignment(PointerAlignment);
Size += Alignment;
if (Is64BitMode)
Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize;
else
Size = Size.RoundUpToAlignment(PointerAlignment) + Alignment;
}
void
MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
LazyEmptyBase = 0;
LastBaseWasEmpty = false;
// Lay out the primary base first.
if (PrimaryBase)
@ -2696,8 +2374,10 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
Bases.insert(std::make_pair(LazyEmptyBase, Size));
// Empty bases only consume space when followed by another empty base.
if (RD && Layout->getNonVirtualSize().isZero())
if (RD && Layout->getNonVirtualSize().isZero()) {
LastBaseWasEmpty = true;
Size++;
}
LazyEmptyBase = 0;
}
@ -2716,6 +2396,7 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
Size = BaseOffset + Layout->getDataSize();
// Note: we don't update alignment here because it was accounted
// for during initalization.
LastBaseWasEmpty = false;
}
void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
@ -2725,24 +2406,24 @@ void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase);
VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset();
} else {
updateAlignment(PointerAlignment);
VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment);
if (Alignment == PointerAlignment && Size % PointerAlignment) {
CharUnits x = Size + Alignment + Alignment;
Size = VBPtrOffset + Alignment;
// Handle strange padding rules. I have no explanation for why the
// virtual base is padded in such an odd way. My guess is that they
// always Add 2 * Alignment and incorrectly round down to the appropriate
// alignment. It's important to get this case correct because it impacts
// the layout of the first member of the struct.
RecordDecl::field_iterator FieldBegin = RD->field_begin();
if (FieldBegin != RD->field_end())
Size += CharUnits::fromQuantity(
x % getAdjustedFieldInfo(*FieldBegin).second);
} else
Size += Alignment;
CharUnits OldSize = Size;
Size = VBPtrOffset + PointerSize;
if (BasesAndFieldsAlignment <= PointerAlignment) {
// Handle strange padding rules for the lazily placed base. I have no
// explanation for why the last virtual base is padded in such an odd way.
// Two things to note about this padding are that the rules are different
// if the alignment of the bases+fields is <= to the alignemnt of a
// pointer and that the rule in 64-bit mode behaves differently depending
// on if the second to last base was also zero sized.
Size += OldSize % BasesAndFieldsAlignment.getQuantity();
} else {
if (Is64BitMode)
Size += LastBaseWasEmpty ? CharUnits::One() : CharUnits::Zero();
else
Size = OldSize + BasesAndFieldsAlignment;
}
updateAlignment(PointerAlignment);
}
// Flush the lazy empty base.
@ -2886,10 +2567,10 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
// Empty bases only consume space when followed by another empty base.
// The space consumed is in an Alignment sized/aligned block and the v-base
// is placed at its alignment offset into the chunk, unless its alignment
// is less than the size of a pointer, at which it is placed at pointer
// width offset in the chunck. We have no idea why.
// is less than 4 bytes, at which it is placed at 4 byte offset in the
// chunk. We have no idea why.
if (RD && Context.getASTRecordLayout(RD).getNonVirtualSize().isZero())
Size = Size.RoundUpToAlignment(Alignment) + PointerSize;
Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
LazyEmptyBase = 0;
}
@ -2906,8 +2587,9 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
CharUnits BaseNVSize = Layout.getNonVirtualSize();
CharUnits BaseAlign = Layout.getAlignment();
// vtordisps are always 4 bytes (even in 64-bit mode)
if (HasVtordisp)
Size = Size.RoundUpToAlignment(Alignment) + PointerSize;
Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
Size = Size.RoundUpToAlignment(BaseAlign);
// Insert the base here.
@ -3091,8 +2773,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder.Alignment,
Builder.HasOwnVFPtr,
RD->isDynamicClass(),
Builder.HasOwnVBPtr,
Builder.VBPtrOffset,
false,
CharUnits::fromQuantity(-1),
DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -86,6 +88,20 @@ struct A : B1, B0, B2, virtual V {
// CHECK: 64 | char a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | struct B1 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 4 | struct B0 (base)
// CHECK-X64: 4 | int a
// CHECK-X64: 16 | struct B2 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | (A vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct V (virtual base)
// CHECK-X64: 48 | char a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct B : B2, B0, B1, virtual V {
int a;
@ -106,6 +122,20 @@ struct B : B2, B0, B1, virtual V {
// CHECK: 64 | char a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | struct B2 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 16 | struct B0 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | struct B1 (base)
// CHECK-X64: 32 | int a
// CHECK-X64: 40 | (B vbtable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: 64 | struct V (virtual base)
// CHECK-X64: 64 | char a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=64, nvalign=16]
struct C : B1, B0, virtual V {
int a;
@ -126,6 +156,19 @@ struct C : B1, B0, virtual V {
// CHECK: 48 | char a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | struct B1 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 4 | struct B0 (base)
// CHECK-X64: 4 | int a
// CHECK-X64: 8 | (C vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | long long a1
// CHECK-X64: 32 | struct V (virtual base)
// CHECK-X64: 32 | char a
// CHECK-X64: | [sizeof=48, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct D : B2, B0, virtual V {
int a;
@ -144,6 +187,18 @@ struct D : B2, B0, virtual V {
// CHECK: 48 | char a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | struct B2 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 16 | struct B0 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | (D vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct V (virtual base)
// CHECK-X64: 48 | char a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct E : B3, B0, virtual V {
int a;
@ -163,6 +218,19 @@ struct E : B3, B0, virtual V {
// CHECK: 48 | char a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct E
// CHECK-X64: 0 | struct B3 (base)
// CHECK-X64: 0 | long long a1
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | (E vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct V (virtual base)
// CHECK-X64: 48 | char a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct F : B0, virtual V1 {
__declspec(align(16)) int a;
@ -182,6 +250,18 @@ struct F : B0, virtual V1 {
// CHECK: 128 | struct A16 (base) (empty)
// CHECK: | [sizeof=128, align=32
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F
// CHECK-X64: 0 | struct B0 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (F vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 60 | (vtordisp for vbase V1)
// CHECK-X64: 64 | struct V1 (virtual base)
// CHECK-X64: 64 | (V1 vftable pointer)
// CHECK-X64: 96 | struct A16 (base) (empty)
// CHECK-X64: | [sizeof=96, align=32
// CHECK-X64: | nvsize=32, nvalign=16]
struct G : virtual V2, virtual V3 {
int a;
@ -199,6 +279,17 @@ struct G : virtual V2, virtual V3 {
// CHECK: 24 | int a
// CHECK: | [sizeof=28, align=8
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct G
// CHECK-X64: 0 | (G vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct V2 (virtual base)
// CHECK-X64: 16 | long long a
// CHECK-X64: 24 | int a1
// CHECK-X64: 32 | struct V3 (virtual base)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct H {
__declspec(align(16)) int a;
@ -212,6 +303,12 @@ struct H {
// CHECK: 4 | int b
// CHECK: | [sizeof=16, align=16
// CHECK: | nvsize=16, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct H
// CHECK-X64: 0 | int a
// CHECK-X64: 4 | int b
// CHECK-X64: | [sizeof=16, align=16
// CHECK-X64: | nvsize=16, nvalign=16]
struct I {
B2 a;
@ -223,11 +320,16 @@ struct I {
// CHECK: 0 | struct I
// CHECK: 0 | struct B2 a
// CHECK: 0 | int a
// CHECK: | [sizeof=16, align=16
// CHECK: | nvsize=16, nvalign=16]
// CHECK: 16 | int b
// CHECK: | [sizeof=32, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct I
// CHECK-X64: 0 | struct B2 a
// CHECK-X64: 0 | int a
// CHECK-X64: 16 | int b
// CHECK-X64: | [sizeof=32, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct AX : B0X, virtual B2X, virtual B6X, virtual B3X {
int a;
@ -254,6 +356,24 @@ struct AX : B0X, virtual B2X, virtual B6X, virtual B3X {
// CHECK: 84 | int a
// CHECK: | [sizeof=96, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AX
// CHECK-X64: 0 | (AX vftable pointer)
// CHECK-X64: 16 | struct B0X (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | int a1
// CHECK-X64: 24 | (AX vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B2X (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: 52 | struct B6X (virtual base)
// CHECK-X64: 52 | int a
// CHECK-X64: 76 | (vtordisp for vbase B3X)
// CHECK-X64: 80 | struct B3X (virtual base)
// CHECK-X64: 80 | (B3X vftable pointer)
// CHECK-X64: 88 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct BX : B4X, virtual B2X, virtual B6X, virtual B3X {
int a;
@ -281,6 +401,25 @@ struct BX : B4X, virtual B2X, virtual B6X, virtual B3X {
// CHECK: 100 | int a
// CHECK: | [sizeof=112, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct BX
// CHECK-X64: 0 | (BX vftable pointer)
// CHECK-X64: 16 | struct B4X (base)
// CHECK-X64: 16 | struct A16X (base) (empty)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | int a1
// CHECK-X64: 32 | (BX vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct B2X (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: 52 | struct B6X (virtual base)
// CHECK-X64: 52 | int a
// CHECK-X64: 76 | (vtordisp for vbase B3X)
// CHECK-X64: 80 | struct B3X (virtual base)
// CHECK-X64: 80 | (B3X vftable pointer)
// CHECK-X64: 88 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct CX : B5X, virtual B2X, virtual B6X, virtual B3X {
int a;
@ -308,6 +447,25 @@ struct CX : B5X, virtual B2X, virtual B6X, virtual B3X {
// CHECK: 68 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct CX
// CHECK-X64: 0 | (CX vftable pointer)
// CHECK-X64: 16 | struct B5X (base)
// CHECK-X64: 16 | (B5X vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 28 | int a1
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct A16X (virtual base) (empty)
// CHECK-X64: 48 | struct B2X (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: 52 | struct B6X (virtual base)
// CHECK-X64: 52 | int a
// CHECK-X64: 76 | (vtordisp for vbase B3X)
// CHECK-X64: 80 | struct B3X (virtual base)
// CHECK-X64: 80 | (B3X vftable pointer)
// CHECK-X64: 88 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct __declspec(align(16)) DX {
int a;
@ -321,6 +479,12 @@ struct __declspec(align(16)) DX {
// CHECK: 4 | int a
// CHECK: | [sizeof=16, align=16
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct DX
// CHECK-X64: 0 | (DX vftable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: | [sizeof=16, align=16
// CHECK-X64: | nvsize=16, nvalign=8]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -45,6 +47,16 @@ struct TestF0 : A4, virtual B4 {
// CHECK: 12 | int a
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF0
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF0 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B4 (virtual base)
// CHECK-X64: 24 | int a
// CHECK-X64: | [sizeof=32, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct TestF1 : A4, virtual A16 {
int a;
@ -61,6 +73,16 @@ struct TestF1 : A4, virtual A16 {
// CHECK: 16 | int a
// CHECK: | [sizeof=32, align=16
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF1
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF1 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | struct A16 (virtual base)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=48, align=16
// CHECK-X64: | nvsize=24, nvalign=8]
struct TestF2 : A4, virtual C4 {
int a;
@ -78,6 +100,17 @@ struct TestF2 : A4, virtual C4 {
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF2
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF2 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct C4 (virtual base)
// CHECK-X64: 24 | (C4 vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct TestF3 : A4, virtual C16 {
int a;
@ -95,6 +128,17 @@ struct TestF3 : A4, virtual C16 {
// CHECK: 32 | int a
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF3
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF3 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | struct C16 (virtual base)
// CHECK-X64: 32 | (C16 vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=24, nvalign=8]
struct TestF4 : TestF3, A4 {
int a;
@ -116,6 +160,21 @@ struct TestF4 : TestF3, A4 {
// CHECK: 48 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF4
// CHECK-X64: 0 | struct TestF3 (base)
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF3 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct A4 (base)
// CHECK-X64: 24 | int a
// CHECK-X64: 28 | int a
// CHECK-X64: 32 | struct C16 (virtual base)
// CHECK-X64: 32 | (C16 vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct TestF5 : TestF3, A4 {
int a;
@ -139,6 +198,22 @@ struct TestF5 : TestF3, A4 {
// CHECK: 64 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF5
// CHECK-X64: 0 | (TestF5 vftable pointer)
// CHECK-X64: 16 | struct TestF3 (base)
// CHECK-X64: 16 | struct A4 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | (TestF3 vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 40 | struct A4 (base)
// CHECK-X64: 40 | int a
// CHECK-X64: 44 | int a
// CHECK-X64: 48 | struct C16 (virtual base)
// CHECK-X64: 48 | (C16 vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct TestF6 : TestF3, A4 {
int a;
@ -162,6 +237,22 @@ struct TestF6 : TestF3, A4 {
// CHECK: 64 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF6
// CHECK-X64: 0 | struct TestF3 (base)
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF3 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct A4 (base)
// CHECK-X64: 24 | int a
// CHECK-X64: 28 | int a
// CHECK-X64: 44 | (vtordisp for vbase C16)
// CHECK-X64: 48 | struct C16 (virtual base)
// CHECK-X64: 48 | (C16 vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct TestF7 : A4, virtual C16 {
int a;
@ -181,6 +272,18 @@ struct TestF7 : A4, virtual C16 {
// CHECK: 48 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF7
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF7 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 44 | (vtordisp for vbase C16)
// CHECK-X64: 48 | struct C16 (virtual base)
// CHECK-X64: 48 | (C16 vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=24, nvalign=8]
struct TestF8 : TestF7, A4 {
int a;
@ -204,6 +307,22 @@ struct TestF8 : TestF7, A4 {
// CHECK: 64 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF8
// CHECK-X64: 0 | struct TestF7 (base)
// CHECK-X64: 0 | struct A4 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (TestF7 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct A4 (base)
// CHECK-X64: 24 | int a
// CHECK-X64: 28 | int a
// CHECK-X64: 44 | (vtordisp for vbase C16)
// CHECK-X64: 48 | struct C16 (virtual base)
// CHECK-X64: 48 | (C16 vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct TestF9 : A4, virtual C16 {
int a;
@ -223,6 +342,18 @@ struct TestF9 : A4, virtual C16 {
// CHECK: 32 | int a
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestF9
// CHECK-X64: 0 | (TestF9 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (TestF9 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | struct C16 (virtual base)
// CHECK-X64: 32 | (C16 vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=32, nvalign=8]
struct TestFA : TestF9, A4 {
int a;
@ -246,6 +377,22 @@ struct TestFA : TestF9, A4 {
// CHECK: 48 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestFA
// CHECK-X64: 0 | struct TestF9 (primary base)
// CHECK-X64: 0 | (TestF9 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (TestF9 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | struct A4 (base)
// CHECK-X64: 32 | int a
// CHECK-X64: 36 | int a
// CHECK-X64: 48 | struct C16 (virtual base)
// CHECK-X64: 48 | (C16 vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct TestFB : A16, virtual C16 {
int a;
@ -265,6 +412,18 @@ struct TestFB : A16, virtual C16 {
// CHECK: 80 | int a
// CHECK: | [sizeof=96, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestFB
// CHECK-X64: 0 | (TestFB vftable pointer)
// CHECK-X64: 16 | struct A16 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | (TestFB vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct C16 (virtual base)
// CHECK-X64: 48 | (C16 vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct TestFC : TestFB, A4 {
int a;
@ -288,6 +447,22 @@ struct TestFC : TestFB, A4 {
// CHECK: 96 | int a
// CHECK: | [sizeof=112, align=16
// CHECK: | nvsize=80, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct TestFC
// CHECK-X64: 0 | struct TestFB (primary base)
// CHECK-X64: 0 | (TestFB vftable pointer)
// CHECK-X64: 16 | struct A16 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | (TestFB vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct A4 (base)
// CHECK-X64: 48 | int a
// CHECK-X64: 52 | int a
// CHECK-X64: 64 | struct C16 (virtual base)
// CHECK-X64: 64 | (C16 vftable pointer)
// CHECK-X64: 80 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=64, nvalign=16]
struct A16f {
@ -329,6 +504,25 @@ struct F0 : A4, B {
// CHECK: 96 | int a
// CHECK: | [sizeof=112, align=16
// CHECK: | nvsize=80, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F0
// CHECK-X64: 0 | (F0 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B (base)
// CHECK-X64: 16 | struct A4 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | struct Y (base)
// CHECK-X64: 20 | char y
// CHECK-X64: 32 | struct X (base)
// CHECK-X64: 32 | (X vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | int a
// CHECK-X64: 64 | struct A16f (virtual base)
// CHECK-X64: 64 | (A16f vftable pointer)
// CHECK-X64: 80 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=64, nvalign=16]
struct F1 : B, A4 {
int a;
@ -355,6 +549,25 @@ struct F1 : B, A4 {
// CHECK: 80 | int a
// CHECK: | [sizeof=96, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F1
// CHECK-X64: 0 | (F1 vftable pointer)
// CHECK-X64: 16 | struct B (base)
// CHECK-X64: 16 | struct A4 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | struct Y (base)
// CHECK-X64: 20 | char y
// CHECK-X64: 32 | struct X (base)
// CHECK-X64: 32 | (X vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct A4 (base)
// CHECK-X64: 48 | int a
// CHECK-X64: 52 | int a
// CHECK-X64: 64 | struct A16f (virtual base)
// CHECK-X64: 64 | (A16f vftable pointer)
// CHECK-X64: 80 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=64, nvalign=16]
struct F2 : A4, virtual A16f {
int a;
@ -374,6 +587,18 @@ struct F2 : A4, virtual A16f {
// CHECK: 32 | int a
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F2
// CHECK-X64: 0 | (F2 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (F2 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | struct A16f (virtual base)
// CHECK-X64: 32 | (A16f vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=32, nvalign=8]
struct F3 : A4, virtual A16f {
__declspec(align(16)) int a;
@ -393,6 +618,18 @@ struct F3 : A4, virtual A16f {
// CHECK: 80 | int a
// CHECK: | [sizeof=96, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F3
// CHECK-X64: 0 | (F3 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (F3 vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct A16f (virtual base)
// CHECK-X64: 48 | (A16f vftable pointer)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct F4 : A4, B {
__declspec(align(16)) int a;
@ -419,6 +656,25 @@ struct F4 : A4, B {
// CHECK: 96 | int a
// CHECK: | [sizeof=112, align=16
// CHECK: | nvsize=80, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F4
// CHECK-X64: 0 | (F4 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B (base)
// CHECK-X64: 16 | struct A4 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | struct Y (base)
// CHECK-X64: 20 | char y
// CHECK-X64: 32 | struct X (base)
// CHECK-X64: 32 | (X vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | int a
// CHECK-X64: 64 | struct A16f (virtual base)
// CHECK-X64: 64 | (A16f vftable pointer)
// CHECK-X64: 80 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=64, nvalign=16]
struct F5 : A16f, virtual A4 {
int a;
@ -437,6 +693,17 @@ struct F5 : A16f, virtual A4 {
// CHECK: 64 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F5
// CHECK-X64: 0 | struct A16f (primary base)
// CHECK-X64: 0 | (A16f vftable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | (F5 vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct A4 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct F6 : virtual A16f, A4, virtual B {
int a;
@ -464,6 +731,26 @@ struct F6 : virtual A16f, A4, virtual B {
// CHECK: 68 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F6
// CHECK-X64: 0 | (F6 vftable pointer)
// CHECK-X64: 8 | struct A4 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (F6 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | struct A16f (virtual base)
// CHECK-X64: 32 | (A16f vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: 64 | struct B (virtual base)
// CHECK-X64: 64 | struct A4 (base)
// CHECK-X64: 64 | int a
// CHECK-X64: 68 | struct Y (base)
// CHECK-X64: 68 | char y
// CHECK-X64: 80 | struct X (base)
// CHECK-X64: 80 | (X vbtable pointer)
// CHECK-X64: 88 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=32, nvalign=8]
int a[
sizeof(TestF0)+

View File

@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
extern "C" int printf(const char *fmt, ...);

View File

@ -1,27 +1,29 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
struct __declspec(align(8)) B0 { B0() {printf("B0 : %3d\n", ((int)this)&0xfff);} };
struct __declspec(align(8)) B1 { B1() {printf("B1 : %3d\n", ((int)this)&0xfff);} };
struct __declspec(align(8)) B2 { B2() {printf("B2 : %3d\n", ((int)this)&0xfff);} };
struct __declspec(align(8)) B3 { B3() {printf("B3 : %3d\n", ((int)this)&0xfff);} };
struct __declspec(align(8)) B4 { B4() {printf("B4 : %3d\n", ((int)this)&0xfff);} };
struct __declspec(align(8)) B0 { B0() {printf("B0 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct __declspec(align(8)) B1 { B1() {printf("B1 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct __declspec(align(8)) B2 { B2() {printf("B2 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct __declspec(align(8)) B3 { B3() {printf("B3 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct __declspec(align(8)) B4 { B4() {printf("B4 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct C0 { int a; C0() : a(0xf00000C0) {printf("C0 : %3d\n", ((int)this)&0xfff);} };
struct C1 { int a; C1() : a(0xf00000C1) {printf("C1 : %3d\n", ((int)this)&0xfff);} };
struct C2 { int a; C2() : a(0xf00000C2) {printf("C2 : %3d\n", ((int)this)&0xfff);} };
struct C3 { int a; C3() : a(0xf00000C3) {printf("C3 : %3d\n", ((int)this)&0xfff);} };
struct C4 { int a; C4() : a(0xf00000C4) {printf("C4 : %3d\n", ((int)this)&0xfff);} };
struct C0 { int a; C0() : a(0xf00000C0) {printf("C0 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct C1 { int a; C1() : a(0xf00000C1) {printf("C1 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct C2 { int a; C2() : a(0xf00000C2) {printf("C2 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct C3 { int a; C3() : a(0xf00000C3) {printf("C3 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct C4 { int a; C4() : a(0xf00000C4) {printf("C4 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct __declspec(align(16)) D0 { D0() {printf("D0 : %3d\n", ((int)this)&0xfff);} virtual void f() {} };
struct D1 { D1() {printf("D1 : %3d\n", ((int)this)&0xfff);} };
struct D2 { int a[8]; D2() {printf("D2 : %3d\n", ((int)this)&0xfff);} };
struct __declspec(align(16)) D0 { D0() {printf("D0 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} virtual void f() {} };
struct D1 { D1() {printf("D1 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct D2 { int a[8]; D2() {printf("D2 : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);} };
struct A : virtual B0 {
int a;
A() : a(0xf000000A) {printf("X : %3d\n", ((int)this)&0xfff);}
A() : a(0xf000000A) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -31,11 +33,18 @@ struct A : virtual B0 {
// CHECK: 8 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=8, align=8
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | (A vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct B : virtual B0 {
B0 b0;
int a;
B() : a(0xf000000B) {printf("X : %3d\n", ((int)this)&0xfff);}
B() : a(0xf000000B) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -48,10 +57,20 @@ struct B : virtual B0 {
// CHECK: 24 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=24, align=8
// CHECK: | nvsize=24, nvalign=8]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | (B vbtable pointer)
// CHECK-X64: 8 | struct B0 b0 (empty)
// CHECK-X64: | [sizeof=8, align=8
// CHECK-X64: | nvsize=0, nvalign=1]
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct C : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
int a;
C() : a(0xf000000C) {printf("X : %3d\n", ((int)this)&0xfff);}
C() : a(0xf000000C) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -65,6 +84,17 @@ struct C : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
// CHECK: 40 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=40, align=8
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | (C vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: 24 | struct B1 (virtual base) (empty)
// CHECK-X64: 32 | struct B2 (virtual base) (empty)
// CHECK-X64: 40 | struct B3 (virtual base) (empty)
// CHECK-X64: 48 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=48, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct D {
B0 b0;
@ -73,36 +103,39 @@ struct D {
C2 c2;
B1 b1;
int a;
D() : a(0xf000000D) {printf("X : %3d\n", ((int)this)&0xfff);}
D() : a(0xf000000D) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
// CHECK: 0 | struct D
// CHECK: 0 | struct B0 b0 (empty)
// CHECK: | [sizeof=8, align=8
// CHECK: | nvsize=0, nvalign=1]
// CHECK: 8 | struct C0 c0
// CHECK: 8 | int a
// CHECK: | [sizeof=4, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK: 12 | struct C1 c1
// CHECK: 12 | int a
// CHECK: | [sizeof=4, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK: 16 | struct C2 c2
// CHECK: 16 | int a
// CHECK: | [sizeof=4, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK: 24 | struct B1 b1 (empty)
// CHECK: | [sizeof=8, align=8
// CHECK: | nvsize=0, nvalign=1]
// CHECK: 32 | int a
// CHECK: | [sizeof=40, align=8
// CHECK: | nvsize=40, nvalign=8]
// CHECK-64: *** Dumping AST Record Layout
// CHECK-64: 0 | struct D
// CHECK-64: 0 | struct B0 b0 (empty)
// CHECK-64: 8 | struct C0 c0
// CHECK-64: 8 | int a
// CHECK-64: 12 | struct C1 c1
// CHECK-64: 12 | int a
// CHECK-64: 16 | struct C2 c2
// CHECK-64: 16 | int a
// CHECK-64: 24 | struct B1 b1 (empty)
// CHECK-64: 32 | int a
// CHECK-64: | [sizeof=40, align=8
// CHECK-64: | nvsize=40, nvalign=8]
struct E : virtual B0, virtual C0, virtual C1, virtual C2, virtual B1 {
int a;
E() : a(0xf000000E) {printf("X : %3d\n", ((int)this)&0xfff);}
E() : a(0xf000000E) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -119,10 +152,24 @@ struct E : virtual B0, virtual C0, virtual C1, virtual C2, virtual B1 {
// CHECK: 24 | struct B1 (virtual base) (empty)
// CHECK: | [sizeof=24, align=8
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct E
// CHECK-X64: 0 | (E vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: 16 | struct C0 (virtual base)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | struct C1 (virtual base)
// CHECK-X64: 20 | int a
// CHECK-X64: 24 | struct C2 (virtual base)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | struct B1 (virtual base) (empty)
// CHECK-X64: | [sizeof=32, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct F : virtual C0, virtual B0, virtual B1, virtual C1 {
int a;
F() : a(0xf000000F) {printf("X : %3d\n", ((int)this)&0xfff);}
F() : a(0xf000000F) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -137,10 +184,22 @@ struct F : virtual C0, virtual B0, virtual B1, virtual C1 {
// CHECK: 24 | int a
// CHECK: | [sizeof=32, align=8
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F
// CHECK-X64: 0 | (F vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct C0 (virtual base)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: 32 | struct B1 (virtual base) (empty)
// CHECK-X64: 32 | struct C1 (virtual base)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct G : virtual C0, virtual B0, virtual B1, D0, virtual C1 {
int a;
G() : a(0xf0000010) {printf("X : %3d\n", ((int)this)&0xfff);}
G() : a(0xf0000010) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
virtual void f() {}
};
@ -158,10 +217,24 @@ struct G : virtual C0, virtual B0, virtual B1, D0, virtual C1 {
// CHECK: 56 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct G
// CHECK-X64: 0 | struct D0 (primary base)
// CHECK-X64: 0 | (D0 vftable pointer)
// CHECK-X64: 8 | (G vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | struct C0 (virtual base)
// CHECK-X64: 32 | int a
// CHECK-X64: 40 | struct B0 (virtual base) (empty)
// CHECK-X64: 56 | struct B1 (virtual base) (empty)
// CHECK-X64: 56 | struct C1 (virtual base)
// CHECK-X64: 56 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct H : virtual C0, virtual B0, virtual B1, virtual D0, virtual C1 {
int a;
H() : a(0xf0000011) {printf("X : %3d\n", ((int)this)&0xfff);}
H() : a(0xf0000011) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
virtual void f() {}
};
@ -180,10 +253,25 @@ struct H : virtual C0, virtual B0, virtual B1, virtual D0, virtual C1 {
// CHECK: 52 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct H
// CHECK-X64: 0 | (H vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct C0 (virtual base)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: 40 | struct B1 (virtual base) (empty)
// CHECK-X64: 60 | (vtordisp for vbase D0)
// CHECK-X64: 64 | struct D0 (virtual base)
// CHECK-X64: 64 | (D0 vftable pointer)
// CHECK-X64: 72 | struct C1 (virtual base)
// CHECK-X64: 72 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=16, nvalign=8]
struct I : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
__declspec(align(32)) int a;
I() : a(0xf0000012) {printf("X : %3d\n", ((int)this)&0xfff);}
I() : a(0xf0000012) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -197,10 +285,21 @@ struct I : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
// CHECK: 168 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=192, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct I
// CHECK-X64: 0 | (I vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B0 (virtual base) (empty)
// CHECK-X64: 72 | struct B1 (virtual base) (empty)
// CHECK-X64: 104 | struct B2 (virtual base) (empty)
// CHECK-X64: 136 | struct B3 (virtual base) (empty)
// CHECK-X64: 168 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=192, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct __declspec(align(32)) J : virtual B0, virtual B1, virtual B2, virtual B3, virtual B4 {
int a;
J() : a(0xf0000012) {printf("X : %3d\n", ((int)this)&0xfff);}
J() : a(0xf0000012) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -214,10 +313,21 @@ struct __declspec(align(32)) J : virtual B0, virtual B1, virtual B2, virtual B3,
// CHECK: 136 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=160, align=32
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct J
// CHECK-X64: 0 | (J vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: 40 | struct B1 (virtual base) (empty)
// CHECK-X64: 72 | struct B2 (virtual base) (empty)
// CHECK-X64: 104 | struct B3 (virtual base) (empty)
// CHECK-X64: 136 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=160, align=32
// CHECK-X64: | nvsize=16, nvalign=8]
struct K : virtual D1, virtual B1, virtual B2, virtual B3, virtual B4 {
__declspec(align(32)) int a;
K() : a(0xf0000013) {printf("X : %3d\n", ((int)this)&0xfff);}
K() : a(0xf0000013) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -231,10 +341,21 @@ struct K : virtual D1, virtual B1, virtual B2, virtual B3, virtual B4 {
// CHECK: 168 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=192, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct K
// CHECK-X64: 0 | (K vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct D1 (virtual base) (empty)
// CHECK-X64: 72 | struct B1 (virtual base) (empty)
// CHECK-X64: 104 | struct B2 (virtual base) (empty)
// CHECK-X64: 136 | struct B3 (virtual base) (empty)
// CHECK-X64: 168 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=192, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct L : virtual B1, virtual D1, virtual B2, virtual B3, virtual B4 {
__declspec(align(32)) int a;
L() : a(0xf0000014) {printf("X : %3d\n", ((int)this)&0xfff);}
L() : a(0xf0000014) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -248,10 +369,21 @@ struct L : virtual B1, virtual D1, virtual B2, virtual B3, virtual B4 {
// CHECK: 168 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=192, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct L
// CHECK-X64: 0 | (L vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B1 (virtual base) (empty)
// CHECK-X64: 68 | struct D1 (virtual base) (empty)
// CHECK-X64: 104 | struct B2 (virtual base) (empty)
// CHECK-X64: 136 | struct B3 (virtual base) (empty)
// CHECK-X64: 168 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=192, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct M : virtual B1, virtual B2, virtual D1, virtual B3, virtual B4 {
__declspec(align(32)) int a;
M() : a(0xf0000015) {printf("X : %3d\n", ((int)this)&0xfff);}
M() : a(0xf0000015) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -265,10 +397,21 @@ struct M : virtual B1, virtual B2, virtual D1, virtual B3, virtual B4 {
// CHECK: 168 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=192, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct M
// CHECK-X64: 0 | (M vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B1 (virtual base) (empty)
// CHECK-X64: 72 | struct B2 (virtual base) (empty)
// CHECK-X64: 100 | struct D1 (virtual base) (empty)
// CHECK-X64: 136 | struct B3 (virtual base) (empty)
// CHECK-X64: 168 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=192, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct N : virtual C0, virtual B1, virtual D1, virtual B2, virtual B3, virtual B4 {
__declspec(align(32)) int a;
N() : a(0xf0000016) {printf("X : %3d\n", ((int)this)&0xfff);}
N() : a(0xf0000016) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -284,10 +427,23 @@ struct N : virtual C0, virtual B1, virtual D1, virtual B2, virtual B3, virtual B
// CHECK: 200 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=224, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct N
// CHECK-X64: 0 | (N vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct C0 (virtual base)
// CHECK-X64: 64 | int a
// CHECK-X64: 72 | struct B1 (virtual base) (empty)
// CHECK-X64: 100 | struct D1 (virtual base) (empty)
// CHECK-X64: 136 | struct B2 (virtual base) (empty)
// CHECK-X64: 168 | struct B3 (virtual base) (empty)
// CHECK-X64: 200 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=224, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct O : virtual C0, virtual B1, virtual B2, virtual D1, virtual B3, virtual B4 {
__declspec(align(32)) int a;
O() : a(0xf0000017) {printf("X : %3d\n", ((int)this)&0xfff);}
O() : a(0xf0000017) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -303,10 +459,23 @@ struct O : virtual C0, virtual B1, virtual B2, virtual D1, virtual B3, virtual B
// CHECK: 200 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=224, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct O
// CHECK-X64: 0 | (O vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct C0 (virtual base)
// CHECK-X64: 64 | int a
// CHECK-X64: 72 | struct B1 (virtual base) (empty)
// CHECK-X64: 104 | struct B2 (virtual base) (empty)
// CHECK-X64: 132 | struct D1 (virtual base) (empty)
// CHECK-X64: 168 | struct B3 (virtual base) (empty)
// CHECK-X64: 200 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=224, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct P : virtual B1, virtual C0, virtual D1, virtual B2, virtual B3, virtual B4 {
__declspec(align(32)) int a;
P() : a(0xf0000018) {printf("X : %3d\n", ((int)this)&0xfff);}
P() : a(0xf0000018) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -322,10 +491,23 @@ struct P : virtual B1, virtual C0, virtual D1, virtual B2, virtual B3, virtual B
// CHECK: 168 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=192, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct P
// CHECK-X64: 0 | (P vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B1 (virtual base) (empty)
// CHECK-X64: 64 | struct C0 (virtual base)
// CHECK-X64: 64 | int a
// CHECK-X64: 68 | struct D1 (virtual base) (empty)
// CHECK-X64: 104 | struct B2 (virtual base) (empty)
// CHECK-X64: 136 | struct B3 (virtual base) (empty)
// CHECK-X64: 168 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=192, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct Q : virtual B1, virtual C0, virtual B2, virtual D1, virtual B3, virtual B4 {
__declspec(align(32)) int a;
Q() : a(0xf0000019) {printf("X : %3d\n", ((int)this)&0xfff);}
Q() : a(0xf0000019) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -341,10 +523,23 @@ struct Q : virtual B1, virtual C0, virtual B2, virtual D1, virtual B3, virtual B
// CHECK: 168 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=192, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct Q
// CHECK-X64: 0 | (Q vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B1 (virtual base) (empty)
// CHECK-X64: 64 | struct C0 (virtual base)
// CHECK-X64: 64 | int a
// CHECK-X64: 72 | struct B2 (virtual base) (empty)
// CHECK-X64: 100 | struct D1 (virtual base) (empty)
// CHECK-X64: 136 | struct B3 (virtual base) (empty)
// CHECK-X64: 168 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=192, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct R : virtual B0, virtual B1, virtual B2, virtual C0, virtual B3, virtual B4 {
__declspec(align(32)) int a;
R() : a(0xf0000020) {printf("X : %3d\n", ((int)this)&0xfff);}
R() : a(0xf0000020) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -360,10 +555,23 @@ struct R : virtual B0, virtual B1, virtual B2, virtual C0, virtual B3, virtual B
// CHECK: 136 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=160, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct R
// CHECK-X64: 0 | (R vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B0 (virtual base) (empty)
// CHECK-X64: 72 | struct B1 (virtual base) (empty)
// CHECK-X64: 104 | struct B2 (virtual base) (empty)
// CHECK-X64: 104 | struct C0 (virtual base)
// CHECK-X64: 104 | int a
// CHECK-X64: 112 | struct B3 (virtual base) (empty)
// CHECK-X64: 136 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=160, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct S : virtual B0, virtual B1, virtual C0, virtual B2, virtual B3, virtual B4 {
__declspec(align(32)) int a;
S() : a(0xf0000021) {printf("X : %3d\n", ((int)this)&0xfff);}
S() : a(0xf0000021) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -379,10 +587,23 @@ struct S : virtual B0, virtual B1, virtual C0, virtual B2, virtual B3, virtual B
// CHECK: 136 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=160, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct S
// CHECK-X64: 0 | (S vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 64 | struct B0 (virtual base) (empty)
// CHECK-X64: 72 | struct B1 (virtual base) (empty)
// CHECK-X64: 72 | struct C0 (virtual base)
// CHECK-X64: 72 | int a
// CHECK-X64: 80 | struct B2 (virtual base) (empty)
// CHECK-X64: 104 | struct B3 (virtual base) (empty)
// CHECK-X64: 136 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=160, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct T : virtual B0, virtual B1, virtual C0, virtual D2, virtual B2, virtual B3, virtual B4 {
__declspec(align(16)) int a;
T() : a(0xf0000022) {printf("X : %3d\n", ((int)this)&0xfff);}
T() : a(0xf0000022) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -400,10 +621,25 @@ struct T : virtual B0, virtual B1, virtual C0, virtual D2, virtual B2, virtual B
// CHECK: 104 | struct B4 (virtual base) (empty)
// CHECK: | [sizeof=112, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct T
// CHECK-X64: 0 | (T vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | struct B0 (virtual base) (empty)
// CHECK-X64: 40 | struct B1 (virtual base) (empty)
// CHECK-X64: 40 | struct C0 (virtual base)
// CHECK-X64: 40 | int a
// CHECK-X64: 44 | struct D2 (virtual base)
// CHECK-X64: 44 | int [8] a
// CHECK-X64: 80 | struct B2 (virtual base) (empty)
// CHECK-X64: 88 | struct B3 (virtual base) (empty)
// CHECK-X64: 104 | struct B4 (virtual base) (empty)
// CHECK-X64: | [sizeof=112, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct __declspec(align(32)) U : virtual B0, virtual B1 {
int a;
U() : a(0xf0000023) {printf("X : %3d\n", ((int)this)&0xfff);}
U() : a(0xf0000023) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -414,10 +650,18 @@ struct __declspec(align(32)) U : virtual B0, virtual B1 {
// CHECK: 40 | struct B1 (virtual base) (empty)
// CHECK: | [sizeof=64, align=32
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct U
// CHECK-X64: 0 | (U vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: 40 | struct B1 (virtual base) (empty)
// CHECK-X64: | [sizeof=64, align=32
// CHECK-X64: | nvsize=16, nvalign=8]
struct __declspec(align(32)) V : virtual D1 {
int a;
V() : a(0xf0000024) {printf("X : %3d\n", ((int)this)&0xfff);}
V() : a(0xf0000024) {printf("X : %3d\n", ((int)(__SIZE_TYPE__)this)&0xfff);}
};
// CHECK: *** Dumping AST Record Layout
@ -427,6 +671,13 @@ struct __declspec(align(32)) V : virtual D1 {
// CHECK: 8 | struct D1 (virtual base) (empty)
// CHECK: | [sizeof=32, align=32
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct V
// CHECK-X64: 0 | (V vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct D1 (virtual base) (empty)
// CHECK-X64: | [sizeof=32, align=32
// CHECK-X64: | nvsize=16, nvalign=8]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -39,6 +41,16 @@ struct AA : B8, B1, virtual B0 {
// CHECK: 20 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AA
// CHECK-X64: 0 | struct B8 (base)
// CHECK-X64: 0 | char [5] c
// CHECK-X64: 17 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AA vbtable pointer)
// CHECK-X64: 20 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AB : B8, B1, virtual B0 {
short a;
@ -55,6 +67,16 @@ struct AB : B8, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AB
// CHECK-X64: 0 | struct B8 (base)
// CHECK-X64: 0 | char [5] c
// CHECK-X64: 17 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AB vbtable pointer)
// CHECK-X64: 18 | short a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AC : B8, B1, virtual B0 {
char a;
@ -71,6 +93,16 @@ struct AC : B8, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AC
// CHECK-X64: 0 | struct B8 (base)
// CHECK-X64: 0 | char [5] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AC vbtable pointer)
// CHECK-X64: 16 | char a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AD : B8, B1, virtual B0 {
AD() { printf("AD = %p\n", this); }
@ -85,6 +117,15 @@ struct AD : B8, B1, virtual B0 {
// CHECK: 12 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AD
// CHECK-X64: 0 | struct B8 (base)
// CHECK-X64: 0 | char [5] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AD vbtable pointer)
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct AA1 : B9, B1, virtual B0 {
int a;
@ -101,6 +142,16 @@ struct AA1 : B9, B1, virtual B0 {
// CHECK: 20 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AA1
// CHECK-X64: 0 | struct B9 (base)
// CHECK-X64: 0 | char [6] c
// CHECK-X64: 18 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AA1 vbtable pointer)
// CHECK-X64: 20 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AB1 : B9, B1, virtual B0 {
short a;
@ -117,6 +168,16 @@ struct AB1 : B9, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AB1
// CHECK-X64: 0 | struct B9 (base)
// CHECK-X64: 0 | char [6] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AB1 vbtable pointer)
// CHECK-X64: 16 | short a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AC1 : B9, B1, virtual B0 {
char a;
@ -133,6 +194,16 @@ struct AC1 : B9, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AC1
// CHECK-X64: 0 | struct B9 (base)
// CHECK-X64: 0 | char [6] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AC1 vbtable pointer)
// CHECK-X64: 16 | char a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AD1 : B9, B1, virtual B0 {
AD1() { printf("AD1 = %p\n", this); }
@ -147,6 +218,15 @@ struct AD1 : B9, B1, virtual B0 {
// CHECK: 12 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AD1
// CHECK-X64: 0 | struct B9 (base)
// CHECK-X64: 0 | char [6] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AD1 vbtable pointer)
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct AA2 : B10, B1, virtual B0 {
int a;
@ -163,6 +243,16 @@ struct AA2 : B10, B1, virtual B0 {
// CHECK: 20 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AA2
// CHECK-X64: 0 | struct B10 (base)
// CHECK-X64: 0 | char [7] c
// CHECK-X64: 19 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AA2 vbtable pointer)
// CHECK-X64: 20 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AB2 : B10, B1, virtual B0 {
short a;
@ -179,6 +269,16 @@ struct AB2 : B10, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AB2
// CHECK-X64: 0 | struct B10 (base)
// CHECK-X64: 0 | char [7] c
// CHECK-X64: 17 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AB2 vbtable pointer)
// CHECK-X64: 18 | short a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AC2 : B10, B1, virtual B0 {
char a;
@ -195,6 +295,16 @@ struct AC2 : B10, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AC2
// CHECK-X64: 0 | struct B10 (base)
// CHECK-X64: 0 | char [7] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AC2 vbtable pointer)
// CHECK-X64: 16 | char a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AD2 : B10, B1, virtual B0 {
AD2() { printf("AD2 = %p\n", this); }
@ -209,6 +319,15 @@ struct AD2 : B10, B1, virtual B0 {
// CHECK: 12 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AD2
// CHECK-X64: 0 | struct B10 (base)
// CHECK-X64: 0 | char [7] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AD2 vbtable pointer)
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct AA3 : B11, B1, virtual B0 {
int a;
@ -225,6 +344,16 @@ struct AA3 : B11, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AA3
// CHECK-X64: 0 | struct B11 (base)
// CHECK-X64: 0 | char [8] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AA3 vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AB3 : B11, B1, virtual B0 {
short a;
@ -241,6 +370,16 @@ struct AB3 : B11, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AB3
// CHECK-X64: 0 | struct B11 (base)
// CHECK-X64: 0 | char [8] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AB3 vbtable pointer)
// CHECK-X64: 16 | short a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AC3 : B11, B1, virtual B0 {
char a;
@ -257,6 +396,16 @@ struct AC3 : B11, B1, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AC3
// CHECK-X64: 0 | struct B11 (base)
// CHECK-X64: 0 | char [8] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AC3 vbtable pointer)
// CHECK-X64: 16 | char a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct AD3 : B11, B1, virtual B0 {
AD3() { printf("AD3 = %p\n", this); }
@ -271,6 +420,15 @@ struct AD3 : B11, B1, virtual B0 {
// CHECK: 12 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AD3
// CHECK-X64: 0 | struct B11 (base)
// CHECK-X64: 0 | char [8] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (AD3 vbtable pointer)
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct B : B1, B2, virtual B0 {
B() { printf("B = %p\n", this); }
@ -284,6 +442,14 @@ struct B : B1, B2, virtual B0 {
// CHECK: 8 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | struct B1 (base) (empty)
// CHECK-X64: 16 | struct B2 (base) (empty)
// CHECK-X64: 8 | (B vbtable pointer)
// CHECK-X64: 16 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct C : B1, B2, B3, virtual B0 {
char a;
@ -300,6 +466,16 @@ struct C : B1, B2, B3, virtual B0 {
// CHECK: 12 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | struct B1 (base) (empty)
// CHECK-X64: 1 | struct B2 (base) (empty)
// CHECK-X64: 16 | struct B3 (base) (empty)
// CHECK-X64: 8 | (C vbtable pointer)
// CHECK-X64: 16 | char a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct D : B1, B2, B3, B4, B5, virtual B0 {
int a;
@ -318,6 +494,18 @@ struct D : B1, B2, B3, B4, B5, virtual B0 {
// CHECK: 12 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | struct B1 (base) (empty)
// CHECK-X64: 1 | struct B2 (base) (empty)
// CHECK-X64: 2 | struct B3 (base) (empty)
// CHECK-X64: 3 | struct B4 (base) (empty)
// CHECK-X64: 16 | struct B5 (base) (empty)
// CHECK-X64: 8 | (D vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct E : B1, B6, B3, B4, B5, virtual B0 {
int a;
@ -336,6 +524,18 @@ struct E : B1, B6, B3, B4, B5, virtual B0 {
// CHECK: 20 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct E
// CHECK-X64: 0 | struct B1 (base) (empty)
// CHECK-X64: 2 | struct B6 (base) (empty)
// CHECK-X64: 3 | struct B3 (base) (empty)
// CHECK-X64: 4 | struct B4 (base) (empty)
// CHECK-X64: 17 | struct B5 (base) (empty)
// CHECK-X64: 8 | (E vbtable pointer)
// CHECK-X64: 20 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct F : B1, B6, B4, B8, B5, virtual B0 {
int a;
@ -355,6 +555,19 @@ struct F : B1, B6, B4, B8, B5, virtual B0 {
// CHECK: 16 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F
// CHECK-X64: 0 | struct B1 (base) (empty)
// CHECK-X64: 2 | struct B6 (base) (empty)
// CHECK-X64: 3 | struct B4 (base) (empty)
// CHECK-X64: 3 | struct B8 (base)
// CHECK-X64: 3 | char [5] c
// CHECK-X64: 16 | struct B5 (base) (empty)
// CHECK-X64: 8 | (F vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct G : B8, B1, virtual B0 {
int a;
@ -373,6 +586,17 @@ struct G : B8, B1, virtual B0 {
// CHECK: 48 | struct B0 (virtual base) (empty)
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct G
// CHECK-X64: 0 | struct B8 (base)
// CHECK-X64: 0 | char [5] c
// CHECK-X64: 16 | struct B1 (base) (empty)
// CHECK-X64: 8 | (G vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | int a1
// CHECK-X64: 48 | struct B0 (virtual base) (empty)
// CHECK-X64: | [sizeof=48, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct AX : B1X, B2X, B3X, B4X, virtual B0X {
int a;
@ -390,6 +614,17 @@ struct AX : B1X, B2X, B3X, B4X, virtual B0X {
// CHECK: 48 | struct B0X (virtual base) (empty)
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AX
// CHECK-X64: 0 | struct B1X (base) (empty)
// CHECK-X64: 16 | struct B2X (base) (empty)
// CHECK-X64: 18 | struct B3X (base) (empty)
// CHECK-X64: 33 | struct B4X (base) (empty)
// CHECK-X64: 24 | (AX vbtable pointer)
// CHECK-X64: 36 | int a
// CHECK-X64: 48 | struct B0X (virtual base) (empty)
// CHECK-X64: | [sizeof=48, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct BX : B2X, B1X, B3X, B4X, virtual B0X {
int a;
@ -407,6 +642,17 @@ struct BX : B2X, B1X, B3X, B4X, virtual B0X {
// CHECK: 32 | struct B0X (virtual base) (empty)
// CHECK: | [sizeof=32, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct BX
// CHECK-X64: 0 | struct B2X (base) (empty)
// CHECK-X64: 1 | struct B1X (base) (empty)
// CHECK-X64: 2 | struct B3X (base) (empty)
// CHECK-X64: 17 | struct B4X (base) (empty)
// CHECK-X64: 8 | (BX vbtable pointer)
// CHECK-X64: 20 | int a
// CHECK-X64: 32 | struct B0X (virtual base) (empty)
// CHECK-X64: | [sizeof=32, align=16
// CHECK-X64: | nvsize=32, nvalign=16]
struct CX : B1X, B3X, B2X, virtual B0X {
int a;
@ -423,6 +669,16 @@ struct CX : B1X, B3X, B2X, virtual B0X {
// CHECK: 48 | struct B0X (virtual base) (empty)
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct CX
// CHECK-X64: 0 | struct B1X (base) (empty)
// CHECK-X64: 2 | struct B3X (base) (empty)
// CHECK-X64: 32 | struct B2X (base) (empty)
// CHECK-X64: 8 | (CX vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B0X (virtual base) (empty)
// CHECK-X64: | [sizeof=48, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct DX : B8X, B1X, virtual B0X {
int a;
@ -439,6 +695,16 @@ struct DX : B8X, B1X, virtual B0X {
// CHECK: 16 | struct B0X (virtual base) (empty)
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct DX
// CHECK-X64: 0 | struct B8X (base)
// CHECK-X64: 0 | short a
// CHECK-X64: 18 | struct B1X (base) (empty)
// CHECK-X64: 8 | (DX vbtable pointer)
// CHECK-X64: 20 | int a
// CHECK-X64: 24 | struct B0X (virtual base) (empty)
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
int a[
sizeof(AA)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -21,6 +23,14 @@ struct A : virtual B0 {
// CHECK: 8 | int a
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | (A vbtable pointer)
// CHECK-X64: 8 | struct B0 (virtual base)
// CHECK-X64: 8 | (B0 vftable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
struct B : virtual B0 {
virtual void f() { printf("B"); }
@ -34,6 +44,14 @@ struct B : virtual B0 {
// CHECK: 8 | int a
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | (B vbtable pointer)
// CHECK-X64: 8 | struct B0 (virtual base)
// CHECK-X64: 8 | (B0 vftable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
struct C : virtual B0 {
virtual void g() { printf("A"); }
@ -48,6 +66,15 @@ struct C : virtual B0 {
// CHECK: 12 | int a
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | (C vftable pointer)
// CHECK-X64: 8 | (C vbtable pointer)
// CHECK-X64: 16 | struct B0 (virtual base)
// CHECK-X64: 16 | (B0 vftable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: | [sizeof=32, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct D : virtual B2, virtual B0 {
virtual void f() { printf("D"); }
@ -65,6 +92,17 @@ struct D : virtual B2, virtual B0 {
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | (D vftable pointer)
// CHECK-X64: 8 | (D vbtable pointer)
// CHECK-X64: 16 | struct B2 (virtual base)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B0 (virtual base)
// CHECK-X64: 24 | (B0 vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct E : B0, virtual B1 {
virtual void f() { printf("E"); }
@ -82,6 +120,17 @@ struct E : B0, virtual B1 {
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct E
// CHECK-X64: 0 | struct B0 (primary base)
// CHECK-X64: 0 | (B0 vftable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (E vbtable pointer)
// CHECK-X64: 24 | struct B1 (virtual base)
// CHECK-X64: 24 | (B1 vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct F : virtual B0, virtual B1 {
};
@ -97,6 +146,17 @@ struct F : virtual B0, virtual B1 {
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F
// CHECK-X64: 0 | (F vbtable pointer)
// CHECK-X64: 8 | struct B0 (virtual base)
// CHECK-X64: 8 | (B0 vftable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B1 (virtual base)
// CHECK-X64: 24 | (B1 vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
struct AX : B0X, B1X { int a; AX() : a(0xf000000A) {} virtual void f() { printf("A"); } };
@ -110,6 +170,16 @@ struct AX : B0X, B1X { int a; AX() : a(0xf000000A) {} virtual void f() { printf(
// CHECK: 12 | int a
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct AX
// CHECK-X64: 16 | struct B0X (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 0 | struct B1X (primary base)
// CHECK-X64: 0 | (B1X vftable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 20 | int a
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct BX : B0X, B1X { int a; BX() : a(0xf000000B) {} virtual void g() { printf("B"); } };
@ -123,6 +193,16 @@ struct BX : B0X, B1X { int a; BX() : a(0xf000000B) {} virtual void g() { printf(
// CHECK: 12 | int a
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=16, nvalign=4]
// CHECK-x64: *** Dumping AST Record Layout
// CHECK-x64: 0 | struct BX
// CHECK-x64: 16 | struct B0X (base)
// CHECK-x64: 16 | int a
// CHECK-x64: 0 | struct B1X (primary base)
// CHECK-x64: 0 | (B1X vftable pointer)
// CHECK-x64: 8 | int a
// CHECK-x64: 24 | int a
// CHECK-x64: | [sizeof=24, align=8
// CHECK-x64: | nvsize=24, nvalign=8]
struct CX : B0X, B2X { int a; CX() : a(0xf000000C) {} virtual void g() { printf("C"); } };
@ -140,6 +220,20 @@ struct CX : B0X, B2X { int a; CX() : a(0xf000000C) {} virtual void g() { printf(
// CHECK: 24 | int a
// CHECK: | [sizeof=28, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct CX
// CHECK-X64: 0 | (CX vftable pointer)
// CHECK-X64: 8 | struct B0X (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B2X (base)
// CHECK-X64: 16 | (B2X vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 40 | struct B1X (virtual base)
// CHECK-X64: 40 | (B1X vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=56, align=8
// CHECK-X64: | nvsize=40, nvalign=8]
struct DX : virtual B1X { int a; DX() : a(0xf000000D) {} virtual void f() { printf("D"); } };
@ -153,6 +247,16 @@ struct DX : virtual B1X { int a; DX() : a(0xf000000D) {} virtual void f() { prin
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct DX
// CHECK-X64: 0 | (DX vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 20 | (vtordisp for vbase B1X)
// CHECK-X64: 24 | struct B1X (virtual base)
// CHECK-X64: 24 | (B1X vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct EX : virtual B1X { int a; EX() : a(0xf000000E) {} virtual void g() { printf("E"); } };
@ -166,6 +270,16 @@ struct EX : virtual B1X { int a; EX() : a(0xf000000E) {} virtual void g() { prin
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct EX
// CHECK-X64: 0 | (EX vftable pointer)
// CHECK-X64: 8 | (EX vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct B1X (virtual base)
// CHECK-X64: 24 | (B1X vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct FX : virtual B1X { int a; FX() : a(0xf000000F) {} };
@ -178,6 +292,15 @@ struct FX : virtual B1X { int a; FX() : a(0xf000000F) {} };
// CHECK: 12 | int a
// CHECK: | [sizeof=16, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct FX
// CHECK-X64: 0 | (FX vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B1X (virtual base)
// CHECK-X64: 16 | (B1X vftable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: | [sizeof=32, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -15,6 +17,13 @@ struct A : virtual B0 {};
// CHECK: 4 | char a
// CHECK: | [sizeof=5, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | (A vbtable pointer)
// CHECK-X64: 8 | struct B0 (virtual base)
// CHECK-X64: 8 | char a
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
struct __declspec(align(1)) B : virtual B0 {};
@ -25,6 +34,13 @@ struct __declspec(align(1)) B : virtual B0 {};
// CHECK: 4 | char a
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | (B vbtable pointer)
// CHECK-X64: 8 | struct B0 (virtual base)
// CHECK-X64: 8 | char a
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
struct C : virtual B0 { int a; C() : a(0xC) {} };
@ -36,6 +52,14 @@ struct C : virtual B0 { int a; C() : a(0xC) {} };
// CHECK: 8 | char a
// CHECK: | [sizeof=9, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | (C vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base)
// CHECK-X64: 16 | char a
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct D : virtual B0 { __declspec(align(1)) int a; D() : a(0xD) {} };
@ -47,6 +71,14 @@ struct D : virtual B0 { __declspec(align(1)) int a; D() : a(0xD) {} };
// CHECK: 8 | char a
// CHECK: | [sizeof=12, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | (D vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B0 (virtual base)
// CHECK-X64: 16 | char a
// CHECK-X64: | [sizeof=24, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct E : virtual B0, virtual B1 {};
@ -58,6 +90,14 @@ struct E : virtual B0, virtual B1 {};
// CHECK: 5 | struct B1 (virtual base) (empty)
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct E
// CHECK-X64: 0 | (E vbtable pointer)
// CHECK-X64: 8 | struct B0 (virtual base)
// CHECK-X64: 8 | char a
// CHECK-X64: 9 | struct B1 (virtual base) (empty)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
struct F { char a; virtual ~F(); };
@ -67,6 +107,12 @@ struct F { char a; virtual ~F(); };
// CHECK: 4 | char a
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F
// CHECK-X64: 0 | (F vftable pointer)
// CHECK-X64: 8 | char a
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -24,6 +26,17 @@ struct A : B0, virtual B1 { __declspec(align(16)) int a; A() : a(0xf000000A) {}
// CHECK: 64 | char a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | (A vftable pointer)
// CHECK-X64: 8 | struct B0 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (A vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | char a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct B : A, B2 { int a; B() : a(0xf000000B) {} virtual void f() { printf("B"); } };
@ -43,6 +56,22 @@ struct B : A, B2 { int a; B() : a(0xf000000B) {} virtual void f() { printf("B");
// CHECK: 80 | char a
// CHECK: | [sizeof=96, align=16
// CHECK: | nvsize=80, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | struct A (primary base)
// CHECK-X64: 0 | (A vftable pointer)
// CHECK-X64: 8 | struct B0 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (A vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B2 (base)
// CHECK-X64: 48 | (B2 vbtable pointer)
// CHECK-X64: 56 | int a
// CHECK-X64: 64 | int a
// CHECK-X64: 80 | struct B1 (virtual base)
// CHECK-X64: 80 | char a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=80, nvalign=16]
struct C : B4 { int a; C() : a(0xf000000C) {} virtual void f() { printf("C"); } };
@ -57,6 +86,17 @@ struct C : B4 { int a; C() : a(0xf000000C) {} virtual void f() { printf("C"); }
// CHECK: 32 | int a
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | (C vftable pointer)
// CHECK-X64: 16 | struct B4 (base)
// CHECK-X64: 16 | (B4 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B3 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct D : C { int a; D() : a(0xf000000D) {} virtual void f() { printf("D"); } };
@ -73,6 +113,19 @@ struct D : C { int a; D() : a(0xf000000D) {} virtual void f() { printf("D"); } }
// CHECK: 48 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | struct C (primary base)
// CHECK-X64: 0 | (C vftable pointer)
// CHECK-X64: 16 | struct B4 (base)
// CHECK-X64: 16 | (B4 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | int a
// CHECK-X64: 64 | struct B3 (virtual base)
// CHECK-X64: 64 | int a
// CHECK-X64: | [sizeof=80, align=16
// CHECK-X64: | nvsize=64, nvalign=16]
struct E : virtual C { int a; E() : a(0xf000000E) {} virtual void f() { printf("E"); } };
@ -91,6 +144,21 @@ struct E : virtual C { int a; E() : a(0xf000000E) {} virtual void f() { printf("
// CHECK: 72 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct E
// CHECK-X64: 0 | (E vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B3 (virtual base)
// CHECK-X64: 16 | int a
// CHECK-X64: 44 | (vtordisp for vbase C)
// CHECK-X64: 48 | struct C (virtual base)
// CHECK-X64: 48 | (C vftable pointer)
// CHECK-X64: 64 | struct B4 (base)
// CHECK-X64: 64 | (B4 vbtable pointer)
// CHECK-X64: 72 | int a
// CHECK-X64: 80 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=16, nvalign=8]
struct F : B3, virtual B0 { int a; F() : a(0xf000000F) {} virtual void f() { printf("F"); } };
@ -105,6 +173,17 @@ struct F : B3, virtual B0 { int a; F() : a(0xf000000F) {} virtual void f() { pri
// CHECK: 64 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct F
// CHECK-X64: 0 | (F vftable pointer)
// CHECK-X64: 16 | struct B3 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | (F vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 48 | struct B0 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct G : B2, B6, virtual B1 { int a; G() : a(0xf0000010) {} };
@ -121,6 +200,19 @@ struct G : B2, B6, virtual B1 { int a; G() : a(0xf0000010) {} };
// CHECK: 20 | char a
// CHECK: | [sizeof=21, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct G
// CHECK-X64: 16 | struct B2 (base)
// CHECK-X64: 16 | (B2 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 0 | struct B6 (primary base)
// CHECK-X64: 0 | (B6 vftable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 40 | struct B1 (virtual base)
// CHECK-X64: 40 | char a
// CHECK-X64: | [sizeof=48, align=8
// CHECK-X64: | nvsize=40, nvalign=8]
struct H : B6, B2, virtual B1 { int a; H() : a(0xf0000011) {} };
@ -137,6 +229,19 @@ struct H : B6, B2, virtual B1 { int a; H() : a(0xf0000011) {} };
// CHECK: 20 | char a
// CHECK: | [sizeof=21, align=4
// CHECK: | nvsize=20, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct H
// CHECK-X64: 0 | struct B6 (primary base)
// CHECK-X64: 0 | (B6 vftable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | struct B2 (base)
// CHECK-X64: 16 | (B2 vbtable pointer)
// CHECK-X64: 24 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 40 | struct B1 (virtual base)
// CHECK-X64: 40 | char a
// CHECK-X64: | [sizeof=48, align=8
// CHECK-X64: | nvsize=40, nvalign=8]
struct I : B0, virtual B1 { int a; int a1; __declspec(align(16)) int a2; I() : a(0xf0000011), a1(0xf0000011), a2(0xf0000011) {} };
@ -152,6 +257,18 @@ struct I : B0, virtual B1 { int a; int a1; __declspec(align(16)) int a2; I() : a
// CHECK: 48 | char a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct I
// CHECK-X64: 0 | struct B0 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 8 | (I vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 20 | int a1
// CHECK-X64: 32 | int a2
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | char a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct J : B0, B3, virtual B1 { int a; int a1; J() : a(0xf0000012), a1(0xf0000012) {} };
@ -168,6 +285,19 @@ struct J : B0, B3, virtual B1 { int a; int a1; J() : a(0xf0000012), a1(0xf000001
// CHECK: 64 | char a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct J
// CHECK-X64: 0 | struct B0 (base)
// CHECK-X64: 0 | int a
// CHECK-X64: 16 | struct B3 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | (J vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 44 | int a1
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | char a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct K { int a; K() : a(0xf0000013) {} virtual void f() { printf("K"); } };
@ -177,6 +307,12 @@ struct K { int a; K() : a(0xf0000013) {} virtual void f() { printf("K"); } };
// CHECK: 4 | int a
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct K
// CHECK-X64: 0 | (K vftable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
struct L : virtual K { int a; L() : a(0xf0000014) {} virtual void g() { printf("L"); } };
@ -190,6 +326,16 @@ struct L : virtual K { int a; L() : a(0xf0000014) {} virtual void g() { printf("
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct L
// CHECK-X64: 0 | (L vftable pointer)
// CHECK-X64: 8 | (L vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 24 | struct K (virtual base)
// CHECK-X64: 24 | (K vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=24, nvalign=8]
struct M : virtual K { int a; M() : a(0xf0000015) {} virtual void f() { printf("M"); } };
@ -203,6 +349,16 @@ struct M : virtual K { int a; M() : a(0xf0000015) {} virtual void f() { printf("
// CHECK: 16 | int a
// CHECK: | [sizeof=20, align=4
// CHECK: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct M
// CHECK-X64: 0 | (M vbtable pointer)
// CHECK-X64: 8 | int a
// CHECK-X64: 20 | (vtordisp for vbase K)
// CHECK-X64: 24 | struct K (virtual base)
// CHECK-X64: 24 | (K vftable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: | [sizeof=40, align=8
// CHECK-X64: | nvsize=16, nvalign=8]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -26,6 +28,17 @@ struct A : B0, virtual B1 {
// CHECK: 64 | int a
// CHECK: | [sizeof=80, align=16
// CHECK: | nvsize=64, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | (A vftable pointer)
// CHECK-X64: 8 | struct B0 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (A vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct B : B2, B0, virtual B1 {
__declspec(align(16)) int a;
@ -45,6 +58,18 @@ struct B : B2, B0, virtual B1 {
// CHECK: 48 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct B
// CHECK-X64: 0 | struct B2 (primary base)
// CHECK-X64: 0 | (B2 vftable pointer)
// CHECK-X64: 8 | struct B0 (base)
// CHECK-X64: 8 | int a
// CHECK-X64: 16 | (B vbtable pointer)
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct C : B3, B0, virtual B1 {
__declspec(align(16)) int a;
@ -64,6 +89,18 @@ struct C : B3, B0, virtual B1 {
// CHECK: 48 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=48, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | (C vftable pointer)
// CHECK-X64: 8 | struct B3 (base)
// CHECK-X64: 8 | (B3 vbtable pointer)
// CHECK-X64: 16 | struct B0 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
struct D : B4, B0, virtual B1 {
__declspec(align(16)) int a;
@ -83,6 +120,18 @@ struct D : B4, B0, virtual B1 {
// CHECK: 32 | int a
// CHECK: | [sizeof=48, align=16
// CHECK: | nvsize=32, nvalign=16]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | struct B4 (primary base)
// CHECK-X64: 0 | (B4 vftable pointer)
// CHECK-X64: 8 | (B4 vbtable pointer)
// CHECK-X64: 16 | struct B0 (base)
// CHECK-X64: 16 | int a
// CHECK-X64: 32 | int a
// CHECK-X64: 48 | struct B1 (virtual base)
// CHECK-X64: 48 | int a
// CHECK-X64: | [sizeof=64, align=16
// CHECK-X64: | nvsize=48, nvalign=16]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>&1 \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only -cxx-abi microsoft %s 2>/dev/null \
// RUN: | FileCheck %s -check-prefix CHECK-X64
extern "C" int printf(const char *fmt, ...);
@ -42,6 +44,21 @@ struct A : virtual B0, virtual B1 {
// CHECK: 52 | int a
// CHECK: | [sizeof=64, align=16
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct A
// CHECK-X64: 0 | (A vftable pointer)
// CHECK-X64: 8 | (A vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 36 | (vtordisp for vbase B0)
// CHECK-X64: 40 | struct B0 (virtual base)
// CHECK-X64: 40 | (B0 vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: 76 | (vtordisp for vbase B1)
// CHECK-X64: 80 | struct B1 (virtual base)
// CHECK-X64: 80 | (B1 vftable pointer)
// CHECK-X64: 88 | int a
// CHECK-X64: | [sizeof=96, align=16
// CHECK-X64: | nvsize=24, nvalign=8]
struct C : virtual B0, virtual B1, VAlign32 {
int a;
@ -67,6 +84,23 @@ struct C : virtual B0, virtual B1, VAlign32 {
// CHECK: 128 | struct Align32 (virtual base) (empty)
// CHECK: | [sizeof=128, align=32
// CHECK: | nvsize=64, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct C
// CHECK-X64: 0 | (C vftable pointer)
// CHECK-X64: 32 | struct VAlign32 (base)
// CHECK-X64: 32 | (VAlign32 vbtable pointer)
// CHECK-X64: 40 | int a
// CHECK-X64: 68 | (vtordisp for vbase B0)
// CHECK-X64: 72 | struct B0 (virtual base)
// CHECK-X64: 72 | (B0 vftable pointer)
// CHECK-X64: 80 | int a
// CHECK-X64: 108 | (vtordisp for vbase B1)
// CHECK-X64: 112 | struct B1 (virtual base)
// CHECK-X64: 112 | (B1 vftable pointer)
// CHECK-X64: 120 | int a
// CHECK-X64: 128 | struct Align32 (virtual base) (empty)
// CHECK-X64: | [sizeof=128, align=32
// CHECK-X64: | nvsize=64, nvalign=32]
struct __declspec(align(32)) D : virtual B0, virtual B1 {
int a;
@ -90,22 +124,44 @@ struct __declspec(align(32)) D : virtual B0, virtual B1 {
// CHECK: 84 | int a
// CHECK: | [sizeof=96, align=32
// CHECK: | nvsize=12, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct D
// CHECK-X64: 0 | (D vftable pointer)
// CHECK-X64: 8 | (D vbtable pointer)
// CHECK-X64: 16 | int a
// CHECK-X64: 36 | (vtordisp for vbase B0)
// CHECK-X64: 40 | struct B0 (virtual base)
// CHECK-X64: 40 | (B0 vftable pointer)
// CHECK-X64: 48 | int a
// CHECK-X64: 76 | (vtordisp for vbase B1)
// CHECK-X64: 80 | struct B1 (virtual base)
// CHECK-X64: 80 | (B1 vftable pointer)
// CHECK-X64: 88 | int a
// CHECK-X64: | [sizeof=96, align=32
// CHECK-X64: | nvsize=24, nvalign=8]
struct AT {
virtual ~AT(){}
};
struct CT : virtual AT {
virtual ~CT();
};
struct AT {
virtual ~AT(){}
};
struct CT : virtual AT {
virtual ~CT();
};
CT::~CT(){}
// CHECK: *** Dumping AST Record Layout
// CHECK: 0 | struct CT
// CHECK: 0 | (CT vbtable pointer)
// CHECK: 4 | struct AT (virtual base)
// CHECK: 4 | (AT vftable pointer)
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK: *** Dumping AST Record Layout
// CHECK: 0 | struct CT
// CHECK: 0 | (CT vbtable pointer)
// CHECK: 4 | struct AT (virtual base)
// CHECK: 4 | (AT vftable pointer)
// CHECK: | [sizeof=8, align=4
// CHECK: | nvsize=4, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: 0 | struct CT
// CHECK-X64: 0 | (CT vbtable pointer)
// CHECK-X64: 8 | struct AT (virtual base)
// CHECK-X64: 8 | (AT vftable pointer)
// CHECK-X64: | [sizeof=16, align=8
// CHECK-X64: | nvsize=8, nvalign=8]
int a[
sizeof(A)+

View File

@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -cxx-abi microsoft -fdump-record-layouts %s 2>/dev/null \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -cxx-abi microsoft -fdump-record-layouts %s 2>/dev/null \
// RUN: | FileCheck %s
typedef struct A {
char x;