diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp | 419 |
1 files changed, 316 insertions, 103 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp index 5636a6f0f64a..bbd3fc016017 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp @@ -44,7 +44,7 @@ struct BaseSubobjectInfo { bool IsVirtual; /// Bases - Information about the base subobjects. - llvm::SmallVector<BaseSubobjectInfo*, 4> Bases; + SmallVector<BaseSubobjectInfo*, 4> Bases; /// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base /// of this base info (if one exists). @@ -64,7 +64,7 @@ class EmptySubobjectMap { const CXXRecordDecl *Class; /// EmptyClassOffsets - A map from offsets to empty record decls. - typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; + typedef SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy; EmptyClassOffsetsMapTy EmptyClassOffsets; @@ -556,7 +556,7 @@ protected: /// \brief The alignment if attribute packed is not used. CharUnits UnpackedAlignment; - llvm::SmallVector<uint64_t, 16> FieldOffsets; + SmallVector<uint64_t, 16> FieldOffsets; /// Packed - Whether the record is packed or not. unsigned Packed : 1; @@ -592,6 +592,9 @@ protected: /// out is virtual. bool PrimaryBaseIsVirtual; + /// VBPtrOffset - Virtual base table offset. Only for MS layout. + CharUnits VBPtrOffset; + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; /// Bases - base classes and their offsets in the record. @@ -613,16 +616,17 @@ protected: llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap - *EmptySubobjects) + *EmptySubobjects, CharUnits Alignment) : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), - Alignment(CharUnits::One()), UnpackedAlignment(Alignment), + Alignment(Alignment), UnpackedAlignment(Alignment), Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), ZeroLengthBitfield(0), PrimaryBase(0), - PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } + PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)), + FirstNearlyEmptyVBase(0) { } void Layout(const RecordDecl *D); void Layout(const CXXRecordDecl *D); @@ -633,6 +637,8 @@ protected: void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize, bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); + void MSLayoutVirtualBases(const CXXRecordDecl *RD); + void MSLayout(const CXXRecordDecl *RD); /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator; @@ -663,7 +669,7 @@ protected: void SelectPrimaryVBase(const CXXRecordDecl *RD); - virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; + CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. @@ -713,6 +719,8 @@ protected: void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); } void setSize(uint64_t NewSize) { Size = NewSize; } + CharUnits getAligment() const { return Alignment; } + CharUnits getDataSize() const { assert(DataSize % Context.getCharWidth() == 0); return Context.toCharUnitsFromBits(DataSize); @@ -722,6 +730,11 @@ protected: void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); } void setDataSize(uint64_t NewSize) { DataSize = NewSize; } + bool HasVBPtr(const CXXRecordDecl *RD) const; + bool HasNewVirtualFunction(const CXXRecordDecl *RD) const; + + /// Add vbptr or vfptr to layout. + void AddVPointer(); RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT @@ -729,6 +742,8 @@ public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); virtual ~RecordLayoutBuilder() { } + + CharUnits GetVBPtrOffset() const { return VBPtrOffset; } }; } // end anonymous namespace @@ -765,7 +780,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { CharUnits RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { - return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + return Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); } /// DeterminePrimaryBase - Determine the primary base of the given class. @@ -825,7 +840,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { setDataSize(getSize()); CharUnits UnpackedBaseAlign = - Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; // The maximum field alignment overrides base align. @@ -1046,6 +1061,45 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, } } +void RecordLayoutBuilder::AddVPointer() { + CharUnits PtrWidth = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + setSize(getSize() + PtrWidth); + setDataSize(getSize()); + + if (Alignment > PtrWidth) { + setSize(getSize() + (Alignment - PtrWidth)); + setDataSize(getSize()); + } +} + +bool +RecordLayoutBuilder::HasNewVirtualFunction(const CXXRecordDecl *RD) const { + for (CXXRecordDecl::method_iterator method = RD->method_begin(); + method != RD->method_end(); + ++method) { + if (method->isVirtual() && + !method->size_overridden_methods()) { + return true; + } + } + return false; +} + +bool +RecordLayoutBuilder::HasVBPtr(const CXXRecordDecl *RD) const { + if (!RD->getNumBases()) + return false; + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (!I->isVirtual()) { + return false; + } + } + return true; +} + void RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass) { @@ -1157,6 +1211,11 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { IsMsStruct = D->hasAttr<MsStructAttr>(); + // Honor the default struct packing maximum alignment flag. + if (unsigned DefaultMaxFieldAlignment = Context.getLangOptions().PackStruct) { + MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); + } + // mac68k alignment supersedes maximum field alignment and attribute aligned, // and forces all structures to have 2-byte alignment. The IBM docs on it // allude to additional (more complicated) semantics, especially with regard @@ -1184,6 +1243,11 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) { } void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { + if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) { + MSLayout(RD); + return ; + } + InitializeLayout(RD); // Lay out the vtable and the non-virtual bases. @@ -1193,7 +1257,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { NonVirtualSize = Context.toCharUnitsFromBits( llvm::RoundUpToAlignment(getSizeInBits(), - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); NonVirtualAlignment = Alignment; // Lay out the virtual bases and add the primary virtual base offsets. @@ -1242,10 +1306,9 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { } InitializeLayout(D); - ObjCInterfaceDecl *OI = const_cast<ObjCInterfaceDecl*>(D); // Layout each ivar sequentially. - for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) + for (const ObjCIvarDecl *IVD = D->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) LayoutField(IVD); // Finally, round the size of the total struct up to the alignment of the @@ -1271,8 +1334,8 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { continue; // FIXME. streamline these conditions into a simple one. else if (Context.BitfieldFollowsBitfield(FD, LastFD) || - Context.BitfieldFollowsNoneBitfield(FD, LastFD) || - Context.NoneBitfieldFollowsBitfield(FD, LastFD)) { + Context.BitfieldFollowsNonBitfield(FD, LastFD) || + Context.NonBitfieldFollowsBitfield(FD, LastFD)) { // 1) Adjacent bit fields are packed into the same 1-, 2-, or // 4-byte allocation unit if the integral types are the same // size and if the next bit field fits into the current @@ -1299,14 +1362,14 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { if (TypeSizeLastFD != TypeSize) { if (RemainingInAlignment && LastFD && LastFD->isBitField() && - LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + LastFD->getBitWidthValue(Context)) { // If previous field was a bitfield with some remaining unfilled // bits, pad the field so current field starts on its type boundary. uint64_t FieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); setSize(std::max(getSizeInBits(), getDataSizeInBits())); RemainingInAlignment = 0; } @@ -1325,13 +1388,12 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { uint64_t NewSizeInBits = llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign); setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; setSize(std::max(getSizeInBits(), getDataSizeInBits())); } if (FD->isBitField()) { - uint64_t FieldSize = - FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = FD->getBitWidthValue(Context); assert (FieldSize > 0 && "LayoutFields - ms_struct layout"); if (RemainingInAlignment < FieldSize) RemainingInAlignment = TypeSize - FieldSize; @@ -1340,8 +1402,7 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } } else if (FD->isBitField()) { - uint64_t FieldSize = - FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = FD->getBitWidthValue(Context); std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(FD->getType()); uint64_t TypeSize = FieldInfo.first; @@ -1349,18 +1410,23 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } LastFD = FD; } + else if (!Context.getTargetInfo().useBitFieldTypeAlignment() && + Context.getTargetInfo().useZeroLengthBitfieldAlignment()) { + FieldDecl *FD = (*Field); + if (FD->isBitField() && FD->getBitWidthValue(Context) == 0) + ZeroLengthBitfield = FD; + } LayoutField(*Field); } if (IsMsStruct && RemainingInAlignment && - LastFD && LastFD->isBitField() && - LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) { // If we ended a bitfield before the full length of the type then // pad the struct out to the full length of the last type. uint64_t FieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); setSize(std::max(getSizeInBits(), getDataSizeInBits())); } } @@ -1405,15 +1471,15 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, setDataSize(std::max(getDataSizeInBits(), FieldSize)); FieldOffset = 0; } else { - // The bitfield is allocated starting at the next offset aligned appropriately - // for T', with length n bits. + // The bitfield is allocated starting at the next offset aligned + // appropriately for T', with length n bits. FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(TypeAlign)); uint64_t NewSizeInBits = FieldOffset + FieldSize; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; } @@ -1434,7 +1500,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset; - uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = D->getBitWidthValue(Context); std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; @@ -1443,21 +1509,32 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // This check is needed for 'long long' in -m32 mode. if (IsMsStruct && (TypeSize > FieldAlign)) FieldAlign = TypeSize; - + if (ZeroLengthBitfield) { - // If a zero-length bitfield is inserted after a bitfield, - // and the alignment of the zero-length bitfield is - // greater than the member that follows it, `bar', `bar' - // will be aligned as the type of the zero-length bitfield. - if (ZeroLengthBitfield != D) { - std::pair<uint64_t, unsigned> FieldInfo = - Context.getTypeInfo(ZeroLengthBitfield->getType()); - unsigned ZeroLengthBitfieldAlignment = FieldInfo.second; - // Ignore alignment of subsequent zero-length bitfields. - if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) - FieldAlign = ZeroLengthBitfieldAlignment; - if (FieldSize) - ZeroLengthBitfield = 0; + std::pair<uint64_t, unsigned> FieldInfo; + unsigned ZeroLengthBitfieldAlignment; + if (IsMsStruct) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + if (ZeroLengthBitfield != D) { + FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType()); + ZeroLengthBitfieldAlignment = FieldInfo.second; + // Ignore alignment of subsequent zero-length bitfields. + if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) + FieldAlign = ZeroLengthBitfieldAlignment; + if (FieldSize) + ZeroLengthBitfield = 0; + } + } else { + // The alignment of a zero-length bitfield affects the alignment + // of the next member. The alignment is the max of the zero + // length bitfield's alignment and a target specific fixed value. + unsigned ZeroLengthBitfieldBoundary = + Context.getTargetInfo().getZeroLengthBitfieldBoundary(); + if (ZeroLengthBitfieldBoundary > FieldAlign) + FieldAlign = ZeroLengthBitfieldBoundary; } } @@ -1470,10 +1547,11 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // was unnecessary (-Wpacked). unsigned UnpackedFieldAlign = FieldAlign; uint64_t UnpackedFieldOffset = FieldOffset; - if (!Context.Target.useBitFieldTypeAlignment()) + if (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield) UnpackedFieldAlign = 1; - if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) + if (FieldPacked || + (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield)) FieldAlign = 1; FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment()); @@ -1494,10 +1572,14 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, UnpackedFieldAlign); - // Padding members don't affect overall alignment. - if (!D->getIdentifier()) + // Padding members don't affect overall alignment, unless zero length bitfield + // alignment is enabled. + if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment()) FieldAlign = UnpackedFieldAlign = 1; + if (!IsMsStruct) + ZeroLengthBitfield = 0; + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); @@ -1512,7 +1594,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { uint64_t NewSizeInBits = FieldOffset + FieldSize; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; } @@ -1552,25 +1634,36 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { unsigned AS = RT->getPointeeType().getAddressSpace(); FieldSize = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS)); FieldAlign = - Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS)); } else { std::pair<CharUnits, CharUnits> FieldInfo = Context.getTypeInfoInChars(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; - + if (ZeroLengthBitfield) { - // If a zero-length bitfield is inserted after a bitfield, - // and the alignment of the zero-length bitfield is - // greater than the member that follows it, `bar', `bar' - // will be aligned as the type of the zero-length bitfield. - std::pair<CharUnits, CharUnits> FieldInfo = - Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); - CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; - if (ZeroLengthBitfieldAlignment > FieldAlign) - FieldAlign = ZeroLengthBitfieldAlignment; + CharUnits ZeroLengthBitfieldBoundary = + Context.toCharUnitsFromBits( + Context.getTargetInfo().getZeroLengthBitfieldBoundary()); + if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); + CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; + if (ZeroLengthBitfieldAlignment > FieldAlign) + FieldAlign = ZeroLengthBitfieldAlignment; + } else if (ZeroLengthBitfieldBoundary > FieldAlign) { + // Align 'bar' based on a fixed alignment specified by the target. + assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() && + "ZeroLengthBitfieldBoundary should only be used in conjunction" + " with useZeroLengthBitfieldAlignment."); + FieldAlign = ZeroLengthBitfieldBoundary; + } ZeroLengthBitfield = 0; } @@ -1641,6 +1734,104 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { UpdateAlignment(FieldAlign, UnpackedFieldAlign); } +void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) { + + if (!RD->getNumVBases()) + return; + + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + + const CXXRecordDecl* BaseDecl = I->getType()->getAsCXXRecordDecl(); + const BaseSubobjectInfo* BaseInfo = VirtualBaseInfo.lookup(BaseDecl); + + assert(BaseInfo && "Did not find virtual base info!"); + + LayoutVirtualBase(BaseInfo); + } +} + +void RecordLayoutBuilder::MSLayout(const CXXRecordDecl *RD) { + + bool IsVBPtrAddedToLayout = false; + + InitializeLayout(RD); + + if (HasVBPtr(RD)) { + // If all bases are virtual and the class declares a new virtual function, + // MSVC builds a vfptr. + if (HasNewVirtualFunction(RD)) { + AddVPointer(); + } + + VBPtrOffset = getSize(); + AddVPointer(); + IsVBPtrAddedToLayout = true; + + ComputeBaseSubobjectInfo(RD); + } else { + LayoutNonVirtualBases(RD); + } + + if (RD->getNumVBases() && + !IsVBPtrAddedToLayout) { + // Add vbptr. + VBPtrOffset = getSize(); + AddVPointer(); + } + + LayoutFields(RD); + + NonVirtualSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(getSizeInBits(), + Context.getTargetInfo().getCharAlign())); + NonVirtualAlignment = Alignment; + + if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) { + CharUnits AlignMember = + NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize; + + setSize(getSize() + AlignMember); + setDataSize(getSize()); + + NonVirtualSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(getSizeInBits(), + Context.getTargetInfo().getCharAlign())); + } + + MSLayoutVirtualBases(RD); + + VisitedVirtualBases.clear(); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + if (!RD->getNumVBases()) + FinishLayout(RD); + +#ifndef NDEBUG + // Check that we have base offsets for all 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 = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); + } +#endif +} + void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // In C++, records cannot be of size 0. if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) { @@ -1663,7 +1854,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment))); - unsigned CharBitNum = Context.Target.getCharWidth(); + unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { // Warn if padding was introduced to the struct/class/union. if (getSizeInBits() > UnpaddedSize) { @@ -1718,7 +1909,12 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, if (isa<ObjCIvarDecl>(D)) return; - unsigned CharBitNum = Context.Target.getCharWidth(); + // Don't warn about structs created without a SourceLocation. This can + // be done by clients of the AST, such as codegen. + if (D->getLocation().isInvalid()) + return; + + unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); // Warn if padding was introduced to the struct/class. if (!IsUnion && Offset > UnpaddedOffset) { @@ -1802,36 +1998,18 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) { return Context.getDiagnostics().Report(Loc, DiagID); } -namespace { - // This class implements layout specific to the Microsoft ABI. - class MSRecordLayoutBuilder : public RecordLayoutBuilder { - public: - MSRecordLayoutBuilder(const ASTContext& Ctx, - EmptySubobjectMap *EmptySubobjects) : - RecordLayoutBuilder(Ctx, EmptySubobjects) {} - - virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; - }; -} - -CharUnits -MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { - // We should reserve space for two pointers if the class has both - // virtual functions and virtual bases. - CharUnits PointerWidth = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); - if (RD->isPolymorphic() && RD->getNumVBases() > 0) - return 2 * PointerWidth; - return PointerWidth; -} - /// getASTRecordLayout - 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::getASTRecordLayout(const RecordDecl *D) const { + // These asserts test different things. A record has a definition + // as soon as we begin to parse the definition. That definition is + // not a complete definition (which is what isDefinition() tests) + // until we *finish* parsing the definition. D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); + assert(D->isCompleteDefinition() && "Cannot layout type before complete!"); // Look up this layout, if already laid out, return what we have. // Note that we can't save a reference to the entry because this function @@ -1844,25 +2022,44 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { EmptySubobjectMap EmptySubobjects(*this, RD); - // When compiling for Microsoft, use the special MS builder. llvm::OwningPtr<RecordLayoutBuilder> Builder; - switch (Target.getCXXABI()) { - default: - Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects)); - break; - case CXXABI_Microsoft: - Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects)); - } + CharUnits TargetAlign = CharUnits::One(); + + Builder.reset(new RecordLayoutBuilder(*this, + &EmptySubobjects, + TargetAlign)); + // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder> RecordBuilderCleanup(Builder.get()); Builder->Layout(RD); + TargetAlign = Builder->getAligment(); + + if (getTargetInfo().getCXXABI() == CXXABI_Microsoft && + TargetAlign.getQuantity() > 4) { + // MSVC rounds the vtable pointer to the struct alignment in what must + // be a multi-pass operation. For now, let the builder figure out the + // alignment and recalculate the layout once its known. + Builder.reset(new RecordLayoutBuilder(*this, + &EmptySubobjects, + TargetAlign)); + + Builder->Layout(RD); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder> + RecordBuilderCleanup(Builder.get()); + } + // FIXME: This is not always correct. See the part about bitfields at // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. - bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); + // This does not affect the calculations of MSVC layouts + bool IsPODForThePurposeOfLayout = + (getTargetInfo().getCXXABI() == CXXABI_Microsoft) || + cast<CXXRecordDecl>(D)->isPOD(); // FIXME: This should be done in FinalizeLayout. CharUnits DataSize = @@ -1873,6 +2070,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { NewEntry = new (*this) ASTRecordLayout(*this, Builder->getSize(), Builder->Alignment, + Builder->GetVBPtrOffset(), DataSize, Builder->FieldOffsets.data(), Builder->FieldOffsets.size(), @@ -1883,7 +2081,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { Builder->PrimaryBaseIsVirtual, Builder->Bases, Builder->VBases); } else { - RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One()); Builder.Layout(D); NewEntry = @@ -1915,8 +2113,8 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { return Entry; } -/// getInterfaceLayoutImpl - Get or compute information about the -/// layout of the given interface. +/// getObjCLayout - Get or compute information about the layout of the +/// given interface. /// /// \param Impl - If given, also include the layout of the interface's /// implementation. This may differ by including synthesized ivars. @@ -1942,7 +2140,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, return getObjCLayout(D, 0); } - RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One()); Builder.Layout(D); const ASTRecordLayout *NewEntry = @@ -1957,13 +2155,13 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, return *NewEntry; } -static void PrintOffset(llvm::raw_ostream &OS, +static void PrintOffset(raw_ostream &OS, CharUnits Offset, unsigned IndentLevel) { OS << llvm::format("%4d | ", Offset.getQuantity()); OS.indent(IndentLevel * 2); } -static void DumpCXXRecordLayout(llvm::raw_ostream &OS, +static void DumpCXXRecordLayout(raw_ostream &OS, const CXXRecordDecl *RD, const ASTContext &C, CharUnits Offset, unsigned IndentLevel, @@ -1982,12 +2180,22 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, IndentLevel++; const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1); // Vtable pointer. if (RD->isDynamicClass() && !PrimaryBase) { PrintOffset(OS, Offset, IndentLevel); - OS << '(' << RD << " vtable pointer)\n"; + OS << '(' << *RD << " vtable pointer)\n"; + } + + if (HasVbptr && !PrimaryBase) { + PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); + OS << '(' << *RD << " vbtable pointer)\n"; + + // one vbtable per class + HasVbptr = false; } + // Dump (non-virtual) bases for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { @@ -2005,6 +2213,11 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, Base == PrimaryBase ? "(primary base)" : "(base)", /*IncludeVirtualBases=*/false); } + // vbptr + if (HasVbptr) { + PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); + OS << '(' << *RD << " vbtable pointer)\n"; + } // Dump fields. uint64_t FieldNo = 0; @@ -2024,7 +2237,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, } PrintOffset(OS, FieldOffset, IndentLevel); - OS << Field->getType().getAsString() << ' ' << Field << '\n'; + OS << Field->getType().getAsString() << ' ' << *Field << '\n'; } if (!IncludeVirtualBases) @@ -2053,7 +2266,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, } void ASTContext::DumpRecordLayout(const RecordDecl *RD, - llvm::raw_ostream &OS) const { + raw_ostream &OS) const { const ASTRecordLayout &Info = getASTRecordLayout(RD); if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) |