From: Warren Hunt Date: Thu, 9 Jan 2014 00:30:56 +0000 (+0000) Subject: [ms-abi] Refactor Microsoft Record Layout X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d640d7d96e93f138e1aa844d91c868485a6b113d;p=platform%2Fupstream%2Fllvm.git [ms-abi] Refactor Microsoft Record Layout This patch refactors microsoft record layout to be more "natural". The most dominant change is that vbptrs and vfptrs are injected after the fact. This simplifies the implementation and the math for the offest for the first base/field after the vbptr. llvm-svn: 198818 --- diff --git a/clang/include/clang/AST/CharUnits.h b/clang/include/clang/AST/CharUnits.h index 09ff682..69dee4c 100644 --- a/clang/include/clang/AST/CharUnits.h +++ b/clang/include/clang/AST/CharUnits.h @@ -165,7 +165,7 @@ namespace clang { /// RoundUpToAlignment - Returns the next integer (mod 2**64) that is /// greater than or equal to this quantity and is a multiple of \p Align. /// Align must be non-zero. - CharUnits RoundUpToAlignment(const CharUnits &Align) { + CharUnits RoundUpToAlignment(const CharUnits &Align) const { return CharUnits(llvm::RoundUpToAlignment(Quantity, Align.Quantity)); } diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h index ca10718..4befb45 100644 --- a/clang/include/clang/AST/RecordLayout.h +++ b/clang/include/clang/AST/RecordLayout.h @@ -82,9 +82,9 @@ private: /// the size of the object without virtual bases. CharUnits NonVirtualSize; - /// NonVirtualAlign - The non-virtual alignment (in chars) of an object, + /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object, /// which is the alignment of the object without virtual bases. - CharUnits NonVirtualAlign; + CharUnits NonVirtualAlignment; /// SizeOfLargestEmptySubobject - The size of the largest empty subobject /// (either a base or a member). Will be zero if the class doesn't contain @@ -104,8 +104,9 @@ private: /// a primary base class. bool HasExtendableVFPtr : 1; - /// HasZeroSizedSubObject - True if this class contains a zero sized member or base or a base - /// with a zero sized member or base. Only used for MS-ABI. + /// HasZeroSizedSubObject - True if this class contains a zero sized member + /// or base or a base with a zero sized member or base. Only used for + /// MS-ABI. bool HasZeroSizedSubObject : 1; /// \brief True if this class is zero sized or first base is zero sized or @@ -148,7 +149,7 @@ private: CharUnits vbptroffset, CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, - CharUnits nonvirtualsize, CharUnits nonvirtualalign, + CharUnits nonvirtualsize, CharUnits nonvirtualalignment, CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual, @@ -198,10 +199,10 @@ public: /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object, /// which is the alignment of the object without virtual bases. - CharUnits getNonVirtualAlign() const { + CharUnits getNonVirtualAlignment() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); - return CXXInfo->NonVirtualAlign; + return CXXInfo->NonVirtualAlignment; } /// getPrimaryBase - Get the primary base for this record. diff --git a/clang/lib/AST/RecordLayout.cpp b/clang/lib/AST/RecordLayout.cpp index d72d5dc..9d46cc6 100644 --- a/clang/lib/AST/RecordLayout.cpp +++ b/clang/lib/AST/RecordLayout.cpp @@ -53,7 +53,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, const uint64_t *fieldoffsets, unsigned fieldcount, CharUnits nonvirtualsize, - CharUnits nonvirtualalign, + CharUnits nonvirtualalignment, CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual, @@ -74,7 +74,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CXXInfo->PrimaryBase.setPointer(PrimaryBase); CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual); CXXInfo->NonVirtualSize = nonvirtualsize; - CXXInfo->NonVirtualAlign = nonvirtualalign; + CXXInfo->NonVirtualAlignment = nonvirtualalignment; CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject; CXXInfo->BaseOffsets = BaseOffsets; CXXInfo->VBaseOffsets = VBaseOffsets; diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 832bfef..5191cb2 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -1189,7 +1189,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { } } - CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign(); + CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment(); CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; // If we have an empty base class, try to place it at offset 0. @@ -2026,10 +2026,16 @@ static bool isMsLayout(const RecordDecl* D) { // added for bases is 1 byte. The padding added for vbases depends on the // alignment of the object but is at least 4 bytes (in both 32 and 64 bit // modes). +// * There is no concept of non-virtual alignment or any distinction between +// data size and non-virtual size. namespace { struct MicrosoftRecordLayoutBuilder { + struct ElementInfo { + CharUnits Size; + CharUnits Alignment; + }; typedef llvm::DenseMap BaseOffsetsMapTy; MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {} private: @@ -2037,7 +2043,6 @@ private: LLVM_DELETED_FUNCTION; void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION; public: - void layout(const RecordDecl *RD); void cxxLayout(const CXXRecordDecl *RD); /// \brief Initializes size and alignment and honors some flags. @@ -2046,10 +2051,13 @@ public: /// existence of vfptrs and vbptrs. Alignment is needed before the vfptr is /// laid out. void initializeCXXLayout(const CXXRecordDecl *RD); - void layoutVFPtr(const CXXRecordDecl *RD); void layoutNonVirtualBases(const CXXRecordDecl *RD); - void layoutNonVirtualBase(const CXXRecordDecl *RD); - void layoutVBPtr(const CXXRecordDecl *RD); + void layoutNonVirtualBase(const CXXRecordDecl *BaseDecl, + const ASTRecordLayout &BaseLayout, + const ASTRecordLayout *&PreviousBaseLayout); + void injectVFPtr(const CXXRecordDecl *RD); + void injectVBPtr(const CXXRecordDecl *RD); + void injectVPtrs(const CXXRecordDecl *RD); /// \brief Lays out the fields of the record. Also rounds size up to /// alignment. void layoutFields(const RecordDecl *RD); @@ -2058,22 +2066,19 @@ public: /// \brief Lays out a single zero-width bit-field in the record and handles /// special cases associated with zero-width bit-fields. void layoutZeroWidthBitField(const FieldDecl *FD); - void fixSizeAndAlignment(const RecordDecl *FD); void layoutVirtualBases(const CXXRecordDecl *RD); - void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp); void finalizeLayout(const RecordDecl *RD); - - /// \brief Updates the alignment of the type. This function doesn't take any - /// properties (such as packedness) into account. getAdjustedFieldInfo() - /// adjustes for packedness. - void updateAlignment(CharUnits NewAlignment) { - Alignment = std::max(Alignment, NewAlignment); - } - CharUnits getBaseAlignment(const ASTRecordLayout& Layout); - /// \brief Gets the size and alignment taking attributes into account. - std::pair getAdjustedFieldInfo(const FieldDecl *FD); - /// \brief Places a field at offset 0. - void placeFieldAtZero() { FieldOffsets.push_back(0); } + /// \brief Gets the size and alignment of a base taking pragma pack and + /// __declspec(align) into account. + ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout); + /// \brief Gets the size and alignment of a field taking pragma pack and + /// __declspec(align) into account. It also updates RequiredAlignment as a + /// side effect because it is most convenient to do so here. + ElementInfo getAdjustedElementInfo(const FieldDecl *FD); + /// \brief Updates the alignment of the record. + void updateAlignment(CharUnits MemberAlignment) { + Alignment = std::max(Alignment, MemberAlignment); + } /// \brief Places a field at an offset in CharUnits. void placeFieldAtOffset(CharUnits FieldOffset) { FieldOffsets.push_back(Context.toBits(FieldOffset)); @@ -2085,66 +2090,48 @@ public: /// \brief Compute the set of virtual bases for which vtordisps are required. llvm::SmallPtrSet computeVtorDispSet(const CXXRecordDecl *RD); - const ASTContext &Context; /// \brief The size of the record being laid out. CharUnits Size; + /// \brief The data alignment of the record layout. + CharUnits DataSize; /// \brief The current alignment of the record layout. CharUnits Alignment; - /// \brief The collection of field offsets. - SmallVector FieldOffsets; /// \brief The maximum allowed field alignment. This is set by #pragma pack. CharUnits MaxFieldAlignment; /// \brief The alignment that this record must obey. This is imposed by /// __declspec(align()) on the record itself or one of its fields or bases. CharUnits RequiredAlignment; - bool IsUnion : 1; - /// \brief True if the last field laid out was a bitfield and was not 0 - /// width. - bool LastFieldIsNonZeroWidthBitfield : 1; /// \brief The size of the allocation of the currently active bitfield. /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield /// is true. CharUnits CurrentBitfieldSize; - /// \brief The number of remaining bits in our last bitfield allocation. - /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is - /// true. - unsigned RemainingBitsInField; - - /// \brief The data alignment of the record layout. - CharUnits DataSize; - /// \brief The alignment of the non-virtual portion of the record layout - /// 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 Offset to the virtual base table pointer (if one exists). + CharUnits VBPtrOffset; + /// \brief The size and alignment info of a pointer. + ElementInfo PointerInfo; /// \brief The primary base class (if one exists). const CXXRecordDecl *PrimaryBase; /// \brief The class we share our vb-pointer with. const CXXRecordDecl *SharedVBPtrBase; - /// \brief True if the class has a vftable pointer that can be extended - /// by this class or classes derived from it. Such a vfptr will always occur - /// at offset 0. - bool HasExtendableVFPtr : 1; - /// \brief True if the class has a (not necessarily its own) vbtable pointer. - bool HasVBPtr : 1; - /// \brief Offset to the virtual base table pointer (if one exists). - CharUnits VBPtrOffset; + /// \brief The collection of field offsets. + SmallVector FieldOffsets; /// \brief Base classes and their offsets in the record. BaseOffsetsMapTy Bases; /// \brief virtual base classes and their offsets in the record. ASTRecordLayout::VBaseOffsetsMapTy VBases; - /// \brief The size of a pointer. - CharUnits PointerSize; - /// \brief The alignment of a pointer. - CharUnits PointerAlignment; - /// \brief Holds an empty base we haven't yet laid out. - const CXXRecordDecl *LazyEmptyBase; - /// \brief A pointer to the Layout for the most recent non-virtual base that - /// has been laid out. - const ASTRecordLayout *PreviousBaseLayout; + /// \brief The number of remaining bits in our last bitfield allocation. + /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is + /// true. + unsigned RemainingBitsInField; + bool IsUnion : 1; + /// \brief True if the last field laid out was a bitfield and was not 0 + /// width. + bool LastFieldIsNonZeroWidthBitfield : 1; + /// \brief True if the class has its own vftable pointer. + bool HasOwnVFPtr : 1; + /// \brief True if the class has a vbtable pointer. + bool HasVBPtr : 1; /// \brief Lets us know if we're in 64-bit mode bool Is64BitMode : 1; /// \brief True if this class contains a zero sized member or base or a base @@ -2156,61 +2143,92 @@ public: }; } // namespace -CharUnits -MicrosoftRecordLayoutBuilder::getBaseAlignment(const ASTRecordLayout& Layout) { - CharUnits BaseAlignment = Layout.getAlignment(); +MicrosoftRecordLayoutBuilder::ElementInfo +MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( + const ASTRecordLayout &Layout) { + ElementInfo Info; + Info.Alignment = Layout.getAlignment(); + // Respect pragma pack. if (!MaxFieldAlignment.isZero()) - BaseAlignment = std::min(BaseAlignment, - std::max(MaxFieldAlignment, - Layout.getRequiredAlignment())); - return BaseAlignment; + Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); + // Track zero-sized subobjects here where it's already available. + if (Layout.hasZeroSizedSubObject()) + HasZeroSizedSubObject = true; + // Respect required alignment, this is necessary because we may have adjusted + // the alignment in the case of pragam pack. + Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment()); + Info.Size = Layout.getNonVirtualSize(); + return Info; } -std::pair -MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) { - std::pair FieldInfo = - Context.getTypeInfoInChars(FD->getType()); - - // Respect packed attribute. - if (FD->hasAttr()) - FieldInfo.second = CharUnits::One(); - // Respect pack pragma. - else if (!MaxFieldAlignment.isZero()) - FieldInfo.second = std::min(FieldInfo.second, MaxFieldAlignment); - // Respect alignment attributes. - if (unsigned fieldAlign = FD->getMaxAlignment()) { - CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign); - RequiredAlignment = std::max(RequiredAlignment, FieldAlign); - FieldInfo.second = std::max(FieldInfo.second, FieldAlign); - } +MicrosoftRecordLayoutBuilder::ElementInfo +MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( + const FieldDecl *FD) { + ElementInfo Info; // Respect attributes applied to subobjects of the field. if (const RecordType *RT = FD->getType()->getBaseElementTypeUnsafe()->getAs()) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RT->getDecl()); + // Get the element info for a layout, respecting pack. + Info = getAdjustedElementInfo(Layout); + // Nomally getAdjustedElementInfo returns the non-virtual size, which is + // correct for bases but not for fields. + Info.Size = Layout.getSize(); + // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, Layout.getRequiredAlignment()); - FieldInfo.second = std::max(FieldInfo.second, - Layout.getRequiredAlignment()); - // Track zero-sized subobjects here where it's already available. - if (Layout.hasZeroSizedSubObject()) - HasZeroSizedSubObject = true; } - return FieldInfo; + else { + std::pair FieldInfo = + Context.getTypeInfoInChars(FD->getType()); + Info.Size = FieldInfo.first; + Info.Alignment = FieldInfo.second; + // Respect pragma pack. + if (!MaxFieldAlignment.isZero()) + Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); + } + // Respect packed field attribute. + if (FD->hasAttr()) + Info.Alignment = CharUnits::One(); + // Respect align attributes. + CharUnits FieldRequiredAlignment = + Context.toCharUnitsFromBits(FD->getMaxAlignment()); + // Take required alignment into account. + Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment); + // Capture required alignment as a side-effect. + RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment); + return Info; +} + +void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) { + initializeLayout(RD); + layoutFields(RD); + DataSize = Size = Size.RoundUpToAlignment(Alignment); + finalizeLayout(RD); +} + +void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) { + initializeLayout(RD); + initializeCXXLayout(RD); + layoutNonVirtualBases(RD); + layoutFields(RD); + injectVPtrs(RD); + DataSize = Size = Size.RoundUpToAlignment(Alignment); + layoutVirtualBases(RD); + finalizeLayout(RD); } void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { IsUnion = RD->isUnion(); Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64; - Size = CharUnits::Zero(); Alignment = CharUnits::One(); - // In 64-bit mode we always perform an alignment step after laying out vbases. // In 32-bit mode we do not. The check to see if we need to perform alignment // checks the RequiredAlignment field and performs alignment if it isn't 0. RequiredAlignment = Is64BitMode ? CharUnits::One() : CharUnits::Zero(); - HasZeroSizedSubObject = false; - + RequiredAlignment = std::max(RequiredAlignment, + Context.toCharUnitsFromBits(RD->getMaxAlignment())); // Compute the maximum field alignment. MaxFieldAlignment = CharUnits::Zero(); // Honor the default struct packing maximum alignment flag. @@ -2224,118 +2242,70 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { MaxFieldAlignment = CharUnits::One(); } -void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) { - initializeLayout(RD); - layoutFields(RD); - fixSizeAndAlignment(RD); - finalizeLayout(RD); -} - -void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) { - initializeLayout(RD); - initializeCXXLayout(RD); - layoutVFPtr(RD); - layoutNonVirtualBases(RD); - layoutVBPtr(RD); - layoutFields(RD); - fixSizeAndAlignment(RD); - layoutVirtualBases(RD); - finalizeLayout(RD); -} - void MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { - // Calculate pointer size and alignment. - PointerSize = - Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); - PointerAlignment = PointerSize; - if (!MaxFieldAlignment.isZero()) - PointerAlignment = std::min(PointerAlignment, MaxFieldAlignment); - - // Initialize information about the bases. + HasZeroSizedSubObject = false; + LeadsWithZeroSizedBase = false; + HasOwnVFPtr = false; HasVBPtr = false; - HasExtendableVFPtr = false; - SharedVBPtrBase = 0; PrimaryBase = 0; - LeadsWithZeroSizedBase = false; + SharedVBPtrBase = 0; + // Calculate pointer size and alignment. These are used for vfptr and vbprt + // injection. + PointerInfo.Size = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + PointerInfo.Alignment = PointerInfo.Size; + // Respect pragma pack. + if (!MaxFieldAlignment.isZero()) + PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment); +} - // 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 - // base class, if one exists. +void +MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { + // The MS-ABI lays out all bases that contain leading vfptrs before it lays + // out any bases that do not contain vfptrs. We implement this as two passes + // over the bases. This approach guarantees that the primary base is laid out + // first. We use these passes to calculate some additional aggregated + // information about the bases, such as reqruied alignment and the presence of + // zero sized members. + const ASTRecordLayout* PreviousBaseLayout = 0; + // Iterate through the bases and lay out the non-virtual ones. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *BaseDecl = - cast(i->getType()->getAs()->getDecl()); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); - // Handle required alignment. + const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl(); + const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl); + // Track RequiredAlignment for all bases in this pass. RequiredAlignment = std::max(RequiredAlignment, - Layout.getRequiredAlignment()); - // Check for zero sized subobjects. - if (Layout.hasZeroSizedSubObject()) - HasZeroSizedSubObject = true; - // Handle virtual bases. + BaseLayout.getRequiredAlignment()); + // Mark and skip virtual bases. if (i->isVirtual()) { HasVBPtr = true; continue; } - // We located a primary base class! - if (!PrimaryBase && Layout.hasExtendableVFPtr()) { - PrimaryBase = BaseDecl; - HasExtendableVFPtr = true; - } - // We located a base to share a VBPtr with! - if (!SharedVBPtrBase && Layout.hasVBPtr()) { + // Check fo a base to share a VBPtr with. + if (!SharedVBPtrBase && BaseLayout.hasVBPtr()) { SharedVBPtrBase = BaseDecl; HasVBPtr = true; } - updateAlignment(getBaseAlignment(Layout)); + // Only lay out bases with extendable VFPtrs on the first pass. + if (!BaseLayout.hasExtendableVFPtr()) + continue; + // If we don't have a primary base, this one qualifies. + if (!PrimaryBase) + PrimaryBase = BaseDecl; + // Lay out the base. + layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout); } - - // Use LayoutFields to compute the alignment of the fields. The layout - // is discarded. This is the simplest way to get all of the bit-field - // behavior correct and is not actually very expensive. - layoutFields(RD); - Size = CharUnits::Zero(); - BasesAndFieldsAlignment = Alignment; - FieldOffsets.clear(); -} - -void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) { - // If we have a primary base then our VFPtr was already laid out - if (PrimaryBase) - return; - - // Look at all of our methods to determine if we need a VFPtr. We need a - // vfptr if we define a new virtual function. - if (!HasExtendableVFPtr && RD->isDynamicClass()) + // Figure out if we need a fresh VFPtr for this class. + if (!PrimaryBase && RD->isDynamicClass()) for (CXXRecordDecl::method_iterator i = RD->method_begin(), e = RD->method_end(); - !HasExtendableVFPtr && i != e; ++i) - HasExtendableVFPtr = i->isVirtual() && i->size_overridden_methods() == 0; - if (!HasExtendableVFPtr) - return; - - updateAlignment(PointerAlignment); - Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize; - // 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. - if (!Is64BitMode && Alignment > PointerSize) - Size += Alignment - PointerSize; -} - -void -MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { - LazyEmptyBase = 0; - PreviousBaseLayout = 0; - - // Lay out the primary base first. - if (PrimaryBase) - layoutNonVirtualBase(PrimaryBase); - - const CXXRecordDecl *LeadingBase = PrimaryBase; + !HasOwnVFPtr && i != e; ++i) + HasOwnVFPtr = i->isVirtual() && i->size_overridden_methods() == 0; + // If we don't have a primary base then we have a leading object that could + // itself lead with a zero-sized object, something we track. + bool CheckLeadingLayout = !PrimaryBase; // Iterate through the bases and lay out the non-virtual ones. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); @@ -2343,71 +2313,41 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { if (i->isVirtual()) continue; const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl(); - if (BaseDecl == PrimaryBase) + const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl); + // Only lay out bases without extendable VFPtrs on the second pass. + if (BaseLayout.hasExtendableVFPtr()) continue; - const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); - if (!LeadingBase) { - LeadsWithZeroSizedBase = Layout.leadsWithZeroSizedBase(); - LeadingBase = BaseDecl; - } - - if (LazyEmptyBase) { - layoutNonVirtualBase(LazyEmptyBase); - LazyEmptyBase = 0; + // If this is the first layout, check to see if it leads with a zero sized + // object. If it does, so do we. + if (CheckLeadingLayout) { + CheckLeadingLayout = false; + LeadsWithZeroSizedBase = BaseLayout.leadsWithZeroSizedBase(); } - // Insert padding between two bases if the left first one is zero sized or - // contains a zero sized subobject and the right is zero sized or one leads - // with a zero sized base. - if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() && - Layout.leadsWithZeroSizedBase()) - Size++; - if (Layout.getNonVirtualSize().isZero()) - LazyEmptyBase = BaseDecl; - else - layoutNonVirtualBase(BaseDecl); + // Lay out the base. + layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout); } -} - -void -MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - // Insert the base here. - CharUnits BaseOffset = Size.RoundUpToAlignment(getBaseAlignment(Layout)); - Bases.insert(std::make_pair(RD, BaseOffset)); - Size = BaseOffset + Layout.getDataSize(); - // Alignment was upadated in InitializeCXXLayout. - PreviousBaseLayout = &Layout; -} - -void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) { + // Set our VBPtroffset if we know it at this point. if (!HasVBPtr) VBPtrOffset = CharUnits::fromQuantity(-1); - else if (SharedVBPtrBase) - VBPtrOffset = Bases[SharedVBPtrBase] + - Context.getASTRecordLayout(SharedVBPtrBase).getVBPtrOffset(); - else { - VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment); - 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 = OldSize + BasesAndFieldsAlignment; - else if (PreviousBaseLayout && - PreviousBaseLayout->getNonVirtualSize().isZero()) - Size += CharUnits::One(); - } - updateAlignment(PointerAlignment); - } - if (LazyEmptyBase) - layoutNonVirtualBase(LazyEmptyBase); +} + +void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase( + const CXXRecordDecl *BaseDecl, + const ASTRecordLayout &BaseLayout, + const ASTRecordLayout *&PreviousBaseLayout) { + // Insert padding between two bases if the left first one is zero sized or + // contains a zero sized subobject and the right is zero sized or one leads + // with a zero sized base. + if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() && + BaseLayout.leadsWithZeroSizedBase()) + Size++; + ElementInfo Info = getAdjustedElementInfo(BaseLayout); + CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment); + Bases.insert(std::make_pair(BaseDecl, BaseOffset)); + Size = BaseOffset + BaseLayout.getDataSize(); + updateAlignment(Info.Alignment); + PreviousBaseLayout = &BaseLayout; + VBPtrOffset = Size; } void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) { @@ -2416,7 +2356,6 @@ void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) { FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) layoutField(*Field); - Size = Size.RoundUpToAlignment(Alignment); } void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { @@ -2425,21 +2364,16 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { return; } LastFieldIsNonZeroWidthBitfield = false; - - std::pair FieldInfo = getAdjustedFieldInfo(FD); - CharUnits FieldSize = FieldInfo.first; - CharUnits FieldAlign = FieldInfo.second; - - updateAlignment(FieldAlign); + ElementInfo Info = getAdjustedElementInfo(FD); if (IsUnion) { - placeFieldAtZero(); - Size = std::max(Size, FieldSize); + placeFieldAtOffset(CharUnits::Zero()); + Size = std::max(Size, Info.Size); } else { - // Round up the current record size to the field's alignment boundary. - CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign); + CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment); placeFieldAtOffset(FieldOffset); - Size = FieldOffset + FieldSize; + Size = FieldOffset + Info.Size; } + updateAlignment(Info.Alignment); } void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { @@ -2448,39 +2382,33 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { layoutZeroWidthBitField(FD); return; } - - std::pair FieldInfo = getAdjustedFieldInfo(FD); - CharUnits FieldSize = FieldInfo.first; - CharUnits FieldAlign = FieldInfo.second; - + ElementInfo Info = getAdjustedElementInfo(FD); // Clamp the bitfield to a containable size for the sake of being able // to lay them out. Sema will throw an error. - if (Width > Context.toBits(FieldSize)) - Width = Context.toBits(FieldSize); - + if (Width > Context.toBits(Info.Size)) + Width = Context.toBits(Info.Size); // Check to see if this bitfield fits into an existing allocation. Note: // MSVC refuses to pack bitfields of formal types with different sizes // into the same allocation. if (!IsUnion && LastFieldIsNonZeroWidthBitfield && - CurrentBitfieldSize == FieldSize && Width <= RemainingBitsInField) { + CurrentBitfieldSize == Info.Size && Width <= RemainingBitsInField) { placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField); RemainingBitsInField -= Width; return; } - LastFieldIsNonZeroWidthBitfield = true; - CurrentBitfieldSize = FieldSize; + CurrentBitfieldSize = Info.Size; if (IsUnion) { - placeFieldAtZero(); - Size = std::max(Size, FieldSize); + placeFieldAtOffset(CharUnits::Zero()); + Size = std::max(Size, Info.Size); // TODO: Add a Sema warning that MS ignores bitfield alignment in unions. } else { // Allocate a new block of memory and place the bitfield in it. - CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign); + CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment); placeFieldAtOffset(FieldOffset); - Size = FieldOffset + FieldSize; - updateAlignment(FieldAlign); - RemainingBitsInField = Context.toBits(FieldSize) - Width; + Size = FieldOffset + Info.Size; + updateAlignment(Info.Alignment); + RemainingBitsInField = Context.toBits(Info.Size) - Width; } } @@ -2488,96 +2416,210 @@ void MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { // Zero-width bitfields are ignored unless they follow a non-zero-width // bitfield. - std::pair FieldInfo = getAdjustedFieldInfo(FD); - CharUnits FieldSize = FieldInfo.first; - CharUnits FieldAlign = FieldInfo.second; - if (!LastFieldIsNonZeroWidthBitfield) { placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size); // TODO: Add a Sema warning that MS ignores alignment for zero // sized bitfields that occur after zero-size bitfields or non-bitfields. return; } - LastFieldIsNonZeroWidthBitfield = false; + ElementInfo Info = getAdjustedElementInfo(FD); if (IsUnion) { - placeFieldAtZero(); - Size = std::max(Size, FieldSize); + placeFieldAtOffset(CharUnits::Zero()); + Size = std::max(Size, Info.Size); } else { // Round up the current record size to the field's alignment boundary. - CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign); + CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment); placeFieldAtOffset(FieldOffset); Size = FieldOffset; - updateAlignment(FieldAlign); + updateAlignment(Info.Alignment); } } -void MicrosoftRecordLayoutBuilder::fixSizeAndAlignment(const RecordDecl *RD) { - DataSize = Size; - NonVirtualAlignment = Alignment; - RequiredAlignment = std::max(RequiredAlignment, - Context.toCharUnitsFromBits(RD->getMaxAlignment())); - updateAlignment(RequiredAlignment); +void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) { + if (!HasVBPtr) + return; + if (SharedVBPtrBase) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase); + VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset(); + return; + } + // Inject the VBPointer at the injection site. + CharUnits InjectionSite = VBPtrOffset; + // But before we do, make sure it's properly aligned. + VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment); + // Determine where the first field should be laid out after the vbptr. + CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; + // Make sure that the amount we push the fields back by is a multiple of the + // alignment. + CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment(Alignment); + // Increase the size of the object and push back all fields by the offset + // amount. + Size += Offset; + for (SmallVector::iterator i = FieldOffsets.begin(), + e = FieldOffsets.end(); + i != e; ++i) + *i += Context.toBits(Offset); + for (BaseOffsetsMapTy::iterator i = Bases.begin(), e = Bases.end(); + i != e; ++i) + if (i->second >= InjectionSite) + i->second += Offset; + // Update the object alignment. + updateAlignment(PointerInfo.Alignment); } -void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { - if (!HasVBPtr) +void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) { + if (!HasOwnVFPtr) return; + // Make sure that the amount we push the struct back by is a multiple of the + // alignment. + CharUnits Offset = PointerInfo.Size.RoundUpToAlignment(Alignment); + // Increase the size of the object and push back all fields, the vbptr and all + // bases by the offset amount. + Size += Offset; + for (SmallVector::iterator i = FieldOffsets.begin(), + e = FieldOffsets.end(); + i != e; ++i) + *i += Context.toBits(Offset); + if (HasVBPtr) + VBPtrOffset += Offset; + for (BaseOffsetsMapTy::iterator i = Bases.begin(), e = Bases.end(); + i != e; ++i) + i->second += Offset; + updateAlignment(PointerInfo.Alignment); +} - PreviousBaseLayout = 0; +void MicrosoftRecordLayoutBuilder::injectVPtrs(const CXXRecordDecl *RD) { + if (!(HasOwnVFPtr || HasVBPtr && !SharedVBPtrBase)) + return; + if (!Is64BitMode || RequiredAlignment <= CharUnits::fromQuantity(8)) { + // Note that the VBPtr is injected first. It depends on the alignment of + // the object *before* the alignment is updated by inserting a pointer into + // the record. + injectVBPtr(RD); + injectVFPtr(RD); + return; + } + // In 64-bit mode, structs with RequiredAlignment greater than 8 get special + // layout rules. Likely this is to avoid excessive padding intruced around + // the vfptrs and vbptrs. The special rules involve re-laying out the struct + // and inserting the vfptr and vbptr as if they were fields/bases. + FieldOffsets.clear(); + Bases.clear(); + Size = CharUnits::Zero(); + updateAlignment(PointerInfo.Alignment); + if (HasOwnVFPtr) + Size = PointerInfo.Size; + layoutNonVirtualBases(RD); + if (HasVBPtr && !SharedVBPtrBase) { + const CXXRecordDecl *PenultBaseDecl = 0; + const CXXRecordDecl *LastBaseDecl = 0; + // Iterate through the bases and find the last two non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); + i != e; ++i) { + if (i->isVirtual()) + continue; + const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl(); + if (!LastBaseDecl || Bases[BaseDecl] > Bases[LastBaseDecl]) { + PenultBaseDecl = LastBaseDecl; + LastBaseDecl = BaseDecl; + } + } + const ASTRecordLayout *PenultBaseLayout = PenultBaseDecl ? + &Context.getASTRecordLayout(PenultBaseDecl) : 0; + const ASTRecordLayout *LastBaseLayout = LastBaseDecl ? + &Context.getASTRecordLayout(LastBaseDecl) : 0; + // Calculate the vbptr offset. The rule is different than in the general + // case layout. Particularly, if the last two non-virtual bases are both + // zero sized, the site of the vbptr is *before* the padding that occurs + // between the two zero sized bases and the vbptr potentially aliases with + // the first of these two bases. We have no understanding of why this is + // different from the general case layout but it may have to do with lazy + // placement of zero sized bases. + VBPtrOffset = Size; + if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) { + VBPtrOffset = Bases[LastBaseDecl]; + if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero()) + VBPtrOffset = Bases[PenultBaseDecl]; + } + // Once we've located a spot for the vbptr, place it. + VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment); + Size = VBPtrOffset + PointerInfo.Size; + if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) { + // Add the padding between zero sized bases after the vbptr. + if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero()) + Size += CharUnits::One(); + Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment()); + Bases[LastBaseDecl] = Size; + } + } + layoutFields(RD); +} - llvm::SmallPtrSet HasVtordisp = +void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { + if (!HasVBPtr) + return; + // Vtordisps are always 4 bytes (even in 64-bit mode) + CharUnits VtorDispSize = CharUnits::fromQuantity(4); + CharUnits VtorDispAlignment = VtorDispSize; + // vtordisps respect pragma pack. + if (!MaxFieldAlignment.isZero()) + VtorDispAlignment = std::min(VtorDispAlignment, MaxFieldAlignment); + // The alignment of the vtordisp is at least the required alignment of the + // entire record. This requirement may be present to support vtordisp + // injection. + VtorDispAlignment = std::max(VtorDispAlignment, RequiredAlignment); + // Compute the vtordisp set. + llvm::SmallPtrSet HasVtordispSet = computeVtorDispSet(RD); - // Iterate through the virtual bases and lay them out. + const ASTRecordLayout* PreviousBaseLayout = 0; for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), e = RD->vbases_end(); i != e; ++i) { const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl(); + const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl); + bool HasVtordisp = HasVtordispSet.count(BaseDecl); // If the last field we laid out was a non-zero length bitfield then add // some extra padding for no obvious reason. if (LastFieldIsNonZeroWidthBitfield) Size += CurrentBitfieldSize; - layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl)); + // Insert padding between two bases if the left first one is zero sized or + // contains a zero sized subobject and the right is zero sized or one leads + // with a zero sized base. The padding between virtual bases is 4 + // bytes (in both 32 and 64 bits modes) and always involves rounding up to + // the required alignment, we don't know why. + if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() && + BaseLayout.leadsWithZeroSizedBase()) + Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize; + // Insert the vtordisp. + if (HasVtordisp) + Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize; + // Insert the virtual base. + ElementInfo Info = getAdjustedElementInfo(BaseLayout); + CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment); + VBases.insert(std::make_pair(BaseDecl, + ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); + Size = BaseOffset + BaseLayout.getNonVirtualSize(); + updateAlignment(Info.Alignment); + PreviousBaseLayout = &BaseLayout; } } -void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD, - bool HasVtordisp) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CharUnits Four = CharUnits::fromQuantity(4); - // Insert padding between two bases if the left first one is zero sized or - // contains a zero sized subobject and the right is zero sized or one leads - // with a zero sized base. The minimal padding between virtual bases is 4 - // bytes (in both 32 and 64 bits modes), we don't know why. - if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() && - Layout.leadsWithZeroSizedBase()) - Size = Size.RoundUpToAlignment(std::max(Four, RequiredAlignment)) + Four; - - // vtordisps are always 4 bytes (even in 64-bit mode) - if (HasVtordisp) - Size = Size.RoundUpToAlignment(Alignment) + Four; - - // Insert the base here. - Size = Size.RoundUpToAlignment(getBaseAlignment(Layout)); - // Update the alignment - updateAlignment(getBaseAlignment(Layout)); - VBases.insert( - std::make_pair(RD, ASTRecordLayout::VBaseInfo(Size, HasVtordisp))); - Size += Layout.getNonVirtualSize(); - // Alignment was upadated in InitializeCXXLayout. - PreviousBaseLayout = &Layout; -} - void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { + // Respect required alignment. Note that in 32-bit mode Required alignment + // may be 0 nad cause size not to be updated. + if (!RequiredAlignment.isZero()) { + Alignment = std::max(Alignment, RequiredAlignment); + Size = Size.RoundUpToAlignment(Alignment); + } + // Zero-sized structures have size equal to their alignment. if (Size.isZero()) { HasZeroSizedSubObject = true; LeadsWithZeroSizedBase = true; Size = Alignment; } - - if (!RequiredAlignment.isZero()) - Size = Size.RoundUpToAlignment(Alignment); } static bool @@ -2600,8 +2642,7 @@ RequiresVtordisp(const llvm::SmallPtrSet &HasVtordisp, llvm::SmallPtrSet MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { - llvm::SmallPtrSet HasVtordisp; - + llvm::SmallPtrSet HasVtordispSet; // If any of our bases need a vtordisp for this type, so do we. Check our // direct bases for vtordisp requirements. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), @@ -2615,9 +2656,8 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { be = Layout.getVBaseOffsetsMap().end(); bi != be; ++bi) if (bi->second.hasVtorDisp()) - HasVtordisp.insert(bi->first); + HasVtordispSet.insert(bi->first); } - // If we define a constructor or destructor and override a function that is // defined in a virtual base's vtable, that virtual bases need a vtordisp. // Here we collect a list of classes with vtables for which our virtual bases @@ -2639,25 +2679,24 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { e = MD->end_overridden_methods(); if (i == e) // If a virtual method has no-overrides it lives in its parent's vtable. - HasVtordisp.insert(MD->getParent()); + HasVtordispSet.insert(MD->getParent()); else Work.insert(i, e); // We've finished processing this element, remove it from the working set. Work.erase(MD); } } - // Re-check all of our vbases for vtordisp requirements (in case their // non-virtual bases have vtordisp requirements). for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), e = RD->vbases_end(); i != e; ++i) { const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl(); - if (!HasVtordisp.count(BaseDecl) && RequiresVtordisp(HasVtordisp, BaseDecl)) - HasVtordisp.insert(BaseDecl); + if (!HasVtordispSet.count(BaseDecl) && + RequiresVtordisp(HasVtordispSet, BaseDecl)) + HasVtordispSet.insert(BaseDecl); } - - return HasVtordisp; + return HasVtordispSet; } /// \brief Get or compute information about the layout of the specified record @@ -2670,11 +2709,11 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const { Builder.cxxLayout(RD); return new (*this) ASTRecordLayout( *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment, - Builder.HasExtendableVFPtr && !Builder.PrimaryBase, - Builder.HasExtendableVFPtr, + Builder.HasOwnVFPtr, + Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), Builder.DataSize, - Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase, + Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase, false, Builder.SharedVBPtrBase, Builder.HasZeroSizedSubObject, Builder.LeadsWithZeroSizedBase, Builder.Bases, Builder.VBases); @@ -2998,7 +3037,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS, PrintIndentNoOffset(OS, IndentLevel - 1); OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity(); - OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n"; + OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity() << "]\n"; OS << '\n'; } diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 2dba75e..69aecfd 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -316,7 +316,7 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF, const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(Base); CharUnits Size = Layout.getNonVirtualSize(); - CharUnits Align = Layout.getNonVirtualAlign(); + CharUnits Align = Layout.getNonVirtualAlignment(); llvm::Value *SizeVal = CGF.CGM.getSize(Size); diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 34cee37..c3338a1 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -712,7 +712,7 @@ CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD); CharUnits NonVirtualSize = Layout.getNonVirtualSize(); - CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); + CharUnits NonVirtualAlign = Layout.getNonVirtualAlignment(); CharUnits AlignedNonVirtualTypeSize = NonVirtualSize.RoundUpToAlignment(NonVirtualAlign); @@ -994,7 +994,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, if (BaseTy) { CharUnits NonVirtualSize = Layout.getNonVirtualSize(); - CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); + CharUnits NonVirtualAlign = Layout.getNonVirtualAlignment(); CharUnits AlignedNonVirtualTypeSize = NonVirtualSize.RoundUpToAlignment(NonVirtualAlign); diff --git a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp index dca9f17..ba7bc89 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -95,7 +95,7 @@ void (UnspecSingle::*us_f_mp)() = &UnspecSingle::foo; // CHECK: @"\01?v_f_mp@Const@@3P8Virtual@@AEXXZQ2@" = // CHECK: global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, align 4 // CHECK: @"\01?u_f_mp@Const@@3P8Unspecified@@AEXXZQ2@" = -// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, align 4 +// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 20, i32 0 }, align 4 // CHECK: @"\01?us_f_mp@Const@@3P8UnspecSingle@@AEXXZQ2@" = // CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@UnspecSingle@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, align 4 } @@ -167,7 +167,7 @@ void EmitNonVirtualMemberPointers() { // CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, // CHECK: { i8*, i32, i32 }* %{{.*}}, align 4 // CHECK: store { i8*, i32, i32, i32 } -// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 20, i32 0 }, // CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4 // CHECK: store { i8*, i32, i32, i32 } // CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@UnspecWithVBPtr@@QAEXXZ" to i8*), diff --git a/clang/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp b/clang/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp index 3fef0e4..2976d19 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp @@ -264,7 +264,7 @@ struct H : Z, A { // VTABLE-EXTENDED-H: VFTable for 'V1' in 'simple::A' in 'extended::A' in 'extended::H' (2 entries). // VTABLE-EXTENDED-H-NEXT: 0 | void simple::A::f() - // VTABLE-EXTENDED-H-NEXT: [this adjustment: vtordisp at -4, vbptr at 8 to the left, + // VTABLE-EXTENDED-H-NEXT: [this adjustment: vtordisp at -4, vbptr at 4 to the left, // VTABLE-EXTENDED-H-NEXT: vboffset at 8 in the vbtable, 8 non-virtual] // MANGLING-DAG: @"\01?f@A@simple@@$R477PPPPPPPM@7AEXXZ" diff --git a/clang/test/CodeGenCXX/virtual-base-cast.cpp b/clang/test/CodeGenCXX/virtual-base-cast.cpp index 40e68f6..e35f41e 100644 --- a/clang/test/CodeGenCXX/virtual-base-cast.cpp +++ b/clang/test/CodeGenCXX/virtual-base-cast.cpp @@ -77,13 +77,13 @@ BB* d() { return y; } // Same as 'c' except the vbptr offset is 4, changing the initial GEP and the // final add. // MSVC: @"\01?d@@YAPAUBB@@XZ"() [[NUW:#[0-9]+]] { -// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 4 +// MSVC: %[[vbptr_off:.*]] = getelementptr inbounds i8* {{.*}}, i32 12 // MSVC: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to i8** // MSVC: %[[vbtable:.*]] = load i8** %[[vbptr]] // MSVC: %[[entry:.*]] = getelementptr inbounds i8* {{.*}}, i32 16 // MSVC: %[[entry_i32:.*]] = bitcast i8* %[[entry]] to i32* // MSVC: %[[offset:.*]] = load i32* %[[entry_i32]] -// MSVC: add nsw i32 4, %[[offset]] +// MSVC: add nsw i32 12, %[[offset]] // MSVC: } // CHECK: attributes [[NUW]] = { nounwind{{.*}} } diff --git a/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp b/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp index 78957cf..1b5d25c 100644 --- a/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp +++ b/clang/test/Layout/ms-x86-alias-avoidance-padding.cpp @@ -46,41 +46,55 @@ struct AT3 : AT2, AT1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct AT3 -// CHECK: 0 | struct AT2 (base) -// CHECK: 0 | struct AT0 t -// CHECK: 0 | union AT0::/dev/null \ // RUN: | FileCheck %s -check-prefix CHECK-X64 -struct T0 { char c; }; -struct T2 : virtual T0 { }; -struct T3 { T2 a[1]; char c; }; +struct T0 { char c; }; +struct T2 : virtual T0 { }; +struct T3 { T2 a[1]; char c; }; -// CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct T3 -// CHECK: 0 | struct T2 [1] a -// CHECK: 5 | char c -// CHECK: | [sizeof=8, align=4 -// CHECK: | nvsize=8, nvalign=4] -// CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 0 | struct T3 -// CHECK-X64: 0 | struct T2 [1] a -// CHECK-X64: 16 | char c -// CHECK-X64: | [sizeof=24, align=8 -// CHECK-X64: | nvsize=24, nvalign=8] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct T3 +// CHECK-NEXT: 0 | struct T2 [1] a +// CHECK-NEXT: 5 | char c +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | nvsize=8, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct T3 +// CHECK-X64-NEXT: 0 | struct T2 [1] a +// CHECK-X64-NEXT: 16 | char c +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=24, nvalign=8] int a[sizeof(T3)]; diff --git a/clang/test/Layout/ms-x86-pack-and-align.cpp b/clang/test/Layout/ms-x86-pack-and-align.cpp index d9bca99..b9d2862 100644 --- a/clang/test/Layout/ms-x86-pack-and-align.cpp +++ b/clang/test/Layout/ms-x86-pack-and-align.cpp @@ -36,21 +36,23 @@ struct X { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct X -// CHECK: 0 | struct B a -// CHECK: 0 | long long a -// CHECK: 8 | char b -// CHECK: 10 | int c -// CHECK: | [sizeof=16, align=4 -// CHECK: | nvsize=16, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct X +// CHECK-NEXT: 0 | struct B a +// CHECK-NEXT: 0 | long long a +// CHECK: 8 | char b +// CHECK-NEXT: 10 | int c +// CHECK-NEXT: | [sizeof=16, align=4 +// CHECK-NEXT: | nvsize=16, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 0 | struct X -// CHECK-X64: 0 | struct B a -// CHECK-X64: 0 | long long a -// CHECK-X64: 8 | char b -// CHECK-X64: 10 | int c -// CHECK-X64: | [sizeof=16, align=4 -// CHECK-X64: | nvsize=16, nvalign=4] +// CHECK-X64-NEXT: 0 | struct X +// CHECK-X64-NEXT: 0 | struct B a +// CHECK-X64-NEXT: 0 | long long a +// CHECK-X64: 8 | char b +// CHECK-X64-NEXT: 10 | int c +// CHECK-X64-NEXT: | [sizeof=16, align=4 +// CHECK-X64-NEXT: | nvsize=16, nvalign=4] struct Y : A, B { char a; @@ -63,25 +65,27 @@ struct Y : A, B { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct Y -// CHECK: 0 | struct A (base) -// CHECK: 0 | char a -// CHECK: 4 | struct B (base) -// CHECK: 4 | long long a -// CHECK: 12 | char a -// CHECK: 14 | int b -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=20, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct Y +// CHECK-NEXT: 0 | struct A (base) +// CHECK-NEXT: 0 | char a +// CHECK-NEXT: 4 | struct B (base) +// CHECK-NEXT: 4 | long long a +// CHECK-NEXT: 12 | char a +// CHECK-NEXT: 14 | int b +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | nvsize=20, nvalign=4] // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 0 | struct Y -// CHECK-X64: 0 | struct A (base) -// CHECK-X64: 0 | char a -// CHECK-X64: 4 | struct B (base) -// CHECK-X64: 4 | long long a -// CHECK-X64: 12 | char a -// CHECK-X64: 14 | int b -// CHECK-X64: | [sizeof=20, align=4 -// CHECK-X64: | nvsize=20, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct Y +// CHECK-X64-NEXT: 0 | struct A (base) +// CHECK-X64-NEXT: 0 | char a +// CHECK-X64-NEXT: 4 | struct B (base) +// CHECK-X64-NEXT: 4 | long long a +// CHECK-X64-NEXT: 12 | char a +// CHECK-X64-NEXT: 14 | int b +// CHECK-X64-NEXT: | [sizeof=20, align=4 +// CHECK-X64-NEXT: | nvsize=20, nvalign=4] struct Z : virtual B { char a; @@ -94,23 +98,23 @@ struct Z : virtual B { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct Z -// CHECK: 0 | (Z vbtable pointer) -// CHECK: 4 | char a -// CHECK: 6 | int b -// CHECK: 12 | struct B (virtual base) -// CHECK: 12 | long long a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=10, nvalign=2] +// CHECK-NEXT: 0 | struct Z +// CHECK-NEXT: 0 | (Z vbtable pointer) +// CHECK-NEXT: 4 | char a +// CHECK-NEXT: 6 | int b +// CHECK-NEXT: 12 | struct B (virtual base) +// CHECK-NEXT: 12 | long long a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | nvsize=10, nvalign=4] // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 0 | struct Z -// CHECK-X64: 0 | (Z vbtable pointer) -// CHECK-X64: 8 | char a -// CHECK-X64: 10 | int b -// CHECK-X64: 16 | struct B (virtual base) -// CHECK-X64: 16 | long long a -// CHECK-X64: | [sizeof=24, align=4 -// CHECK-X64: | nvsize=14, nvalign=2] +// CHECK-X64-NEXT: 0 | struct Z +// CHECK-X64-NEXT: 0 | (Z vbtable pointer) +// CHECK-X64-NEXT: 8 | char a +// CHECK-X64-NEXT: 10 | int b +// CHECK-X64-NEXT: 16 | struct B (virtual base) +// CHECK-X64-NEXT: 16 | long long a +// CHECK-X64-NEXT: | [sizeof=24, align=4 +// CHECK-X64-NEXT: | nvsize=14, nvalign=4] #pragma pack(pop) @@ -121,23 +125,27 @@ struct B1 : virtual A1 { char a; }; struct C1 : B1 {}; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct C1 -// CHECK: 0 | struct B1 (base) -// CHECK: 0 | (B1 vbtable pointer) -// CHECK: 4 | char a -// CHECK: 8 | struct A1 (virtual base) -// CHECK: 8 | long long a -// CHECK: | [sizeof=16, align=8 -// CHECK: | nvsize=5, nvalign=1] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C1 +// CHECK-NEXT: 0 | struct B1 (base) +// CHECK-NEXT: 0 | (B1 vbtable pointer) +// CHECK-NEXT: 4 | char a +// CHECK-NEXT: 8 | struct A1 (virtual base) +// CHECK-NEXT: 8 | long long a +// CHECK-NEXT: | [sizeof=16, align=8 +// CHECK-NEXT: | nvsize=5, nvalign=8] // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 0 | struct C1 -// CHECK-X64: 0 | struct B1 (base) -// CHECK-X64: 0 | (B1 vbtable pointer) -// CHECK-X64: 8 | char a -// CHECK-X64: 16 | struct A1 (virtual base) -// CHECK-X64: 16 | long long a -// CHECK-X64: | [sizeof=24, align=8 -// CHECK-X64: | nvsize=9, nvalign=1] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct C1 +// CHECK-X64-NEXT: 0 | struct B1 (base) +// CHECK-X64-NEXT: 0 | (B1 vbtable pointer) +// CHECK-X64-NEXT: 8 | char a +// CHECK-X64-NEXT: 16 | struct A1 (virtual base) +// CHECK-X64-NEXT: 16 | long long a +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=9, nvalign=8] struct CA0 { CA0() {} @@ -153,23 +161,27 @@ struct CA2 : public CA1, public CA0 { #pragma pack(pop) // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct CA2 -// CHECK: 0 | (CA2 vftable pointer) -// CHECK: 4 | struct CA1 (base) -// CHECK: 4 | (CA1 vbtable pointer) -// CHECK: 9 | struct CA0 (base) (empty) -// CHECK: 9 | struct CA0 (virtual base) (empty) -// CHECK: | [sizeof=9, align=1 -// CHECK: | nvsize=9, nvalign=1] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct CA2 +// CHECK-NEXT: 0 | (CA2 vftable pointer) +// CHECK-NEXT: 4 | struct CA1 (base) +// CHECK-NEXT: 4 | (CA1 vbtable pointer) +// CHECK-NEXT: 9 | struct CA0 (base) (empty) +// CHECK-NEXT: 9 | struct CA0 (virtual base) (empty) +// CHECK-NEXT: | [sizeof=9, align=1 +// CHECK-NEXT: | nvsize=9, nvalign=1] +// CHECK-C64: *** Dumping AST Record Layout +// CHECK-C64: *** Dumping AST Record Layout // CHECK-C64: *** Dumping AST Record Layout -// CHECK-C64: 0 | struct CA2 -// CHECK-C64: 0 | (CA2 vftable pointer) -// CHECK-C64: 8 | struct CA1 (base) -// CHECK-C64: 8 | (CA1 vbtable pointer) -// CHECK-C64: 17 | struct CA0 (base) (empty) -// CHECK-C64: 17 | struct CA0 (virtual base) (empty) -// CHECK-C64: | [sizeof=17, align=1 -// CHECK-C64: | nvsize=17, nvalign=1] +// CHECK-C64-NEXT: 0 | struct CA2 +// CHECK-C64-NEXT: 0 | (CA2 vftable pointer) +// CHECK-C64-NEXT: 8 | struct CA1 (base) +// CHECK-C64-NEXT: 8 | (CA1 vbtable pointer) +// CHECK-C64-NEXT: 17 | struct CA0 (base) (empty) +// CHECK-C64-NEXT: 17 | struct CA0 (virtual base) (empty) +// CHECK-C64-NEXT: | [sizeof=17, align=1 +// CHECK-C64-NEXT: | nvsize=17, nvalign=1] int a[ sizeof(X)+ diff --git a/clang/test/Layout/ms-x86-primary-bases.cpp b/clang/test/Layout/ms-x86-primary-bases.cpp index bc9b801..1597657 100644 --- a/clang/test/Layout/ms-x86-primary-bases.cpp +++ b/clang/test/Layout/ms-x86-primary-bases.cpp @@ -16,65 +16,67 @@ struct A : virtual B0 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct A -// CHECK: 0 | (A vbtable pointer) -// CHECK: 4 | struct B0 (virtual base) -// CHECK: 4 | (B0 vftable pointer) -// CHECK: 8 | int a -// CHECK: | [sizeof=12, align=4 -// CHECK: | nvsize=4, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0 | (A vbtable pointer) +// CHECK-NEXT: 4 | struct B0 (virtual base) +// CHECK-NEXT: 4 | (B0 vftable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: | [sizeof=12, align=4 +// CHECK-NEXT: | nvsize=4, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct A +// CHECK-X64-NEXT: 0 | (A vbtable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (virtual base) +// CHECK-X64-NEXT: 8 | (B0 vftable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct B : virtual B0 { virtual void f() { printf("B"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct B -// CHECK: 0 | (B vbtable pointer) -// CHECK: 4 | struct B0 (virtual base) -// CHECK: 4 | (B0 vftable pointer) -// CHECK: 8 | int a -// CHECK: | [sizeof=12, align=4 -// CHECK: | nvsize=4, nvalign=4] +// CHECK-NEXT: 0 | struct B +// CHECK-NEXT: 0 | (B vbtable pointer) +// CHECK-NEXT: 4 | struct B0 (virtual base) +// CHECK-NEXT: 4 | (B0 vftable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: | [sizeof=12, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct B +// CHECK-X64-NEXT: 0 | (B vbtable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (virtual base) +// CHECK-X64-NEXT: 8 | (B0 vftable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct C : virtual B0 { virtual void g() { printf("A"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct C -// CHECK: 0 | (C vftable pointer) -// CHECK: 4 | (C vbtable pointer) -// CHECK: 8 | struct B0 (virtual base) -// CHECK: 8 | (B0 vftable pointer) -// CHECK: 12 | int a -// CHECK: | [sizeof=16, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct C +// CHECK-NEXT: 0 | (C vftable pointer) +// CHECK-NEXT: 4 | (C vbtable pointer) +// CHECK-NEXT: 8 | struct B0 (virtual base) +// CHECK-NEXT: 8 | (B0 vftable pointer) +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: | [sizeof=16, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct C +// CHECK-X64-NEXT: 0 | (C vftable pointer) +// CHECK-X64-NEXT: 8 | (C vbtable pointer) +// CHECK-X64-NEXT: 16 | struct B0 (virtual base) +// CHECK-X64-NEXT: 16 | (B0 vftable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: | [sizeof=32, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] struct D : virtual B2, virtual B0 { virtual void f() { printf("D"); } @@ -82,27 +84,29 @@ struct D : virtual B2, virtual B0 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct D -// CHECK: 0 | (D vftable pointer) -// CHECK: 4 | (D vbtable pointer) -// CHECK: 8 | struct B2 (virtual base) -// CHECK: 8 | int a -// CHECK: 12 | struct B0 (virtual base) -// CHECK: 12 | (B0 vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D +// CHECK-NEXT: 0 | (D vftable pointer) +// CHECK-NEXT: 4 | (D vbtable pointer) +// CHECK-NEXT: 8 | struct B2 (virtual base) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 12 | struct B0 (virtual base) +// CHECK-NEXT: 12 | (B0 vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | nvsize=8, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct D +// CHECK-X64-NEXT: 0 | (D vftable pointer) +// CHECK-X64-NEXT: 8 | (D vbtable pointer) +// CHECK-X64-NEXT: 16 | struct B2 (virtual base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 24 | struct B0 (virtual base) +// CHECK-X64-NEXT: 24 | (B0 vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] struct E : B0, virtual B1 { virtual void f() { printf("E"); } @@ -110,197 +114,206 @@ struct E : B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct E -// CHECK: 0 | struct B0 (primary base) -// CHECK: 0 | (B0 vftable pointer) -// CHECK: 4 | int a -// CHECK: 8 | (E vbtable pointer) -// CHECK: 12 | struct B1 (virtual base) -// CHECK: 12 | (B1 vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=12, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct E +// CHECK-NEXT: 0 | struct B0 (primary base) +// CHECK-NEXT: 0 | (B0 vftable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | (E vbtable pointer) +// CHECK-NEXT: 12 | struct B1 (virtual base) +// CHECK-NEXT: 12 | (B1 vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | nvsize=12, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct E +// CHECK-X64-NEXT: 0 | struct B0 (primary base) +// CHECK-X64-NEXT: 0 | (B0 vftable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | (E vbtable pointer) +// CHECK-X64-NEXT: 24 | struct B1 (virtual base) +// CHECK-X64-NEXT: 24 | (B1 vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=24, nvalign=8] struct F : virtual B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct F -// CHECK: 0 | (F vbtable pointer) -// CHECK: 4 | struct B0 (virtual base) -// CHECK: 4 | (B0 vftable pointer) -// CHECK: 8 | int a -// CHECK: 12 | struct B1 (virtual base) -// CHECK: 12 | (B1 vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=4, nvalign=4] +// CHECK-NEXT: 0 | struct F +// CHECK-NEXT: 0 | (F vbtable pointer) +// CHECK-NEXT: 4 | struct B0 (virtual base) +// CHECK-NEXT: 4 | (B0 vftable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 12 | struct B1 (virtual base) +// CHECK-NEXT: 12 | (B1 vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct F +// CHECK-X64-NEXT: 0 | (F vbtable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (virtual base) +// CHECK-X64-NEXT: 8 | (B0 vftable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 24 | struct B1 (virtual base) +// CHECK-X64-NEXT: 24 | (B1 vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct AX : B0X, B1X { int a; AX() : a(0xf000000A) {} virtual void f() { printf("A"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct AX -// CHECK: 8 | struct B0X (base) -// CHECK: 8 | int a -// CHECK: 0 | struct B1X (primary base) -// CHECK: 0 | (B1X vftable pointer) -// CHECK: 4 | int a -// CHECK: 12 | int a -// CHECK: | [sizeof=16, align=4 -// CHECK: | nvsize=16, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct AX +// CHECK-NEXT: 8 | struct B0X (base) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 0 | struct B1X (primary base) +// CHECK-NEXT: 0 | (B1X vftable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: | [sizeof=16, align=4 +// CHECK-NEXT: | nvsize=16, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 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] +// CHECK-X64-NEXT: 0 | struct AX +// CHECK-X64-NEXT: 16 | struct B0X (base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 0 | struct B1X (primary base) +// CHECK-X64-NEXT: 0 | (B1X vftable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 20 | int a +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=24, nvalign=8] struct BX : B0X, B1X { int a; BX() : a(0xf000000B) {} virtual void g() { printf("B"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct BX -// CHECK: 8 | struct B0X (base) -// CHECK: 8 | int a -// CHECK: 0 | struct B1X (primary base) -// CHECK: 0 | (B1X vftable pointer) -// CHECK: 4 | int a -// CHECK: 12 | int a -// CHECK: | [sizeof=16, align=4 -// CHECK: | nvsize=16, nvalign=4] +// CHECK-NEXT: 0 | struct BX +// CHECK-NEXT: 8 | struct B0X (base) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 0 | struct B1X (primary base) +// CHECK-NEXT: 0 | (B1X vftable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: | [sizeof=16, align=4 +// CHECK-NEXT: | 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] +// CHECK-x64-NEXT: 0 | struct BX +// CHECK-x64-NEXT: 16 | struct B0X (base) +// CHECK-x64-NEXT: 16 | int a +// CHECK-x64-NEXT: 0 | struct B1X (primary base) +// CHECK-x64-NEXT: 0 | (B1X vftable pointer) +// CHECK-x64-NEXT: 8 | int a +// CHECK-x64-NEXT: 24 | int a +// CHECK-x64-NEXT: | [sizeof=24, align=8 +// CHECK-x64-NEXT: | nvsize=24, nvalign=8] struct CX : B0X, B2X { int a; CX() : a(0xf000000C) {} virtual void g() { printf("C"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct CX -// CHECK: 0 | (CX vftable pointer) -// CHECK: 4 | struct B0X (base) -// CHECK: 4 | int a -// CHECK: 8 | struct B2X (base) -// CHECK: 8 | (B2X vbtable pointer) -// CHECK: 12 | int a -// CHECK: 16 | int a -// CHECK: 20 | struct B1X (virtual base) -// CHECK: 20 | (B1X vftable pointer) -// CHECK: 24 | int a -// CHECK: | [sizeof=28, align=4 -// CHECK: | nvsize=20, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct CX +// CHECK-NEXT: 0 | (CX vftable pointer) +// CHECK-NEXT: 4 | struct B0X (base) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | struct B2X (base) +// CHECK-NEXT: 8 | (B2X vbtable pointer) +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 20 | struct B1X (virtual base) +// CHECK-NEXT: 20 | (B1X vftable pointer) +// CHECK-NEXT: 24 | int a +// CHECK-NEXT: | [sizeof=28, align=4 +// CHECK-NEXT: | nvsize=20, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct CX +// CHECK-X64-NEXT: 0 | (CX vftable pointer) +// CHECK-X64-NEXT: 8 | struct B0X (base) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | struct B2X (base) +// CHECK-X64-NEXT: 16 | (B2X vbtable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 40 | struct B1X (virtual base) +// CHECK-X64-NEXT: 40 | (B1X vftable pointer) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=56, align=8 +// CHECK-X64-NEXT: | nvsize=40, nvalign=8] struct DX : virtual B1X { int a; DX() : a(0xf000000D) {} virtual void f() { printf("D"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct DX -// CHECK: 0 | (DX vbtable pointer) -// CHECK: 4 | int a -// CHECK: 8 | (vtordisp for vbase B1X) -// CHECK: 12 | struct B1X (virtual base) -// CHECK: 12 | (B1X vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct DX +// CHECK-NEXT: 0 | (DX vbtable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | (vtordisp for vbase B1X) +// CHECK-NEXT: 12 | struct B1X (virtual base) +// CHECK-NEXT: 12 | (B1X vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct DX +// CHECK-X64-NEXT: 0 | (DX vbtable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 20 | (vtordisp for vbase B1X) +// CHECK-X64-NEXT: 24 | struct B1X (virtual base) +// CHECK-X64-NEXT: 24 | (B1X vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] struct EX : virtual B1X { int a; EX() : a(0xf000000E) {} virtual void g() { printf("E"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct EX -// CHECK: 0 | (EX vftable pointer) -// CHECK: 4 | (EX vbtable pointer) -// CHECK: 8 | int a -// CHECK: 12 | struct B1X (virtual base) -// CHECK: 12 | (B1X vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=12, nvalign=4] +// CHECK-NEXT: 0 | struct EX +// CHECK-NEXT: 0 | (EX vftable pointer) +// CHECK-NEXT: 4 | (EX vbtable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 12 | struct B1X (virtual base) +// CHECK-NEXT: 12 | (B1X vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct EX +// CHECK-X64-NEXT: 0 | (EX vftable pointer) +// CHECK-X64-NEXT: 8 | (EX vbtable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 24 | struct B1X (virtual base) +// CHECK-X64-NEXT: 24 | (B1X vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=24, nvalign=8] struct FX : virtual B1X { int a; FX() : a(0xf000000F) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct FX -// CHECK: 0 | (FX vbtable pointer) -// CHECK: 4 | int a -// CHECK: 8 | struct B1X (virtual base) -// CHECK: 8 | (B1X vftable pointer) -// CHECK: 12 | int a -// CHECK: | [sizeof=16, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct FX +// CHECK-NEXT: 0 | (FX vbtable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | struct B1X (virtual base) +// CHECK-NEXT: 8 | (B1X vftable pointer) +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: | [sizeof=16, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct FX +// CHECK-X64-NEXT: 0 | (FX vbtable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | struct B1X (virtual base) +// CHECK-X64-NEXT: 16 | (B1X vftable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: | [sizeof=32, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] int a[ sizeof(A)+ diff --git a/clang/test/Layout/ms-x86-size-alignment-fail.cpp b/clang/test/Layout/ms-x86-size-alignment-fail.cpp index f998ee1..ad1de16 100644 --- a/clang/test/Layout/ms-x86-size-alignment-fail.cpp +++ b/clang/test/Layout/ms-x86-size-alignment-fail.cpp @@ -11,108 +11,112 @@ struct __declspec(align(1)) B1 {}; struct A : virtual B0 {}; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct A -// CHECK: 0 | (A vbtable pointer) -// CHECK: 4 | struct B0 (virtual base) -// CHECK: 4 | char a -// CHECK: | [sizeof=5, align=4 -// CHECK: | nvsize=4, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0 | (A vbtable pointer) +// CHECK-NEXT: 4 | struct B0 (virtual base) +// CHECK-NEXT: 4 | char a +// CHECK-NEXT: | [sizeof=5, align=4 +// CHECK-NEXT: | nvsize=4, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 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] +// CHECK-X64-NEXT: 0 | struct A +// CHECK-X64-NEXT: 0 | (A vbtable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (virtual base) +// CHECK-X64-NEXT: 8 | char a +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct __declspec(align(1)) B : virtual B0 {}; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct B -// CHECK: 0 | (B vbtable pointer) -// CHECK: 4 | struct B0 (virtual base) -// CHECK: 4 | char a -// CHECK: | [sizeof=8, align=4 -// CHECK: | nvsize=4, nvalign=4] +// CHECK-NEXT: 0 | struct B +// CHECK-NEXT: 0 | (B vbtable pointer) +// CHECK-NEXT: 4 | struct B0 (virtual base) +// CHECK-NEXT: 4 | char a +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct B +// CHECK-X64-NEXT: 0 | (B vbtable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (virtual base) +// CHECK-X64-NEXT: 8 | char a +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct C : virtual B0 { int a; C() : a(0xC) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct C -// CHECK: 0 | (C vbtable pointer) -// CHECK: 4 | int a -// CHECK: 8 | struct B0 (virtual base) -// CHECK: 8 | char a -// CHECK: | [sizeof=9, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct C +// CHECK-NEXT: 0 | (C vbtable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | struct B0 (virtual base) +// CHECK-NEXT: 8 | char a +// CHECK-NEXT: | [sizeof=9, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct C +// CHECK-X64-NEXT: 0 | (C vbtable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | struct B0 (virtual base) +// CHECK-X64-NEXT: 16 | char a +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] struct D : virtual B0 { __declspec(align(1)) int a; D() : a(0xD) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct D -// CHECK: 0 | (D vbtable pointer) -// CHECK: 4 | int a -// CHECK: 8 | struct B0 (virtual base) -// CHECK: 8 | char a -// CHECK: | [sizeof=12, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct D +// CHECK-NEXT: 0 | (D vbtable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | struct B0 (virtual base) +// CHECK-NEXT: 8 | char a +// CHECK-NEXT: | [sizeof=12, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct D +// CHECK-X64-NEXT: 0 | (D vbtable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | struct B0 (virtual base) +// CHECK-X64-NEXT: 16 | char a +// CHECK-X64-NEXT: | [sizeof=24, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] struct E : virtual B0, virtual B1 {}; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct E -// CHECK: 0 | (E vbtable pointer) -// CHECK: 4 | struct B0 (virtual base) -// CHECK: 4 | char a -// CHECK: 5 | struct B1 (virtual base) (empty) -// CHECK: | [sizeof=8, align=4 -// CHECK: | nvsize=4, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct E +// CHECK-NEXT: 0 | (E vbtable pointer) +// CHECK-NEXT: 4 | struct B0 (virtual base) +// CHECK-NEXT: 4 | char a +// CHECK-NEXT: 5 | struct B1 (virtual base) (empty) +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | nvsize=4, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct E +// CHECK-X64-NEXT: 0 | (E vbtable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (virtual base) +// CHECK-X64-NEXT: 8 | char a +// CHECK-X64-NEXT: 9 | struct B1 (virtual base) (empty) +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct F { char a; virtual ~F(); }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct F -// CHECK: 0 | (F vftable pointer) -// CHECK: 4 | char a -// CHECK: | [sizeof=8, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct F +// CHECK-NEXT: 0 | (F vftable pointer) +// CHECK-NEXT: 4 | char a +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct F +// CHECK-X64-NEXT: 0 | (F vftable pointer) +// CHECK-X64-NEXT: 8 | char a +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] int a[ sizeof(A)+ diff --git a/clang/test/Layout/ms-x86-vfvb-alignment.cpp b/clang/test/Layout/ms-x86-vfvb-alignment.cpp index 8eea209..51d46fe 100644 --- a/clang/test/Layout/ms-x86-vfvb-alignment.cpp +++ b/clang/test/Layout/ms-x86-vfvb-alignment.cpp @@ -16,349 +16,361 @@ struct B6 { int a; B6() : a(0xf00000B6) {} virtual void f() { printf("B6"); } }; struct A : B0, virtual B1 { __declspec(align(16)) int a; A() : a(0xf000000A) {} virtual void f() { printf("A"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct A -// CHECK: 0 | (A vftable pointer) -// CHECK: 16 | struct B0 (base) -// CHECK: 16 | int a -// CHECK: 20 | (A vbtable pointer) -// CHECK: 48 | int a -// CHECK: 64 | struct B1 (virtual base) -// CHECK: 64 | char a -// CHECK: | [sizeof=80, align=16 -// CHECK: | nvsize=64, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0 | (A vftable pointer) +// CHECK-NEXT: 16 | struct B0 (base) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 20 | (A vbtable pointer) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: 64 | struct B1 (virtual base) +// CHECK-NEXT: 64 | char a +// CHECK-NEXT: | [sizeof=80, align=16 +// CHECK-NEXT: | nvsize=64, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct A +// CHECK-X64-NEXT: 0 | (A vftable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (base) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | (A vbtable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | char a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct B : A, B2 { int a; B() : a(0xf000000B) {} virtual void f() { printf("B"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct B -// CHECK: 0 | struct A (primary base) -// CHECK: 0 | (A vftable pointer) -// CHECK: 16 | struct B0 (base) -// CHECK: 16 | int a -// CHECK: 20 | (A vbtable pointer) -// CHECK: 48 | int a -// CHECK: 64 | struct B2 (base) -// CHECK: 64 | (B2 vbtable pointer) -// CHECK: 68 | int a -// CHECK: 72 | int a -// CHECK: 80 | struct B1 (virtual base) -// CHECK: 80 | char a -// CHECK: | [sizeof=96, align=16 -// CHECK: | nvsize=80, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct B +// CHECK-NEXT: 0 | struct A (primary base) +// CHECK-NEXT: 0 | (A vftable pointer) +// CHECK-NEXT: 16 | struct B0 (base) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 20 | (A vbtable pointer) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: 64 | struct B2 (base) +// CHECK-NEXT: 64 | (B2 vbtable pointer) +// CHECK-NEXT: 68 | int a +// CHECK-NEXT: 72 | int a +// CHECK-NEXT: 80 | struct B1 (virtual base) +// CHECK-NEXT: 80 | char a +// CHECK-NEXT: | [sizeof=96, align=16 +// CHECK-NEXT: | nvsize=80, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct B +// CHECK-X64-NEXT: 0 | struct A (primary base) +// CHECK-X64-NEXT: 0 | (A vftable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (base) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | (A vbtable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B2 (base) +// CHECK-X64-NEXT: 48 | (B2 vbtable pointer) +// CHECK-X64-NEXT: 56 | int a +// CHECK-X64-NEXT: 64 | int a +// CHECK-X64-NEXT: 80 | struct B1 (virtual base) +// CHECK-X64-NEXT: 80 | char a +// CHECK-X64-NEXT: | [sizeof=96, align=16 +// CHECK-X64-NEXT: | nvsize=80, nvalign=16] struct C : B4 { int a; C() : a(0xf000000C) {} virtual void f() { printf("C"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct C -// CHECK: 0 | (C vftable pointer) -// CHECK: 16 | struct B4 (base) -// CHECK: 16 | (B4 vbtable pointer) -// CHECK: 20 | int a -// CHECK: 24 | int a -// CHECK: 32 | struct B3 (virtual base) -// CHECK: 32 | int a -// CHECK: | [sizeof=48, align=16 -// CHECK: | nvsize=32, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C +// CHECK-NEXT: 0 | (C vftable pointer) +// CHECK-NEXT: 16 | struct B4 (base) +// CHECK-NEXT: 16 | (B4 vbtable pointer) +// CHECK-NEXT: 20 | int a +// CHECK-NEXT: 24 | int a +// CHECK-NEXT: 32 | struct B3 (virtual base) +// CHECK-NEXT: 32 | int a +// CHECK-NEXT: | [sizeof=48, align=16 +// CHECK-NEXT: | nvsize=32, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct C +// CHECK-X64-NEXT: 0 | (C vftable pointer) +// CHECK-X64-NEXT: 16 | struct B4 (base) +// CHECK-X64-NEXT: 16 | (B4 vbtable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B3 (virtual base) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct D : C { int a; D() : a(0xf000000D) {} virtual void f() { printf("D"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct D -// CHECK: 0 | struct C (primary base) -// CHECK: 0 | (C vftable pointer) -// CHECK: 16 | struct B4 (base) -// CHECK: 16 | (B4 vbtable pointer) -// CHECK: 20 | int a -// CHECK: 24 | int a -// CHECK: 32 | int a -// CHECK: 48 | struct B3 (virtual base) -// CHECK: 48 | int a -// CHECK: | [sizeof=64, align=16 -// CHECK: | nvsize=48, nvalign=16] +// CHECK-NEXT: 0 | struct D +// CHECK-NEXT: 0 | struct C (primary base) +// CHECK-NEXT: 0 | (C vftable pointer) +// CHECK-NEXT: 16 | struct B4 (base) +// CHECK-NEXT: 16 | (B4 vbtable pointer) +// CHECK-NEXT: 20 | int a +// CHECK-NEXT: 24 | int a +// CHECK-NEXT: 32 | int a +// CHECK-NEXT: 48 | struct B3 (virtual base) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: | [sizeof=64, align=16 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct D +// CHECK-X64-NEXT: 0 | struct C (primary base) +// CHECK-X64-NEXT: 0 | (C vftable pointer) +// CHECK-X64-NEXT: 16 | struct B4 (base) +// CHECK-X64-NEXT: 16 | (B4 vbtable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: 64 | struct B3 (virtual base) +// CHECK-X64-NEXT: 64 | int a +// CHECK-X64-NEXT: | [sizeof=80, align=16 +// CHECK-X64-NEXT: | nvsize=64, nvalign=16] struct E : virtual C { int a; E() : a(0xf000000E) {} virtual void f() { printf("E"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct E -// CHECK: 0 | (E vbtable pointer) -// CHECK: 4 | int a -// CHECK: 16 | struct B3 (virtual base) -// CHECK: 16 | int a -// CHECK: 44 | (vtordisp for vbase C) -// CHECK: 48 | struct C (virtual base) -// CHECK: 48 | (C vftable pointer) -// CHECK: 64 | struct B4 (base) -// CHECK: 64 | (B4 vbtable pointer) -// CHECK: 68 | int a -// CHECK: 72 | int a -// CHECK: | [sizeof=80, align=16 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct E +// CHECK-NEXT: 0 | (E vbtable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 16 | struct B3 (virtual base) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 44 | (vtordisp for vbase C) +// CHECK-NEXT: 48 | struct C (virtual base) +// CHECK-NEXT: 48 | (C vftable pointer) +// CHECK-NEXT: 64 | struct B4 (base) +// CHECK-NEXT: 64 | (B4 vbtable pointer) +// CHECK-NEXT: 68 | int a +// CHECK-NEXT: 72 | int a +// CHECK-NEXT: | [sizeof=80, align=16 +// CHECK-NEXT: | nvsize=8, nvalign=16] // 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] +// CHECK-X64-NEXT: 0 | struct E +// CHECK-X64-NEXT: 0 | (E vbtable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | struct B3 (virtual base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 44 | (vtordisp for vbase C) +// CHECK-X64-NEXT: 48 | struct C (virtual base) +// CHECK-X64-NEXT: 48 | (C vftable pointer) +// CHECK-X64-NEXT: 64 | struct B4 (base) +// CHECK-X64-NEXT: 64 | (B4 vbtable pointer) +// CHECK-X64-NEXT: 72 | int a +// CHECK-X64-NEXT: 80 | int a +// CHECK-X64-NEXT: | [sizeof=96, align=16 +// CHECK-X64-NEXT: | nvsize=16, nvalign=16] struct F : B3, virtual B0 { int a; F() : a(0xf000000F) {} virtual void f() { printf("F"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct F -// CHECK: 0 | (F vftable pointer) -// CHECK: 16 | struct B3 (base) -// CHECK: 16 | int a -// CHECK: 32 | (F vbtable pointer) -// CHECK: 48 | int a -// CHECK: 64 | struct B0 (virtual base) -// CHECK: 64 | int a -// CHECK: | [sizeof=80, align=16 -// CHECK: | nvsize=64, nvalign=16] +// CHECK-NEXT: 0 | struct F +// CHECK-NEXT: 0 | (F vftable pointer) +// CHECK-NEXT: 16 | struct B3 (base) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 32 | (F vbtable pointer) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: 64 | struct B0 (virtual base) +// CHECK-NEXT: 64 | int a +// CHECK-NEXT: | [sizeof=80, align=16 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct F +// CHECK-X64-NEXT: 0 | (F vftable pointer) +// CHECK-X64-NEXT: 16 | struct B3 (base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 32 | (F vbtable pointer) +// CHECK-X64-NEXT: 40 | int a +// CHECK-X64-NEXT: 48 | struct B0 (virtual base) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct G : B2, B6, virtual B1 { int a; G() : a(0xf0000010) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct G -// CHECK: 8 | struct B2 (base) -// CHECK: 8 | (B2 vbtable pointer) -// CHECK: 12 | int a -// CHECK: 0 | struct B6 (primary base) -// CHECK: 0 | (B6 vftable pointer) -// CHECK: 4 | int a -// CHECK: 16 | int a -// CHECK: 20 | struct B1 (virtual base) -// CHECK: 20 | char a -// CHECK: | [sizeof=21, align=4 -// CHECK: | nvsize=20, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct G +// CHECK-NEXT: 8 | struct B2 (base) +// CHECK-NEXT: 8 | (B2 vbtable pointer) +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: 0 | struct B6 (primary base) +// CHECK-NEXT: 0 | (B6 vftable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 20 | struct B1 (virtual base) +// CHECK-NEXT: 20 | char a +// CHECK-NEXT: | [sizeof=21, align=4 +// CHECK-NEXT: | nvsize=20, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct G +// CHECK-X64-NEXT: 16 | struct B2 (base) +// CHECK-X64-NEXT: 16 | (B2 vbtable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: 0 | struct B6 (primary base) +// CHECK-X64-NEXT: 0 | (B6 vftable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 40 | struct B1 (virtual base) +// CHECK-X64-NEXT: 40 | char a +// CHECK-X64-NEXT: | [sizeof=48, align=8 +// CHECK-X64-NEXT: | nvsize=40, nvalign=8] struct H : B6, B2, virtual B1 { int a; H() : a(0xf0000011) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct H -// CHECK: 0 | struct B6 (primary base) -// CHECK: 0 | (B6 vftable pointer) -// CHECK: 4 | int a -// CHECK: 8 | struct B2 (base) -// CHECK: 8 | (B2 vbtable pointer) -// CHECK: 12 | int a -// CHECK: 16 | int a -// CHECK: 20 | struct B1 (virtual base) -// CHECK: 20 | char a -// CHECK: | [sizeof=21, align=4 -// CHECK: | nvsize=20, nvalign=4] +// CHECK-NEXT: 0 | struct H +// CHECK-NEXT: 0 | struct B6 (primary base) +// CHECK-NEXT: 0 | (B6 vftable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | struct B2 (base) +// CHECK-NEXT: 8 | (B2 vbtable pointer) +// CHECK-NEXT: 12 | int a +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 20 | struct B1 (virtual base) +// CHECK-NEXT: 20 | char a +// CHECK-NEXT: | [sizeof=21, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct H +// CHECK-X64-NEXT: 0 | struct B6 (primary base) +// CHECK-X64-NEXT: 0 | (B6 vftable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | struct B2 (base) +// CHECK-X64-NEXT: 16 | (B2 vbtable pointer) +// CHECK-X64-NEXT: 24 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 40 | struct B1 (virtual base) +// CHECK-X64-NEXT: 40 | char a +// CHECK-X64-NEXT: | [sizeof=48, align=8 +// CHECK-X64-NEXT: | 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) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct I -// CHECK: 0 | struct B0 (base) -// CHECK: 0 | int a -// CHECK: 4 | (I vbtable pointer) -// CHECK: 20 | int a -// CHECK: 24 | int a1 -// CHECK: 32 | int a2 -// CHECK: 48 | struct B1 (virtual base) -// CHECK: 48 | char a -// CHECK: | [sizeof=64, align=16 -// CHECK: | nvsize=48, nvalign=16] +// CHECK-NEXT: 0 | struct I +// CHECK-NEXT: 0 | struct B0 (base) +// CHECK-NEXT: 0 | int a +// CHECK-NEXT: 4 | (I vbtable pointer) +// CHECK-NEXT: 20 | int a +// CHECK-NEXT: 24 | int a1 +// CHECK-NEXT: 32 | int a2 +// CHECK-NEXT: 48 | struct B1 (virtual base) +// CHECK-NEXT: 48 | char a +// CHECK-NEXT: | [sizeof=64, align=16 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct I +// CHECK-X64-NEXT: 0 | struct B0 (base) +// CHECK-X64-NEXT: 0 | int a +// CHECK-X64-NEXT: 8 | (I vbtable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 20 | int a1 +// CHECK-X64-NEXT: 32 | int a2 +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | char a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct J : B0, B3, virtual B1 { int a; int a1; J() : a(0xf0000012), a1(0xf0000012) {} }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct J -// CHECK: 0 | struct B0 (base) -// CHECK: 0 | int a -// CHECK: 16 | struct B3 (base) -// CHECK: 16 | int a -// CHECK: 32 | (J vbtable pointer) -// CHECK: 48 | int a -// CHECK: 52 | int a1 -// CHECK: 64 | struct B1 (virtual base) -// CHECK: 64 | char a -// CHECK: | [sizeof=80, align=16 -// CHECK: | nvsize=64, nvalign=16] +// CHECK-NEXT: 0 | struct J +// CHECK-NEXT: 0 | struct B0 (base) +// CHECK-NEXT: 0 | int a +// CHECK-NEXT: 16 | struct B3 (base) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 32 | (J vbtable pointer) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: 52 | int a1 +// CHECK-NEXT: 64 | struct B1 (virtual base) +// CHECK-NEXT: 64 | char a +// CHECK-NEXT: | [sizeof=80, align=16 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct J +// CHECK-X64-NEXT: 0 | struct B0 (base) +// CHECK-X64-NEXT: 0 | int a +// CHECK-X64-NEXT: 16 | struct B3 (base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 32 | (J vbtable pointer) +// CHECK-X64-NEXT: 40 | int a +// CHECK-X64-NEXT: 44 | int a1 +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | char a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct K { int a; K() : a(0xf0000013) {} virtual void f() { printf("K"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct K -// CHECK: 0 | (K vftable pointer) -// CHECK: 4 | int a -// CHECK: | [sizeof=8, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct K +// CHECK-NEXT: 0 | (K vftable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct K +// CHECK-X64-NEXT: 0 | (K vftable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] struct L : virtual K { int a; L() : a(0xf0000014) {} virtual void g() { printf("L"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct L -// CHECK: 0 | (L vftable pointer) -// CHECK: 4 | (L vbtable pointer) -// CHECK: 8 | int a -// CHECK: 12 | struct K (virtual base) -// CHECK: 12 | (K vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=12, nvalign=4] +// CHECK-NEXT: 0 | struct L +// CHECK-NEXT: 0 | (L vftable pointer) +// CHECK-NEXT: 4 | (L vbtable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 12 | struct K (virtual base) +// CHECK-NEXT: 12 | (K vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct L +// CHECK-X64-NEXT: 0 | (L vftable pointer) +// CHECK-X64-NEXT: 8 | (L vbtable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 24 | struct K (virtual base) +// CHECK-X64-NEXT: 24 | (K vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=24, nvalign=8] struct M : virtual K { int a; M() : a(0xf0000015) {} virtual void f() { printf("M"); } }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct M -// CHECK: 0 | (M vbtable pointer) -// CHECK: 4 | int a -// CHECK: 8 | (vtordisp for vbase K) -// CHECK: 12 | struct K (virtual base) -// CHECK: 12 | (K vftable pointer) -// CHECK: 16 | int a -// CHECK: | [sizeof=20, align=4 -// CHECK: | nvsize=8, nvalign=4] +// CHECK-NEXT: 0 | struct M +// CHECK-NEXT: 0 | (M vbtable pointer) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | (vtordisp for vbase K) +// CHECK-NEXT: 12 | struct K (virtual base) +// CHECK-NEXT: 12 | (K vftable pointer) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: | [sizeof=20, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64-NEXT: 0 | struct M +// CHECK-X64-NEXT: 0 | (M vbtable pointer) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 20 | (vtordisp for vbase K) +// CHECK-X64-NEXT: 24 | struct K (virtual base) +// CHECK-X64-NEXT: 24 | (K vftable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=16, nvalign=8] int a[ sizeof(A)+ diff --git a/clang/test/Layout/ms-x86-vfvb-sharing.cpp b/clang/test/Layout/ms-x86-vfvb-sharing.cpp index 2b3d08e..8deb9c0 100644 --- a/clang/test/Layout/ms-x86-vfvb-sharing.cpp +++ b/clang/test/Layout/ms-x86-vfvb-sharing.cpp @@ -18,27 +18,31 @@ struct A : B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct A -// CHECK: 0 | (A vftable pointer) -// CHECK: 16 | struct B0 (base) -// CHECK: 16 | int a -// CHECK: 20 | (A vbtable pointer) -// CHECK: 48 | int a -// CHECK: 64 | struct B1 (virtual base) -// CHECK: 64 | int a -// CHECK: | [sizeof=80, align=16 -// CHECK: | nvsize=64, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0 | (A vftable pointer) +// CHECK-NEXT: 16 | struct B0 (base) +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 20 | (A vbtable pointer) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: 64 | struct B1 (virtual base) +// CHECK-NEXT: 64 | int a +// CHECK-NEXT: | [sizeof=80, align=16 +// CHECK-NEXT: | nvsize=64, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct A +// CHECK-X64-NEXT: 0 | (A vftable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (base) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | (A vbtable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct B : B2, B0, virtual B1 { __declspec(align(16)) int a; @@ -47,29 +51,31 @@ struct B : B2, B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct B -// CHECK: 0 | struct B2 (primary base) -// CHECK: 0 | (B2 vftable pointer) -// CHECK: 4 | struct B0 (base) -// CHECK: 4 | int a -// CHECK: 8 | (B vbtable pointer) -// CHECK: 32 | int a -// CHECK: 48 | struct B1 (virtual base) -// CHECK: 48 | int a -// CHECK: | [sizeof=64, align=16 -// CHECK: | nvsize=48, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct B +// CHECK-NEXT: 0 | struct B2 (primary base) +// CHECK-NEXT: 0 | (B2 vftable pointer) +// CHECK-NEXT: 4 | struct B0 (base) +// CHECK-NEXT: 4 | int a +// CHECK-NEXT: 8 | (B vbtable pointer) +// CHECK-NEXT: 32 | int a +// CHECK-NEXT: 48 | struct B1 (virtual base) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: | [sizeof=64, align=16 +// CHECK-NEXT: | 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] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct B +// CHECK-X64-NEXT: 0 | struct B2 (primary base) +// CHECK-X64-NEXT: 0 | (B2 vftable pointer) +// CHECK-X64-NEXT: 8 | struct B0 (base) +// CHECK-X64-NEXT: 8 | int a +// CHECK-X64-NEXT: 16 | (B vbtable pointer) +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct C : B3, B0, virtual B1 { __declspec(align(16)) int a; @@ -78,29 +84,31 @@ struct C : B3, B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct C -// CHECK: 0 | (C vftable pointer) -// CHECK: 16 | struct B3 (base) -// CHECK: 16 | (B3 vbtable pointer) -// CHECK: 20 | struct B0 (base) -// CHECK: 20 | int a -// CHECK: 32 | int a -// CHECK: 48 | struct B1 (virtual base) -// CHECK: 48 | int a -// CHECK: | [sizeof=64, align=16 -// CHECK: | nvsize=48, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C +// CHECK-NEXT: 0 | (C vftable pointer) +// CHECK-NEXT: 16 | struct B3 (base) +// CHECK-NEXT: 16 | (B3 vbtable pointer) +// CHECK-NEXT: 20 | struct B0 (base) +// CHECK-NEXT: 20 | int a +// CHECK-NEXT: 32 | int a +// CHECK-NEXT: 48 | struct B1 (virtual base) +// CHECK-NEXT: 48 | int a +// CHECK-NEXT: | [sizeof=64, align=16 +// CHECK-NEXT: | nvsize=48, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct C +// CHECK-X64-NEXT: 0 | (C vftable pointer) +// CHECK-X64-NEXT: 8 | struct B3 (base) +// CHECK-X64-NEXT: 8 | (B3 vbtable pointer) +// CHECK-X64-NEXT: 16 | struct B0 (base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] struct D : B4, B0, virtual B1 { __declspec(align(16)) int a; @@ -109,29 +117,31 @@ struct D : B4, B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct D -// CHECK: 0 | struct B4 (primary base) -// CHECK: 0 | (B4 vftable pointer) -// CHECK: 4 | (B4 vbtable pointer) -// CHECK: 8 | struct B0 (base) -// CHECK: 8 | int a -// CHECK: 16 | int a -// CHECK: 32 | struct B1 (virtual base) -// CHECK: 32 | int a -// CHECK: | [sizeof=48, align=16 -// CHECK: | nvsize=32, nvalign=16] +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct D +// CHECK-NEXT: 0 | struct B4 (primary base) +// CHECK-NEXT: 0 | (B4 vftable pointer) +// CHECK-NEXT: 4 | (B4 vbtable pointer) +// CHECK-NEXT: 8 | struct B0 (base) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 16 | int a +// CHECK-NEXT: 32 | struct B1 (virtual base) +// CHECK-NEXT: 32 | int a +// CHECK-NEXT: | [sizeof=48, align=16 +// CHECK-NEXT: | nvsize=32, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct D +// CHECK-X64-NEXT: 0 | struct B4 (primary base) +// CHECK-X64-NEXT: 0 | (B4 vftable pointer) +// CHECK-X64-NEXT: 8 | (B4 vbtable pointer) +// CHECK-X64-NEXT: 16 | struct B0 (base) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 32 | int a +// CHECK-X64-NEXT: 48 | struct B1 (virtual base) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: | [sizeof=64, align=16 +// CHECK-X64-NEXT: | nvsize=48, nvalign=16] int a[ sizeof(A)+ diff --git a/clang/test/Layout/ms-x86-vtordisp.cpp b/clang/test/Layout/ms-x86-vtordisp.cpp index 6a37eb1..390d671 100644 --- a/clang/test/Layout/ms-x86-vtordisp.cpp +++ b/clang/test/Layout/ms-x86-vtordisp.cpp @@ -30,35 +30,39 @@ struct A : virtual B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct A -// CHECK: 0 | (A vftable pointer) -// CHECK: 4 | (A vbtable pointer) -// CHECK: 8 | int a -// CHECK: 16 | (vtordisp for vbase B0) -// CHECK: 20 | struct B0 (virtual base) -// CHECK: 20 | (B0 vftable pointer) -// CHECK: 24 | int a -// CHECK: 44 | (vtordisp for vbase B1) -// CHECK: 48 | struct B1 (virtual base) -// CHECK: 48 | (B1 vftable pointer) -// CHECK: 52 | int a -// CHECK: | [sizeof=64, align=16 -// CHECK: | nvsize=12, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct A +// CHECK-NEXT: 0 | (A vftable pointer) +// CHECK-NEXT: 4 | (A vbtable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 16 | (vtordisp for vbase B0) +// CHECK-NEXT: 20 | struct B0 (virtual base) +// CHECK-NEXT: 20 | (B0 vftable pointer) +// CHECK-NEXT: 24 | int a +// CHECK-NEXT: 44 | (vtordisp for vbase B1) +// CHECK-NEXT: 48 | struct B1 (virtual base) +// CHECK-NEXT: 48 | (B1 vftable pointer) +// CHECK-NEXT: 52 | int a +// CHECK-NEXT: | [sizeof=64, align=16 +// CHECK-NEXT: | nvsize=12, nvalign=16] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64-NEXT: 0 | struct A +// CHECK-X64-NEXT: 0 | (A vftable pointer) +// CHECK-X64-NEXT: 8 | (A vbtable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 36 | (vtordisp for vbase B0) +// CHECK-X64-NEXT: 40 | struct B0 (virtual base) +// CHECK-X64-NEXT: 40 | (B0 vftable pointer) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: 76 | (vtordisp for vbase B1) +// CHECK-X64-NEXT: 80 | struct B1 (virtual base) +// CHECK-X64-NEXT: 80 | (B1 vftable pointer) +// CHECK-X64-NEXT: 88 | int a +// CHECK-X64-NEXT: | [sizeof=96, align=16 +// CHECK-X64-NEXT: | nvsize=24, nvalign=16] struct C : virtual B0, virtual B1, VAlign32 { int a; @@ -68,39 +72,43 @@ struct C : virtual B0, virtual B1, VAlign32 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct C -// CHECK: 0 | (C vftable pointer) -// CHECK: 32 | struct VAlign32 (base) -// CHECK: 32 | (VAlign32 vbtable pointer) -// CHECK: 36 | int a -// CHECK: 64 | (vtordisp for vbase B0) -// CHECK: 68 | struct B0 (virtual base) -// CHECK: 68 | (B0 vftable pointer) -// CHECK: 72 | int a -// CHECK: 108 | (vtordisp for vbase B1) -// CHECK: 112 | struct B1 (virtual base) -// CHECK: 112 | (B1 vftable pointer) -// CHECK: 116 | int a -// CHECK: 128 | struct Align32 (virtual base) (empty) -// CHECK: | [sizeof=128, align=32 -// CHECK: | nvsize=64, nvalign=32] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct C +// CHECK-NEXT: 0 | (C vftable pointer) +// CHECK-NEXT: 32 | struct VAlign32 (base) +// CHECK-NEXT: 32 | (VAlign32 vbtable pointer) +// CHECK-NEXT: 36 | int a +// CHECK-NEXT: 64 | (vtordisp for vbase B0) +// CHECK-NEXT: 68 | struct B0 (virtual base) +// CHECK-NEXT: 68 | (B0 vftable pointer) +// CHECK-NEXT: 72 | int a +// CHECK-NEXT: 108 | (vtordisp for vbase B1) +// CHECK-NEXT: 112 | struct B1 (virtual base) +// CHECK-NEXT: 112 | (B1 vftable pointer) +// CHECK-NEXT: 116 | int a +// CHECK-NEXT: 128 | struct Align32 (virtual base) (empty) +// CHECK-NEXT: | [sizeof=128, align=32 +// CHECK-NEXT: | nvsize=64, nvalign=32] +// CHECK-X64: *** Dumping AST Record Layout // 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] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct C +// CHECK-X64-NEXT: 0 | (C vftable pointer) +// CHECK-X64-NEXT: 32 | struct VAlign32 (base) +// CHECK-X64-NEXT: 32 | (VAlign32 vbtable pointer) +// CHECK-X64-NEXT: 40 | int a +// CHECK-X64-NEXT: 68 | (vtordisp for vbase B0) +// CHECK-X64-NEXT: 72 | struct B0 (virtual base) +// CHECK-X64-NEXT: 72 | (B0 vftable pointer) +// CHECK-X64-NEXT: 80 | int a +// CHECK-X64-NEXT: 108 | (vtordisp for vbase B1) +// CHECK-X64-NEXT: 112 | struct B1 (virtual base) +// CHECK-X64-NEXT: 112 | (B1 vftable pointer) +// CHECK-X64-NEXT: 120 | int a +// CHECK-X64-NEXT: 128 | struct Align32 (virtual base) (empty) +// CHECK-X64-NEXT: | [sizeof=128, align=32 +// CHECK-X64-NEXT: | nvsize=64, nvalign=32] struct __declspec(align(32)) D : virtual B0, virtual B1 { int a; @@ -110,35 +118,35 @@ struct __declspec(align(32)) D : virtual B0, virtual B1 { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct D -// CHECK: 0 | (D vftable pointer) -// CHECK: 4 | (D vbtable pointer) -// CHECK: 8 | int a -// CHECK: 32 | (vtordisp for vbase B0) -// CHECK: 36 | struct B0 (virtual base) -// CHECK: 36 | (B0 vftable pointer) -// CHECK: 40 | int a -// CHECK: 76 | (vtordisp for vbase B1) -// CHECK: 80 | struct B1 (virtual base) -// CHECK: 80 | (B1 vftable pointer) -// CHECK: 84 | int a -// CHECK: | [sizeof=96, align=32 -// CHECK: | nvsize=12, nvalign=4] +// CHECK-NEXT: 0 | struct D +// CHECK-NEXT: 0 | (D vftable pointer) +// CHECK-NEXT: 4 | (D vbtable pointer) +// CHECK-NEXT: 8 | int a +// CHECK-NEXT: 32 | (vtordisp for vbase B0) +// CHECK-NEXT: 36 | struct B0 (virtual base) +// CHECK-NEXT: 36 | (B0 vftable pointer) +// CHECK-NEXT: 40 | int a +// CHECK-NEXT: 76 | (vtordisp for vbase B1) +// CHECK-NEXT: 80 | struct B1 (virtual base) +// CHECK-NEXT: 80 | (B1 vftable pointer) +// CHECK-NEXT: 84 | int a +// CHECK-NEXT: | [sizeof=96, align=32 +// CHECK-NEXT: | nvsize=12, nvalign=32] // 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] +// CHECK-X64-NEXT: 0 | struct D +// CHECK-X64-NEXT: 0 | (D vftable pointer) +// CHECK-X64-NEXT: 8 | (D vbtable pointer) +// CHECK-X64-NEXT: 16 | int a +// CHECK-X64-NEXT: 36 | (vtordisp for vbase B0) +// CHECK-X64-NEXT: 40 | struct B0 (virtual base) +// CHECK-X64-NEXT: 40 | (B0 vftable pointer) +// CHECK-X64-NEXT: 48 | int a +// CHECK-X64-NEXT: 76 | (vtordisp for vbase B1) +// CHECK-X64-NEXT: 80 | struct B1 (virtual base) +// CHECK-X64-NEXT: 80 | (B1 vftable pointer) +// CHECK-X64-NEXT: 88 | int a +// CHECK-X64-NEXT: | [sizeof=96, align=32 +// CHECK-X64-NEXT: | nvsize=24, nvalign=32] struct AT { virtual ~AT(){} @@ -149,19 +157,21 @@ struct CT : virtual AT { 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-NEXT: 0 | struct CT +// CHECK-NEXT: 0 | (CT vbtable pointer) +// CHECK-NEXT: 4 | struct AT (virtual base) +// CHECK-NEXT: 4 | (AT vftable pointer) +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | 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] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct CT +// CHECK-X64-NEXT: 0 | (CT vbtable pointer) +// CHECK-X64-NEXT: 8 | struct AT (virtual base) +// CHECK-X64-NEXT: 8 | (AT vftable pointer) +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] struct XA { XA() { printf("XA"); } @@ -178,27 +188,31 @@ struct XC : virtual XB { }; // CHECK: *** Dumping AST Record Layout -// CHECK: 0 | struct XC -// CHECK: 0 | (XC vbtable pointer) -// CHECK: 4 | (vtordisp for vbase XB) -// CHECK: 8 | struct XB (virtual base) -// CHECK: 8 | (XB vftable pointer) -// CHECK: 16 | struct XA (base) -// CHECK: 16 | long long ll -// CHECK: 24 | int b -// CHECK: | [sizeof=32, align=8 -// CHECK: | nvsize=4, nvalign=4] +// CHECK: *** Dumping AST Record Layout +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct XC +// CHECK-NEXT: 0 | (XC vbtable pointer) +// CHECK-NEXT: 4 | (vtordisp for vbase XB) +// CHECK-NEXT: 8 | struct XB (virtual base) +// CHECK-NEXT: 8 | (XB vftable pointer) +// CHECK-NEXT: 16 | struct XA (base) +// CHECK-NEXT: 16 | long long ll +// CHECK-NEXT: 24 | int b +// CHECK-NEXT: | [sizeof=32, align=8 +// CHECK-NEXT: | nvsize=4, nvalign=8] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: *** Dumping AST Record Layout // CHECK-X64: *** Dumping AST Record Layout -// CHECK-X64: 0 | struct XC -// CHECK-X64: 0 | (XC vbtable pointer) -// CHECK-X64: 12 | (vtordisp for vbase XB) -// CHECK-X64: 16 | struct XB (virtual base) -// CHECK-X64: 16 | (XB vftable pointer) -// CHECK-X64: 24 | struct XA (base) -// CHECK-X64: 24 | long long ll -// CHECK-X64: 32 | int b -// CHECK-X64: | [sizeof=40, align=8 -// CHECK-X64: | nvsize=8, nvalign=8] +// CHECK-X64-NEXT: 0 | struct XC +// CHECK-X64-NEXT: 0 | (XC vbtable pointer) +// CHECK-X64-NEXT: 12 | (vtordisp for vbase XB) +// CHECK-X64-NEXT: 16 | struct XB (virtual base) +// CHECK-X64-NEXT: 16 | (XB vftable pointer) +// CHECK-X64-NEXT: 24 | struct XA (base) +// CHECK-X64-NEXT: 24 | long long ll +// CHECK-X64-NEXT: 32 | int b +// CHECK-X64-NEXT: | [sizeof=40, align=8 +// CHECK-X64-NEXT: | nvsize=8, nvalign=8] int a[ sizeof(A)+