r192494 - Adds Microsoft compatiable C++ record layout code to clang.
jahanian
fjahanian at apple.com
Fri Oct 11 15:00:33 PDT 2013
We are experiencing VS buildbot failures after this patch went in. These three tests are failing.
Testing Time: 47.63s
********************
Failing Tests (3):
Clang :: Analysis/inlining/dyn-dispatch-bifurcate.cpp
Clang :: SemaCXX/primary-base.cpp
Clang :: SemaCXX/warn-reinterpret-base-class.cpp
They all give error having to do with what it says is illegal use of reinterpret_cast.
- Fariborz
On Oct 11, 2013, at 1:19 PM, Warren Hunt <whunt at google.com> wrote:
> Author: whunt
> Date: Fri Oct 11 15:19:00 2013
> New Revision: 192494
>
> URL: http://llvm.org/viewvc/llvm-project?rev=192494&view=rev
> Log:
> Adds Microsoft compatiable C++ record layout code to clang.
>
>
> Modified:
> cfe/trunk/include/clang/AST/ASTContext.h
> cfe/trunk/include/clang/AST/RecordLayout.h
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/lib/AST/RecordLayout.cpp
> cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
> cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
> cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp
> cfe/trunk/lib/Sema/SemaDecl.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/test/CodeGen/pr2394.c
> cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp
> cfe/trunk/test/Coverage/codegen-next.m
> cfe/trunk/test/PCH/rdar10830559.cpp
> cfe/trunk/test/Sema/ms_class_layout.cpp
> cfe/trunk/test/SemaCXX/ms_struct.cpp
>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Fri Oct 11 15:19:00 2013
> @@ -1660,6 +1660,7 @@ public:
> /// record (struct/union/class) \p D, which indicates its size and field
> /// position information.
> const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
> + const ASTRecordLayout *BuildMicrosoftASTRecordLayout(const RecordDecl *D) const;
>
> /// \brief Get or compute information about the layout of the specified
> /// Objective-C interface.
>
> Modified: cfe/trunk/include/clang/AST/RecordLayout.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecordLayout.h?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/RecordLayout.h (original)
> +++ cfe/trunk/include/clang/AST/RecordLayout.h Fri Oct 11 15:19:00 2013
> @@ -93,7 +93,20 @@ private:
> /// HasOwnVFPtr - Does this class provide a virtual function table
> /// (vtable in Itanium, vftbl in Microsoft) that is independent from
> /// its base classes?
> - bool HasOwnVFPtr; // TODO: stash this somewhere more efficient
> + bool HasOwnVFPtr : 1;
> +
> + /// HasVFPtr - Does this class have a vftable at all (could be inherited
> + /// from its primary base.)
> + bool HasVFPtr : 1;
> +
> + /// HasOwnVBPtr - Does this class provide a virtual function table
> + /// (vtable in Itanium, VBtbl in Microsoft) that is independent from
> + /// its base classes?
> + bool HasOwnVBPtr : 1;
> +
> + /// AlignAfterVBases - Force appropriate alignment after virtual bases are
> + /// laid out in MS-C++-ABI.
> + bool AlignAfterVBases : 1;
>
> /// PrimaryBase - The primary base info for this record.
> llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
> @@ -122,13 +135,15 @@ private:
> typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
> ASTRecordLayout(const ASTContext &Ctx,
> CharUnits size, CharUnits alignment,
> - bool hasOwnVFPtr, CharUnits vbptroffset,
> + bool hasOwnVFPtr, bool hasVFPtr, bool hasOwnVBPtr,
> + CharUnits vbptroffset,
> CharUnits datasize,
> const uint64_t *fieldoffsets, unsigned fieldcount,
> CharUnits nonvirtualsize, CharUnits nonvirtualalign,
> CharUnits SizeOfLargestEmptySubobject,
> const CXXRecordDecl *PrimaryBase,
> bool IsPrimaryBaseVirtual,
> + bool ForceAlign,
> const BaseOffsetsMapTy& BaseOffsets,
> const VBaseOffsetsMapTy& VBaseOffsets);
>
> @@ -226,6 +241,35 @@ public:
> return CXXInfo->HasOwnVFPtr;
> }
>
> + /// hasVFPtr - Does this class have a virtual function table pointer.
> + bool hasVFPtr() const {
> + assert(CXXInfo && "Record layout does not have C++ specific info!");
> + return CXXInfo->HasVFPtr;
> + }
> +
> + /// hasOwnVBPtr - Does this class provide its own virtual-base
> + /// table pointer, rather than inheriting one from a primary base
> + /// class?
> + ///
> + /// This implies that the ABI has no primary base class, meaning
> + /// that it has no base classes that are suitable under the conditions
> + /// of the ABI.
> + bool hasOwnVBPtr() const {
> + assert(CXXInfo && "Record layout does not have C++ specific info!");
> + return CXXInfo->HasOwnVBPtr;
> + }
> +
> + /// hasVBPtr - Does this class have a virtual function table pointer.
> + bool hasVBPtr() const {
> + assert(CXXInfo && "Record layout does not have C++ specific info!");
> + return !CXXInfo->VBPtrOffset.isNegative();
> + }
> +
> + bool getAlignAfterVBases() const {
> + assert(CXXInfo && "Record layout does not have C++ specific info!");
> + return CXXInfo->AlignAfterVBases;
> + }
> +
> /// getVBPtrOffset - Get the offset for virtual base table pointer.
> /// This is only meaningful with the Microsoft ABI.
> CharUnits getVBPtrOffset() const {
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Oct 11 15:19:00 2013
> @@ -463,6 +463,7 @@ def warn_pragma_pack_show : Warning<"val
> def warn_pragma_pack_pop_identifer_and_alignment : Warning<
> "specifying both a name and alignment to 'pop' is undefined">;
> def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">;
> +def warn_pragma_ms_struct_failed : Warning<"#pramga ms_struct can not be used with dynamic classes or structures">, InGroup<IgnoredAttributes>;
>
> def warn_pragma_unused_undeclared_var : Warning<
> "undeclared variable %0 used as an argument for '#pragma unused'">;
>
> Modified: cfe/trunk/lib/AST/RecordLayout.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayout.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/RecordLayout.cpp (original)
> +++ cfe/trunk/lib/AST/RecordLayout.cpp Fri Oct 11 15:19:00 2013
> @@ -43,7 +43,9 @@ ASTRecordLayout::ASTRecordLayout(const A
> // Constructor for C++ records.
> ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
> CharUnits size, CharUnits alignment,
> - bool hasOwnVFPtr, CharUnits vbptroffset,
> + bool hasOwnVFPtr, bool hasVFPtr,
> + bool hasOwnVBPtr,
> + CharUnits vbptroffset,
> CharUnits datasize,
> const uint64_t *fieldoffsets,
> unsigned fieldcount,
> @@ -52,6 +54,7 @@ ASTRecordLayout::ASTRecordLayout(const A
> CharUnits SizeOfLargestEmptySubobject,
> const CXXRecordDecl *PrimaryBase,
> bool IsPrimaryBaseVirtual,
> + bool AlignAfterVBases,
> const BaseOffsetsMapTy& BaseOffsets,
> const VBaseOffsetsMapTy& VBaseOffsets)
> : Size(size), DataSize(datasize), Alignment(alignment), FieldOffsets(0),
> @@ -71,6 +74,10 @@ ASTRecordLayout::ASTRecordLayout(const A
> CXXInfo->VBaseOffsets = VBaseOffsets;
> CXXInfo->HasOwnVFPtr = hasOwnVFPtr;
> CXXInfo->VBPtrOffset = vbptroffset;
> + CXXInfo->HasVFPtr = hasVFPtr;
> + CXXInfo->HasOwnVBPtr = hasOwnVBPtr;
> + CXXInfo->AlignAfterVBases = AlignAfterVBases;
> +
>
> #ifndef NDEBUG
> if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
>
> Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
> +++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Fri Oct 11 15:19:00 2013
> @@ -604,6 +604,10 @@ protected:
> /// pointer, as opposed to inheriting one from a primary base class.
> bool HasOwnVFPtr;
>
> + /// HasOwnVBPtr - Whether the class provides its own vbtbl
> + /// pointer, as opposed to inheriting one from a base class. Only for MS.
> + bool HasOwnVBPtr;
> +
> /// VBPtrOffset - Virtual base table offset. Only for MS layout.
> CharUnits VBPtrOffset;
>
> @@ -654,6 +658,7 @@ protected:
> NonVirtualAlignment(CharUnits::One()),
> PrimaryBase(0), PrimaryBaseIsVirtual(false),
> HasOwnVFPtr(false),
> + HasOwnVBPtr(false),
> VBPtrOffset(CharUnits::fromQuantity(-1)),
> FirstNearlyEmptyVBase(0) { }
>
> @@ -1074,8 +1079,10 @@ RecordLayoutBuilder::LayoutNonVirtualBas
> cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
>
> // Remember if this base has virtual bases itself.
> - if (BaseDecl->getNumVBases())
> + if (BaseDecl->getNumVBases()) {
> + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
> HasNonVirtualBaseWithVBTable = true;
> + }
>
> // Skip the primary base, because we've already laid it out. The
> // !PrimaryBaseIsVirtual check is required because we might have a
> @@ -1116,6 +1123,7 @@ RecordLayoutBuilder::LayoutNonVirtualBas
> PtrAlign = std::max(PtrAlign, Alignment);
>
> EnsureVTablePointerAlignment(PtrAlign);
> + HasOwnVBPtr = true;
> VBPtrOffset = getSize();
> setSize(getSize() + PtrWidth);
> setDataSize(getSize());
> @@ -2338,6 +2346,704 @@ static bool mustSkipTailPadding(TargetCX
> llvm_unreachable("bad tail-padding use kind");
> }
>
> +static bool isMsLayout(const RecordDecl* D) {
> + return (D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() ||
> + D->getASTContext().getTargetInfo().getTriple().getOS() ==
> + llvm::Triple::Win32) &&
> + D->getASTContext().getTargetInfo().getPointerWidth(0) == 32;
> + // FIXME: we intend to enable 64 bit mode once it's been verified.
> +}
> +
> +// This section contains an implementation of struct layout that is, up to the
> +// included tests, compatible with cl.exe (2012). The layout produced is
> +// significantly different than those produced by the Itanium ABI. Here we note
> +// the most important differences.
> +//
> +// * The alignment of bitfields in unions is ignored when computing the
> +// alignment of the union.
> +// * The existance of zero-width bitfield that occurs after anything other than
> +// a non-zero length bitfield is ignored.
> +// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
> +// function pointer) and a vbptr (virtual base pointer). They can each be
> +// shared with a, non-virtual bases. These bases need not be the same. vfptrs always occur at offset 0. vbptrs can occur at an
> +// arbitrary offset and are placed after non-virtual bases but before fields.
> +// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
> +// the virtual base and is used in conjunction with virtual overrides during
> +// construction and destruction.
> +// * vfptrs are allocated in a block of memory equal to the alignment of the
> +// fields and non-virtual bases at offset 0.
> +// * vbptrs are allocated in a block of memory equal to the alignment of the
> +// fields and non-virtual bases. This block is at a potentially unaligned offset. If the
> +// allocation slot is unaligned and the alignment is less than or equal to the
> +// pointer size, additional space is allocated so that the pointer can be aligned properly. This causes very strange effects on the placement of objects after the allocated block. (see
> +// the code).
> +// * vtordisps are allocated in a block of memory with size and alignment equal
> +// to the alignment of the completed structure (before applying __declspec(
> +// align())). The vtordisp always occur at the end of the allocation block, immediately prior to the virtual base.
> +// * The last zero sized non-virtual base is allocated after the placement of
> +// vbptr if one exists and can be placed at the end of the struct, potentially
> +// aliasing either the first member or another struct allocated after this
> +// one.
> +// * The last zero size virtual base may be placed at the end of the struct.
> +// and can potentially alias a zero sized type in the next struct.
> +
> +namespace {
> +struct MicrosoftRecordLayoutBuilder {
> + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
> + MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {}
> +private:
> + MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &)
> + 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.
> + void initializeLayout(const RecordDecl *RD);
> + /// \brief Initialized C++ layout, compute alignment and virtual alignment and
> + /// existance 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);
> + /// \brief Lays out the fields of the record. Also rounds size up to
> + /// alignment.
> + void layoutFields(const RecordDecl *RD);
> + void layoutField(const FieldDecl *FD);
> + void layoutBitField(const FieldDecl *FD);
> + /// \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 layoutVirtualBases(const CXXRecordDecl *RD);
> + void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp);
> + /// \brief Flushes the lazy virtual base and conditionally rounds up to
> + /// alignment.
> + void finalizeCXXLayout(const CXXRecordDecl *RD);
> + void honorDeclspecAlign(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);
> + }
> + /// \brief Gets the size and alignment taking attributes into account.
> + std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD);
> + /// \brief Places a field at offset 0.
> + void placeFieldAtZero() { FieldOffsets.push_back(0); }
> + /// \brief Places a field at an offset in CharUnits.
> + void placeFieldAtOffset(CharUnits FieldOffset) {
> + FieldOffsets.push_back(Context.toBits(FieldOffset));
> + }
> + /// \brief Places a bitfield at a bit offset.
> + void placeFieldAtBitOffset(uint64_t FieldOffset) {
> + FieldOffsets.push_back(FieldOffset);
> + }
> + /// \brief Compute the set of virtual bases for which vtordisps are required.
> + llvm::SmallPtrSet<const CXXRecordDecl *, 2>
> + computeVtorDispSet(const CXXRecordDecl *RD);
> +
> + const ASTContext &Context;
> + /// \brief The size of the record being laid out.
> + CharUnits Size;
> + /// \brief The current alignment of the record layout.
> + CharUnits Alignment;
> + /// \brief The collection of field offsets.
> + SmallVector<uint64_t, 16> FieldOffsets;
> + /// \brief The maximum allowed field alignment. This is set by #pragma pack.
> + CharUnits MaxFieldAlignment;
> + /// \brief Alignment does not occur for virtual bases unless something
> + /// forces it to by explicitly using __declspec(align())
> + bool AlignAfterVBases : 1;
> + 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
> + /// including. Only used for C++ layouts.
> + CharUnits NonVirtualAlignment;
> + /// \brief The additional alignment imposed by the virtual bases.
> + CharUnits VirtualAlignment;
> + /// \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 (not necessarily its own) vftable pointer.
> + bool HasVFPtr : 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 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;
> +};
> +} // namespace
> +
> +std::pair<CharUnits, CharUnits>
> +MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
> + std::pair<CharUnits, CharUnits> FieldInfo;
> + if (FD->getType()->isIncompleteArrayType()) {
> + // This is a flexible array member; we can't directly
> + // query getTypeInfo about these, so we figure it out here.
> + // Flexible array members don't have any size, but they
> + // have to be aligned appropriately for their element type.
> + FieldInfo.first = CharUnits::Zero();
> + const ArrayType *ATy = Context.getAsArrayType(FD->getType());
> + FieldInfo.second = Context.getTypeAlignInChars(ATy->getElementType());
> + } else if (const ReferenceType *RT = FD->getType()->getAs<ReferenceType>()) {
> + unsigned AS = RT->getPointeeType().getAddressSpace();
> + FieldInfo.first = Context
> + .toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
> + FieldInfo.second = Context
> + .toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS));
> + } else
> + FieldInfo = Context.getTypeInfoInChars(FD->getType());
> +
> + // If we're not on win32 and using ms_struct the field alignment will be wrong
> + // for 64 bit types, so we fix that here.
> + if (FD->getASTContext().getTargetInfo().getTriple().getOS() !=
> + llvm::Triple::Win32) {
> + QualType T = Context.getBaseElementType(FD->getType());
> + if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
> + CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
> + if (TypeSize > FieldInfo.second)
> + FieldInfo.second = TypeSize;
> + }
> + }
> +
> + // Respect packed attribute.
> + if (FD->hasAttr<PackedAttr>())
> + 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);
> + AlignAfterVBases = true;
> + FieldInfo.second = std::max(FieldInfo.second, FieldAlign);
> + }
> + return FieldInfo;
> +}
> +
> +void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
> + IsUnion = RD->isUnion();
> +
> + Size = CharUnits::Zero();
> + Alignment = CharUnits::One();
> + AlignAfterVBases = false;
> +
> + // Compute the maximum field alignment.
> + MaxFieldAlignment = CharUnits::Zero();
> + // Honor the default struct packing maximum alignment flag.
> + if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct)
> + MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
> + // Honor the packing attribute.
> + if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>())
> + MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
> + // Packed attribute forces max field alignment to be 1.
> + if (RD->hasAttr<PackedAttr>())
> + MaxFieldAlignment = CharUnits::One();
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
> + initializeLayout(RD);
> + layoutFields(RD);
> + honorDeclspecAlign(RD);
> +}
> +
> +void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
> + initializeLayout(RD);
> + initializeCXXLayout(RD);
> + layoutVFPtr(RD);
> + layoutNonVirtualBases(RD);
> + layoutVBPtr(RD);
> + layoutFields(RD);
> + DataSize = Size;
> + NonVirtualAlignment = Alignment;
> + layoutVirtualBases(RD);
> + finalizeCXXLayout(RD);
> + honorDeclspecAlign(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.
> + HasVBPtr = false;
> + HasVFPtr = false;
> + SharedVBPtrBase = 0;
> + PrimaryBase = 0;
> + VirtualAlignment = CharUnits::One();
> +
> + // 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.
> + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
> + e = RD->bases_end();
> + i != e; ++i) {
> + const CXXRecordDecl *BaseDecl =
> + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
> + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
> + // Handle forced alignment.
> + if (Layout.getAlignAfterVBases())
> + AlignAfterVBases = true;
> + // Handle virtual bases.
> + if (i->isVirtual()) {
> + VirtualAlignment = std::max(VirtualAlignment, Layout.getAlignment());
> + HasVBPtr = true;
> + continue;
> + }
> + // We located a primary base class!
> + if (!PrimaryBase && Layout.hasVFPtr()) {
> + PrimaryBase = BaseDecl;
> + HasVFPtr = true;
> + }
> + // We located a base to share a VBPtr with!
> + if (!SharedVBPtrBase && Layout.hasVBPtr()) {
> + SharedVBPtrBase = BaseDecl;
> + HasVBPtr = true;
> + }
> + updateAlignment(Layout.getAlignment());
> + }
> +
> + // 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();
> + 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 (!HasVFPtr && RD->isDynamicClass())
> + for (CXXRecordDecl::method_iterator i = RD->method_begin(),
> + e = RD->method_end();
> + !HasVFPtr && i != e; ++i)
> + HasVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
> + if (!HasVFPtr)
> + return;
> +
> + // MSVC potentially over-aligns the vf-table pointer by giving it
> + // the max alignment of all the non-virtual data in the class. The resulting
> + // layout is essentially { vftbl, { nvdata } }. This is completely
> + // unnecessary, but we're not here to pass judgment.
> + Size += Alignment;
> + updateAlignment(PointerAlignment);
> +}
> +
> +void
> +MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
> + LazyEmptyBase = 0;
> +
> + // Lay out the primary base first.
> + if (PrimaryBase)
> + layoutNonVirtualBase(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();
> + i != e; ++i) {
> + if (i->isVirtual())
> + continue;
> + const CXXRecordDecl *BaseDecl =
> + cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
> + if (BaseDecl != PrimaryBase)
> + layoutNonVirtualBase(BaseDecl);
> + }
> +}
> +
> +void
> +MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
> + const ASTRecordLayout *Layout = RD ? &Context.getASTRecordLayout(RD) : 0;
> +
> + // If we have a lazy empty base we haven't laid out yet, do that now.
> + if (LazyEmptyBase) {
> + const ASTRecordLayout &LazyLayout =
> + Context.getASTRecordLayout(LazyEmptyBase);
> + Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
> + Bases.insert(std::make_pair(LazyEmptyBase, Size));
> + // Empty bases only consume space when followed by another empty base.
> + if (RD && Layout->getNonVirtualSize().isZero())
> + Size++;
> + LazyEmptyBase = 0;
> + }
> +
> + // RD is null when flushing the final lazy base.
> + if (!RD)
> + return;
> +
> + if (Layout->getNonVirtualSize().isZero()) {
> + LazyEmptyBase = RD;
> + return;
> + }
> +
> + // Insert the base here.
> + CharUnits BaseOffset = Size.RoundUpToAlignment(Layout->getAlignment());
> + Bases.insert(std::make_pair(RD, BaseOffset));
> + Size = BaseOffset + Layout->getDataSize();
> + // Note: we don't update alignment here because it was accounted
> + // for during initalization.
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
> + if (!HasVBPtr)
> + VBPtrOffset = CharUnits::fromQuantity(-1);
> + else if (SharedVBPtrBase) {
> + const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase);
> + VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset();
> + } else {
> + updateAlignment(PointerAlignment);
> + VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment);
> +
> + if (Alignment == PointerAlignment && Size % PointerAlignment) {
> + CharUnits x = Size + Alignment + Alignment;
> + Size = VBPtrOffset + Alignment;
> + // Handle strange padding rules. I have no explanation for why the
> + // virtual base is padded in such an odd way. My guess is that they
> + // always Add 2 * Alignment and incorrectly round down to the appropriate
> + // alignment. It's important to get this case correct because it impacts
> + // the layout of the first member of the struct.
> +
> + RecordDecl::field_iterator FieldBegin = RD->field_begin();
> + if (FieldBegin != RD->field_end())
> + Size += CharUnits::fromQuantity(
> + x % getAdjustedFieldInfo(*FieldBegin).second);
> + } else
> + Size += Alignment;
> + }
> +
> + // Flush the lazy empty base.
> + layoutNonVirtualBase(0);
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
> + LastFieldIsNonZeroWidthBitfield = false;
> + for (RecordDecl::field_iterator Field = RD->field_begin(),
> + FieldEnd = RD->field_end();
> + Field != FieldEnd; ++Field)
> + layoutField(*Field);
> + Size = Size.RoundUpToAlignment(Alignment);
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
> + if (FD->isBitField()) {
> + layoutBitField(FD);
> + return;
> + }
> + LastFieldIsNonZeroWidthBitfield = false;
> +
> + std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
> + CharUnits FieldSize = FieldInfo.first;
> + CharUnits FieldAlign = FieldInfo.second;
> +
> + updateAlignment(FieldAlign);
> + if (IsUnion) {
> + placeFieldAtZero();
> + Size = std::max(Size, FieldSize);
> + } else {
> + // Round up the current record size to the field's alignment boundary.
> + CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
> + placeFieldAtOffset(FieldOffset);
> + Size = FieldOffset + FieldSize;
> + }
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
> + unsigned Width = FD->getBitWidthValue(Context);
> + if (Width == 0) {
> + layoutZeroWidthBitField(FD);
> + return;
> + }
> +
> + std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
> + CharUnits FieldSize = FieldInfo.first;
> + CharUnits FieldAlign = FieldInfo.second;
> +
> + // 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);
> +
> + // 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) {
> + placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField);
> + RemainingBitsInField -= Width;
> + return;
> + }
> +
> + LastFieldIsNonZeroWidthBitfield = true;
> + CurrentBitfieldSize = FieldSize;
> + if (IsUnion) {
> + placeFieldAtZero();
> + Size = std::max(Size, FieldSize);
> + // 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);
> + placeFieldAtOffset(FieldOffset);
> + Size = FieldOffset + FieldSize;
> + updateAlignment(FieldAlign);
> + RemainingBitsInField = Context.toBits(FieldSize) - Width;
> + }
> +}
> +
> +void
> +MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
> + // Zero-width bitfields are ignored unless they follow a non-zero-width
> + // bitfield.
> + std::pair<CharUnits, CharUnits> 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;
> + if (IsUnion) {
> + placeFieldAtZero();
> + Size = std::max(Size, FieldSize);
> + } else {
> + // Round up the current record size to the field's alignment boundary.
> + CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
> + placeFieldAtOffset(FieldOffset);
> + Size = FieldOffset;
> + updateAlignment(FieldAlign);
> + }
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
> + if (!HasVBPtr)
> + return;
> +
> + updateAlignment(VirtualAlignment);
> +
> + // Zero-sized v-bases obey the alignment attribute so apply it here. The
> + // alignment attribute is normally accounted for in FinalizeLayout.
> + if (unsigned MaxAlign = RD->getMaxAlignment())
> + updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
> +
> + llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp =
> + computeVtorDispSet(RD);
> +
> + // Iterate through the virtual bases and lay them out.
> + for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
> + e = RD->vbases_end();
> + i != e; ++i) {
> + const CXXRecordDecl *BaseDecl =
> + cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
> + layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl));
> + }
> +}
> +
> +void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
> + bool HasVtordisp) {
> + if (LazyEmptyBase) {
> + const ASTRecordLayout &LazyLayout =
> + Context.getASTRecordLayout(LazyEmptyBase);
> + Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
> + VBases.insert(
> + std::make_pair(LazyEmptyBase, ASTRecordLayout::VBaseInfo(Size, false)));
> + // Empty bases only consume space when followed by another empty base.
> + // The space consumed is in an Alignment sized/aligned block and the v-base
> + // is placed at its alignment offset into the chunk, unless its alignment
> + // is less than the size of a pointer, at which it is placed at pointer
> + // width offset in the chunck. We have no idea why.
> + if (RD && Context.getASTRecordLayout(RD).getNonVirtualSize().isZero())
> + Size = Size.RoundUpToAlignment(Alignment) + PointerSize;
> + LazyEmptyBase = 0;
> + }
> +
> + // RD is null when flushing the final lazy virtual base.
> + if (!RD)
> + return;
> +
> + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
> + if (Layout.getNonVirtualSize().isZero() && !HasVtordisp) {
> + LazyEmptyBase = RD;
> + return;
> + }
> +
> + CharUnits BaseNVSize = Layout.getNonVirtualSize();
> + CharUnits BaseAlign = Layout.getAlignment();
> +
> + if (HasVtordisp)
> + Size = Size.RoundUpToAlignment(Alignment) + PointerSize;
> + Size = Size.RoundUpToAlignment(BaseAlign);
> +
> + // Insert the base here.
> + CharUnits BaseOffset = Size.RoundUpToAlignment(BaseAlign);
> + VBases.insert(
> + std::make_pair(RD, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
> + Size = BaseOffset + BaseNVSize;
> + // Note: we don't update alignment here because it was accounted for in
> + // InitializeLayout.
> +}
> +
> +void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) {
> + // Flush the lazy virtual base.
> + layoutVirtualBase(0, false);
> +
> + if (RD->vbases_begin() == RD->vbases_end() || AlignAfterVBases)
> + Size = Size.RoundUpToAlignment(Alignment);
> +
> + if (Size.isZero())
> + Size = Alignment;
> +}
> +
> +void MicrosoftRecordLayoutBuilder::honorDeclspecAlign(const RecordDecl *RD) {
> + if (unsigned MaxAlign = RD->getMaxAlignment()) {
> + AlignAfterVBases = true;
> + updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
> + Size = Size.RoundUpToAlignment(Alignment);
> + }
> +}
> +
> +static bool
> +RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp,
> + const CXXRecordDecl *RD) {
> + if (HasVtordisp.count(RD))
> + return true;
> + // If any of a virtual bases non-virtual bases (recursively) requires a
> + // vtordisp than so does this virtual base.
> + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
> + e = RD->bases_end();
> + i != e; ++i)
> + if (!i->isVirtual() &&
> + RequiresVtordisp(
> + HasVtordisp,
> + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl())))
> + return true;
> + return false;
> +}
> +
> +llvm::SmallPtrSet<const CXXRecordDecl *, 2>
> +MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
> + llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp;
> +
> + // 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(),
> + e = RD->bases_end();
> + i != e; ++i) {
> + const CXXRecordDecl *BaseDecl =
> + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
> + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
> + for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
> + bi = Layout.getVBaseOffsetsMap().begin(),
> + be = Layout.getVBaseOffsetsMap().end();
> + bi != be; ++bi)
> + if (bi->second.hasVtorDisp())
> + HasVtordisp.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
> + // actually live. The virtual bases with this property will require
> + // vtordisps. In addition, virtual bases that contain non-virtual bases that
> + // define functions we override also require vtordisps, this case is checked
> + // explicitly below.
> + if (RD->hasUserDeclaredConstructor() || RD->hasUserDeclaredDestructor()) {
> + llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
> + // Seed the working set with our non-destructor virtual methods.
> + for (CXXRecordDecl::method_iterator i = RD->method_begin(),
> + e = RD->method_end();
> + i != e; ++i)
> + if ((*i)->isVirtual() && (*i) != RD->getDestructor())
> + Work.insert(*i);
> + while (!Work.empty()) {
> + const CXXMethodDecl *MD = *Work.begin();
> + CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
> + 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());
> + 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);
> + }
> +
> + return HasVtordisp;
> +}
> +
> +/// \brief Get or compute information about the layout of the specified record
> +/// (struct/union/class), which indicates its size and field position
> +/// information.
> +const ASTRecordLayout *
> +ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
> + MicrosoftRecordLayoutBuilder Builder(*this);
> + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
> + Builder.cxxLayout(RD);
> + return new (*this) ASTRecordLayout(
> + *this, Builder.Size, Builder.Alignment,
> + Builder.HasVFPtr && !Builder.PrimaryBase, Builder.HasVFPtr,
> + Builder.HasVBPtr && !Builder.SharedVBPtrBase, Builder.VBPtrOffset,
> + Builder.DataSize, Builder.FieldOffsets.data(),
> + Builder.FieldOffsets.size(), Builder.DataSize,
> + Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase,
> + false, Builder.AlignAfterVBases, Builder.Bases, Builder.VBases);
> + } else {
> + Builder.layout(D);
> + return new (*this) ASTRecordLayout(
> + *this, Builder.Size, Builder.Alignment, Builder.Size,
> + Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
> + }
> +}
> +
> /// getASTRecordLayout - Get or compute information about the layout of the
> /// specified record (struct/union/class), which indicates its size and field
> /// position information.
> @@ -2362,27 +3068,15 @@ ASTContext::getASTRecordLayout(const Rec
> const ASTRecordLayout *Entry = ASTRecordLayouts[D];
> if (Entry) return *Entry;
>
> - const ASTRecordLayout *NewEntry;
> + const ASTRecordLayout *NewEntry = 0;
>
> - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
> + if (isMsLayout(D) && !D->getASTContext().getExternalSource()) {
> + NewEntry = BuildMicrosoftASTRecordLayout(D);
> + } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
> EmptySubobjectMap EmptySubobjects(*this, RD);
> RecordLayoutBuilder Builder(*this, &EmptySubobjects);
> Builder.Layout(RD);
>
> - // MSVC gives the vb-table pointer an alignment equal to that of
> - // the non-virtual part of the structure. That's an inherently
> - // multi-pass operation. If our first pass doesn't give us
> - // adequate alignment, try again with the specified minimum
> - // alignment. This is *much* more maintainable than computing the
> - // alignment in advance in a separately-coded pass; it's also
> - // significantly more efficient in the common case where the
> - // vb-table doesn't need extra padding.
> - if (Builder.VBPtrOffset != CharUnits::fromQuantity(-1) &&
> - (Builder.VBPtrOffset % Builder.NonVirtualAlignment) != 0) {
> - Builder.resetWithTargetAlignment(Builder.NonVirtualAlignment);
> - Builder.Layout(RD);
> - }
> -
> // In certain situations, we are allowed to lay out objects in the
> // tail-padding of base classes. This is ABI-dependent.
> // FIXME: this should be stored in the record layout.
> @@ -2394,11 +3088,12 @@ ASTContext::getASTRecordLayout(const Rec
> skipTailPadding ? Builder.getSize() : Builder.getDataSize();
> CharUnits NonVirtualSize =
> skipTailPadding ? DataSize : Builder.NonVirtualSize;
> -
> NewEntry =
> new (*this) ASTRecordLayout(*this, Builder.getSize(),
> Builder.Alignment,
> Builder.HasOwnVFPtr,
> + RD->isDynamicClass(),
> + Builder.HasOwnVBPtr,
> Builder.VBPtrOffset,
> DataSize,
> Builder.FieldOffsets.data(),
> @@ -2408,6 +3103,7 @@ ASTContext::getASTRecordLayout(const Rec
> EmptySubobjects.SizeOfLargestEmptySubobject,
> Builder.PrimaryBase,
> Builder.PrimaryBaseIsVirtual,
> + true,
> Builder.Bases, Builder.VBases);
> } else {
> RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
> @@ -2564,16 +3260,19 @@ static void DumpCXXRecordLayout(raw_ostr
> IndentLevel++;
>
> const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
> - bool HasVfptr = Layout.hasOwnVFPtr();
> - bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
> + bool HasOwnVFPtr = Layout.hasOwnVFPtr();
> + bool HasOwnVBPtr = Layout.hasOwnVBPtr();
>
> // Vtable pointer.
> - if (RD->isDynamicClass() && !PrimaryBase &&
> - !C.getTargetInfo().getCXXABI().isMicrosoft()) {
> + if (RD->isDynamicClass() && !PrimaryBase && !isMsLayout(RD)) {
> PrintOffset(OS, Offset, IndentLevel);
> OS << '(' << *RD << " vtable pointer)\n";
> + } else if (HasOwnVFPtr) {
> + PrintOffset(OS, Offset, IndentLevel);
> + // vfptr (for Microsoft C++ ABI)
> + OS << '(' << *RD << " vftable pointer)\n";
> }
> -
> +
> // Dump (non-virtual) bases
> for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
> E = RD->bases_end(); I != E; ++I) {
> @@ -2592,12 +3291,8 @@ static void DumpCXXRecordLayout(raw_ostr
> /*IncludeVirtualBases=*/false);
> }
>
> - // vfptr and vbptr (for Microsoft C++ ABI)
> - if (HasVfptr) {
> - PrintOffset(OS, Offset, IndentLevel);
> - OS << '(' << *RD << " vftable pointer)\n";
> - }
> - if (HasVbptr) {
> + // vbptr (for Microsoft C++ ABI)
> + if (HasOwnVBPtr) {
> PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
> OS << '(' << *RD << " vbtable pointer)\n";
> }
> @@ -2650,7 +3345,8 @@ static void DumpCXXRecordLayout(raw_ostr
>
> PrintIndentNoOffset(OS, IndentLevel - 1);
> OS << "[sizeof=" << Layout.getSize().getQuantity();
> - OS << ", dsize=" << Layout.getDataSize().getQuantity();
> + if (!isMsLayout(RD))
> + OS << ", dsize=" << Layout.getDataSize().getQuantity();
> OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
>
> PrintIndentNoOffset(OS, IndentLevel - 1);
> @@ -2677,7 +3373,8 @@ void ASTContext::DumpRecordLayout(const
> OS << "\nLayout: ";
> OS << "<ASTRecordLayout\n";
> OS << " Size:" << toBits(Info.getSize()) << "\n";
> - OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
> + if (!isMsLayout(RD))
> + OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
> OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
> OS << " FieldOffsets: [";
> for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
>
> Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Fri Oct 11 15:19:00 2013
> @@ -696,7 +696,7 @@ CGRecordLayoutBuilder::LayoutNonVirtualB
> }
>
> // Add a vb-table pointer if the layout insists.
> - if (Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1)) {
> + if (Layout.hasOwnVBPtr()) {
> CharUnits VBPtrOffset = Layout.getVBPtrOffset();
> llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
> AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr));
>
> Modified: cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftVBTables.cpp Fri Oct 11 15:19:00 2013
> @@ -54,10 +54,6 @@ void VBTableBuilder::enumerateVBTables(V
> }
> }
>
> -bool VBTableBuilder::hasVBPtr(const CXXRecordDecl *RD) {
> - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
> - return Layout.getVBPtrOffset().getQuantity() != -1;
> -}
>
> void VBTableBuilder::findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
> BaseSubobject CurSubobject,
> @@ -65,10 +61,11 @@ void VBTableBuilder::findUnambiguousPath
> size_t PathsStart = Paths.size();
> bool ReuseVBPtrFromBase = true;
> const CXXRecordDecl *CurBase = CurSubobject.getBase();
> + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase);
>
> // If this base has a vbptr, then we've found a path. These are not full
> // paths, so we don't use CXXBasePath.
> - if (hasVBPtr(CurBase)) {
> + if (Layout.hasOwnVBPtr()) {
> ReuseVBPtrFromBase = false;
> VBTablePath *Info = new VBTablePath(
> VBTableInfo(ReusingBase, CurSubobject, /*GV=*/0));
> @@ -76,7 +73,6 @@ void VBTableBuilder::findUnambiguousPath
> }
>
> // Recurse onto any bases which themselves have virtual bases.
> - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase);
> for (CXXRecordDecl::base_class_const_iterator I = CurBase->bases_begin(),
> E = CurBase->bases_end(); I != E; ++I) {
> const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Oct 11 15:19:00 2013
> @@ -11503,8 +11503,7 @@ Decl *Sema::ActOnIvar(Scope *S,
>
> if (BitWidth) {
> // 6.7.2.1p3, 6.7.2.1p4
> - BitWidth =
> - VerifyBitField(Loc, II, T, /*IsMsStruct=*/false, BitWidth).take();
> + BitWidth = VerifyBitField(Loc, II, T, /*IsMsStruct*/false, BitWidth).take();
> if (!BitWidth)
> D.setInvalidType();
> } else {
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Oct 11 15:19:00 2013
> @@ -4451,6 +4451,13 @@ void Sema::CheckCompletedCXXClass(CXXRec
> }
> }
>
> + // Check to see if we're trying to lay out a struct using the ms_struct
> + // attribute that is dynamic.
> + if (Record->isMsStruct(Context) && Record->isDynamicClass()) {
> + Diag(Record->getLocation(), diag::warn_pragma_ms_struct_failed);
> + Record->dropAttr<MsStructAttr>();
> + }
> +
> // Declare inheriting constructors. We do this eagerly here because:
> // - The standard requires an eager diagnostic for conflicting inheriting
> // constructors from different classes.
>
> Modified: cfe/trunk/test/CodeGen/pr2394.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/pr2394.c?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGen/pr2394.c (original)
> +++ cfe/trunk/test/CodeGen/pr2394.c Fri Oct 11 15:19:00 2013
> @@ -1,4 +1,4 @@
> -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
> +// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -emit-llvm -o - | FileCheck %s
> struct __attribute((packed)) x {int a : 24;};
> int a(struct x* g) {
> // CHECK: load i24
>
> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp Fri Oct 11 15:19:00 2013
> @@ -156,7 +156,9 @@ C::C() {
> // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
> // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
> // CHECK-NEXT: store [2 x i32]* @"\01??_8C at constructors@@7B@", [2 x i32]** %[[vbptr]]
> - // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to %"struct.constructors::A"*
> + // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to i8*
> + // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
> + // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
> // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
> // CHECK-NEXT: br label %[[SKIP_VBASES]]
> //
> @@ -189,7 +191,9 @@ D::D() {
> // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
> // CHECK-NEXT: %[[vbptr:.*]] = bitcast i8* %[[vbptr_off]] to [2 x i32]**
> // CHECK-NEXT: store [2 x i32]* @"\01??_8D at constructors@@7B@", [2 x i32]** %[[vbptr]]
> - // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to %"struct.constructors::A"*
> + // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to i8*
> + // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
> + // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
> // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
> // CHECK-NEXT: br label %[[SKIP_VBASES]]
> //
> @@ -217,7 +221,9 @@ E::E() {
> // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 4
> // CHECK-NEXT: %[[vbptr_C:.*]] = bitcast i8* %[[offs]] to [2 x i32]**
> // CHECK-NEXT: store [2 x i32]* @"\01??_8E at constructors@@7BC at 1@@", [2 x i32]** %[[vbptr_C]]
> - // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to %"struct.constructors::A"*
> + // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to i8*
> + // CHECK-NEXT: getelementptr inbounds i8* %{{.*}}, i64 4
> + // CHECK-NEXT: bitcast i8* %{{.*}} to %"struct.constructors::A"*
> // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A at constructors@@QAE at XZ"(%"struct.constructors::A"* %{{.*}})
> // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C at constructors@@QAE at XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
> // CHECK-NEXT: br label %[[SKIP_VBASES]]
>
> Modified: cfe/trunk/test/Coverage/codegen-next.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Coverage/codegen-next.m?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/test/Coverage/codegen-next.m (original)
> +++ cfe/trunk/test/Coverage/codegen-next.m Fri Oct 11 15:19:00 2013
> @@ -1,5 +1,5 @@
> -// RUN: %clang_cc1 -emit-llvm -fobjc-exceptions -o %t %s
> -// RUN: %clang_cc1 -g -emit-llvm -fobjc-exceptions -o %t %s
> +// RUN: %clang_cc1 -emit-llvm -fobjc-exceptions -triple x86_64-apple-darwin -o %t %s
> +// RUN: %clang_cc1 -g -emit-llvm -fobjc-exceptions -triple x86_64-apple-darwin -o %t %s
>
> // An error could be seen for targeting x86_64-win32;
> //
>
> Modified: cfe/trunk/test/PCH/rdar10830559.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/rdar10830559.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/test/PCH/rdar10830559.cpp (original)
> +++ cfe/trunk/test/PCH/rdar10830559.cpp Fri Oct 11 15:19:00 2013
> @@ -8,7 +8,7 @@
>
> // rdar://10830559
>
> -#pragma ms_struct on
> +//#pragma ms_struct on
>
> template< typename T >
> class Templated
>
> Modified: cfe/trunk/test/Sema/ms_class_layout.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/ms_class_layout.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/test/Sema/ms_class_layout.cpp (original)
> +++ cfe/trunk/test/Sema/ms_class_layout.cpp Fri Oct 11 15:19:00 2013
> @@ -164,7 +164,7 @@ int main() {
> // CHECK-NEXT: 0 | (D vftable pointer)
> // CHECK-NEXT: 8 | double a
>
> -// CHECK-NEXT: sizeof=16, dsize=16, align=8
> +// CHECK-NEXT: sizeof=16, align=8
> // CHECK-NEXT: nvsize=16, nvalign=8
>
> // CHECK: %class.D = type { i32 (...)**, double }
> @@ -173,7 +173,7 @@ int main() {
> // CHECK-NEXT: 0 | (B vftable pointer)
> // CHECK-NEXT: 4 | int b_field
>
> -// CHECK-NEXT: sizeof=8, dsize=8, align=4
> +// CHECK-NEXT: sizeof=8, align=4
> // CHECK-NEXT: nvsize=8, nvalign=4
>
> // CHECK: %class.B = type { i32 (...)**, i32 }
> @@ -185,7 +185,7 @@ int main() {
> // CHECK-NEXT: 8 | int a_field
> // CHECK-NEXT: 12 | char one
>
> -// CHECK-NEXT: sizeof=16, dsize=16, align=4
> +// CHECK-NEXT: sizeof=16, align=4
> // CHECK-NEXT: nvsize=16, nvalign=4
>
> // CHECK: 0 | class C
> @@ -207,7 +207,7 @@ int main() {
> // CHECK-NEXT: 72 | int a_field
> // CHECK-NEXT: 76 | char one
>
> -// CHECK-NEXT: sizeof=80, dsize=80, align=8
> +// CHECK-NEXT: sizeof=80, align=8
> // CHECK-NEXT: nvsize=64, nvalign=8
>
> // CHECK: %class.A = type { %class.B, i32, i8 }
> @@ -237,10 +237,10 @@ int main() {
> // CHECK-NEXT: 88 | int a_field
> // CHECK-NEXT: 92 | char one
>
> -// CHECK-NEXT: sizeof=80, dsize=80, align=8
> +// CHECK-NEXT: sizeof=80, align=8
> // CHECK-NEXT: nvsize=64, nvalign=8
>
> -// CHECK: sizeof=96, dsize=96, align=8
> +// CHECK: sizeof=96, align=8
> // CHECK-NEXT: nvsize=96, nvalign=8
>
> // CHECK: %struct.BaseStruct = type { double, float, %class.C }
> @@ -267,18 +267,18 @@ int main() {
> // CHECK-NEXT: 84 | int b_field
> // CHECK-NEXT: 88 | int a_field
> // CHECK-NEXT: 92 | char one
> -// CHECK-NEXT: sizeof=80, dsize=80, align=8
> +// CHECK-NEXT: sizeof=80, align=8
> // CHECK-NEXT: nvsize=64, nvalign=8
>
> // CHECK: 96 | int x
> -// CHECK-NEXT: sizeof=104, dsize=104, align=8
> +// CHECK-NEXT: sizeof=104, align=8
> // CHECK-NEXT: nvsize=104, nvalign=8
>
> // CHECK: %struct.DerivedStruct = type { %struct.BaseStruct, i32 }
>
> // CHECK: 0 | struct G
> // CHECK-NEXT: 0 | int g_field
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: 0 | struct H
> @@ -288,7 +288,7 @@ int main() {
> // CHECK-NEXT: 8 | class D (virtual base)
> // CHECK-NEXT: 8 | (D vftable pointer)
> // CHECK-NEXT: 16 | double a
> -// CHECK-NEXT: sizeof=24, dsize=24, align=8
> +// CHECK-NEXT: sizeof=24, align=8
> // CHECK-NEXT: nvsize=8, nvalign=4
>
> // CHECK: %struct.H = type { %struct.G, i32*, %class.D }
> @@ -300,7 +300,7 @@ int main() {
> // CHECK-NEXT: 24 | class D (virtual base)
> // CHECK-NEXT: 24 | (D vftable pointer)
> // CHECK-NEXT: 32 | double a
> -// CHECK-NEXT: sizeof=40, dsize=40, align=8
> +// CHECK-NEXT: sizeof=40, align=8
> // CHECK-NEXT: nvsize=24, nvalign=8
>
> // CHECK: %struct.I = type { i32 (...)**, [4 x i8], i32*, double, %class.D }
> @@ -308,12 +308,12 @@ int main() {
>
> // CHECK: 0 | struct L
> // CHECK-NEXT: 0 | int l
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: 0 | struct K
> // CHECK-NEXT: 0 | int k
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: 0 | struct M
> @@ -321,42 +321,42 @@ int main() {
> // CHECK-NEXT: 4 | int m
> // CHECK-NEXT: 8 | struct K (virtual base)
> // CHECK-NEXT: 8 | int k
> -// CHECK-NEXT: sizeof=12, dsize=12, align=4
> +// CHECK-NEXT: sizeof=12, align=4
>
> //CHECK: %struct.M = type { i32*, i32, %struct.K }
> //CHECK: %struct.M.base = type { i32*, i32 }
>
> // CHECK: 0 | struct N
> +// CHECK-NEXT: 0 | (N vftable pointer)
> // CHECK-NEXT: 4 | struct L (base)
> // CHECK-NEXT: 4 | int l
> // CHECK-NEXT: 8 | struct M (base)
> // CHECK-NEXT: 8 | (M vbtable pointer)
> // CHECK-NEXT: 12 | int m
> -// CHECK-NEXT: 0 | (N vftable pointer)
> // CHECK-NEXT: 16 | struct K (virtual base)
> // CHECK-NEXT: 16 | int k
> -// CHECK-NEXT: sizeof=20, dsize=20, align=4
> +// CHECK-NEXT: sizeof=20, align=4
> // CHECK-NEXT: nvsize=16, nvalign=4
>
> //CHECK: %struct.N = type { i32 (...)**, %struct.L, %struct.M.base, %struct.K }
>
> -// FIXME: MSVC place struct H at offset 8.
> // CHECK: 0 | struct O
> -// CHECK-NEXT: 4 | struct H (base)
> -// CHECK-NEXT: 4 | struct G (base)
> -// CHECK-NEXT: 4 | int g_field
> -// CHECK-NEXT: 8 | (H vbtable pointer)
> -// CHECK-NEXT: 12 | struct G (base)
> -// CHECK-NEXT: 12 | int g_field
> // CHECK-NEXT: 0 | (O vftable pointer)
> -// CHECK-NEXT: 16 | class D (virtual base)
> -// CHECK-NEXT: 16 | (D vftable pointer)
> -// CHECK-NEXT: 24 | double a
> -// CHECK-NEXT: sizeof=32, dsize=32, align=8
> -// CHECK-NEXT: nvsize=16, nvalign=4
> +// CHECK-NEXT: 8 | struct H (base)
> +// CHECK-NEXT: 8 | struct G (base)
> +// CHECK-NEXT: 8 | int g_field
> +// CHECK-NEXT: 12 | (H vbtable pointer)
> +// CHECK-NEXT: 16 | struct G (base)
> +// CHECK-NEXT: 16 | int g_field
> +// CHECK-NEXT: 24 | class D (virtual base)
> +// CHECK-NEXT: 24 | (D vftable pointer)
> +// CHECK-NEXT: 32 | double a
> +// CHECK-NEXT: | [sizeof=40, align=8
> +// CHECK-NEXT: | nvsize=24, nvalign=8]
> +
> +// CHECK: struct.O = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8], %class.D }
> +// CHECK: struct.O.base = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8] }
>
> -//CHECK: %struct.O = type { i32 (...)**, %struct.H.base, %struct.G, %class.D }
> -//CHECK: %struct.O.base = type { i32 (...)**, %struct.H.base, %struct.G }
>
> // CHECK: 0 | struct P
> // CHECK-NEXT: 0 | struct M (base)
> @@ -367,20 +367,20 @@ int main() {
> // CHECK-NEXT: 12 | int k
> // CHECK-NEXT: 16 | struct L (virtual base)
> // CHECK-NEXT: 16 | int l
> -// CHECK-NEXT: sizeof=20, dsize=20, align=4
> +// CHECK-NEXT: sizeof=20, align=4
> // CHECK-NEXT: nvsize=12, nvalign=4
>
> //CHECK: %struct.P = type { %struct.M.base, i32, %struct.K, %struct.L }
>
> // CHECK: 0 | struct R (empty)
> -// CHECK-NEXT: sizeof=1, dsize=0, align=1
> +// CHECK-NEXT: sizeof=1, align=1
> // CHECK-NEXT: nvsize=0, nvalign=1
>
> //CHECK: %struct.R = type { i8 }
>
> // CHECK: 0 | struct f
> // CHECK-NEXT: 0 | (f vftable pointer)
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: 0 | struct s
> @@ -390,12 +390,12 @@ int main() {
> // CHECK-NEXT: 12 | (vtordisp for vbase f)
> // CHECK-NEXT: 16 | struct f (virtual base)
> // CHECK-NEXT: 16 | (f vftable pointer)
> -// CHECK-NEXT: sizeof=20, dsize=20, align=4
> +// CHECK-NEXT: sizeof=20, align=4
> // CHECK-NEXT: nvsize=12, nvalign=4
>
> // CHECK: 0 | class IA
> // CHECK-NEXT: 0 | (IA vftable pointer)
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: 0 | class ICh
> @@ -404,7 +404,7 @@ int main() {
> // CHECK-NEXT: 8 | (vtordisp for vbase IA)
> // CHECK-NEXT: 12 | class IA (virtual base)
> // CHECK-NEXT: 12 | (IA vftable pointer)
> -// CHECK-NEXT: sizeof=16, dsize=16, align=4
> +// CHECK-NEXT: sizeof=16, align=4
> // CHECK-NEXT: nvsize=8, nvalign=4
>
> // CHECK: 0 | struct sd
> @@ -424,7 +424,7 @@ int main() {
> // CHECK-NEXT: 40 | class ICh (virtual base)
> // CHECK-NEXT: 40 | (ICh vftable pointer)
> // CHECK-NEXT: 44 | (ICh vbtable pointer)
> -// CHECK-NEXT: sizeof=48, dsize=48, align=4
> +// CHECK-NEXT: sizeof=48, align=4
> // CHECK-NEXT: nvsize=12, nvalign=4
>
> // CHECK: %struct.f = type { i32 (...)** }
> @@ -435,14 +435,14 @@ int main() {
>
> // CHECK: 0 | struct AV
> // CHECK-NEXT: 0 | (AV vftable pointer)
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
>
> // CHECK: 0 | struct BV
> // CHECK-NEXT: 0 | struct AV (primary base)
> // CHECK-NEXT: 0 | (AV vftable pointer)
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
>
> @@ -452,7 +452,7 @@ int main() {
> // CHECK-NEXT: 8 | struct BV (virtual base)
> // CHECK-NEXT: 8 | struct AV (primary base)
> // CHECK-NEXT: 8 | (AV vftable pointer)
> -// CHECK-NEXT: sizeof=12, dsize=12, align=4
> +// CHECK-NEXT: sizeof=12, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: %struct.AV = type { i32 (...)** }
> @@ -464,7 +464,7 @@ int main() {
> // CHECK-NEXT: 0 | struct BV (primary base)
> // CHECK-NEXT: 0 | struct AV (primary base)
> // CHECK-NEXT: 0 | (AV vftable pointer)
> -// CHECK-NEXT: sizeof=4, dsize=4, align=4
> +// CHECK-NEXT: sizeof=4, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
>
> // CHECK: %struct.DV = type { %struct.BV }
> @@ -480,14 +480,14 @@ int main() {
> // CHECK-NEXT: 12 | struct BV (virtual base)
> // CHECK-NEXT: 12 | struct AV (primary base)
> // CHECK-NEXT: 12 | (AV vftable pointer)
> -// CHECK-NEXT: sizeof=16, dsize=16, align=4
> +// CHECK-NEXT: sizeof=16, align=4
> // CHECK-NEXT: nvsize=8, nvalign=4
>
> // CHECK: %struct.EV = type { %struct.DV, %struct.CV.base, [4 x i8], %struct.BV }
> // CHECK: %struct.EV.base = type { %struct.DV, %struct.CV.base }
>
> // Overriding a method means that all the vbases containing that
> -// method need a vtordisp.
> +// method need a vtordisp. Note: this code will cause an error in cl.exe.
> namespace test1 {
> struct A { virtual void foo(); };
> struct B : A {};
> @@ -503,6 +503,6 @@ namespace test1 {
> // CHECK-NEXT: 16 | struct test1::B (virtual base)
> // CHECK-NEXT: 16 | struct test1::A (primary base)
> // CHECK-NEXT: 16 | (A vftable pointer)
> -// CHECK-NEXT: sizeof=20, dsize=20, align=4
> +// CHECK-NEXT: sizeof=20, align=4
> // CHECK-NEXT: nvsize=4, nvalign=4
> }
>
> Modified: cfe/trunk/test/SemaCXX/ms_struct.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ms_struct.cpp?rev=192494&r1=192493&r2=192494&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/ms_struct.cpp (original)
> +++ cfe/trunk/test/SemaCXX/ms_struct.cpp Fri Oct 11 15:19:00 2013
> @@ -6,7 +6,6 @@
> struct A {
> unsigned long a:4;
> unsigned char b;
> - A();
> };
>
> struct B : public A {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list