From: Timur Iskhodzhanov Date: Fri, 27 Sep 2013 14:48:01 +0000 (+0000) Subject: Abstract out the emission of vtables, add basic support for vtable emission when... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a53d7a0259ff88f78ba8ecac7d0cb3ea96302b1d;p=clang Abstract out the emission of vtables, add basic support for vtable emission when using -cxx-abi microsoft Reviewed at http://llvm-reviews.chandlerc.com/D1532 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191523 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index 34864fa192..b9eb4f0006 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -106,8 +106,16 @@ public: raw_ostream &) = 0; virtual void mangleReferenceTemporary(const VarDecl *D, raw_ostream &) = 0; + // FIXME: Some of these objects only exist in select ABIs. We should probably + // only declare them in ABI-specific manglers? virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0; + /// \brief Mangle vftable symbols. Only a subset of the bases along the path + /// to the vftable are included in the name. It's up to the caller to pick + /// them correctly. + virtual void mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef BasePath, + raw_ostream &Out) = 0; virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0; /// \brief Mangle vbtable symbols. Only a subset of the bases along the path diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index 2ea455e1fa..877ff407a1 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -329,13 +329,6 @@ public: VTableContext(ASTContext &Context); ~VTableContext(); - bool isMicrosoftABI() const { - // FIXME: Currently, this method is only used in the VTableContext and - // VTableBuilder code which is ABI-specific. Probably we can remove it - // when we add a layer of abstraction for vtable generation. - return IsMicrosoftABI; - } - const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { computeVTableRelatedInformation(RD); assert(VTableLayouts.count(RD) && "No layout for this record decl!"); @@ -377,11 +370,13 @@ unsigned GetVBTableIndex(const CXXRecordDecl *Derived, struct VFPtrInfo { typedef SmallVector BasePath; + // Don't pass the PathToMangle as it should be calculated later. VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr) : VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset), PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) { } + // Don't pass the PathToMangle as it should be calculated later. VFPtrInfo(uint64_t VBTableIndex, const CXXRecordDecl *LastVBase, CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr, CharUnits VFPtrFullOffset) @@ -404,9 +399,13 @@ struct VFPtrInfo { CharUnits VFPtrOffset; /// This holds the base classes path from the complete type to the first base - /// with the given vfptr offset. + /// with the given vfptr offset, in the base-to-derived order. BasePath PathToBaseWithVFPtr; + /// This holds the subset of records that need to be mangled into the vftable + /// symbol name in order to get a unique name, in the derived-to-base order. + BasePath PathToMangle; + /// This is the full offset of the vfptr from the start of the complete type. CharUnits VFPtrFullOffset; }; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index cb3c920bcf..13923ae8f6 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -137,6 +137,9 @@ public: raw_ostream &); void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &); + void mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef BasePath, + raw_ostream &Out); void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &); void mangleCXXVBTable(const CXXRecordDecl *Derived, @@ -3772,6 +3775,14 @@ void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, Mangler.mangleNameOrStandardSubstitution(RD); } +void +ItaniumMangleContext::mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef BasePath, + raw_ostream &Out) { + llvm_unreachable( + "The Itanium C++ ABI does not have vftables (use vtables instead)!"); +} + void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &Out) { // ::= TT # VTT structure diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index cf68cdd1d5..211e6e7931 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -188,6 +188,9 @@ public: raw_ostream &); virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &); + virtual void mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef BasePath, + raw_ostream &Out); virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &); virtual void mangleCXXVBTable(const CXXRecordDecl *Derived, @@ -1900,16 +1903,26 @@ void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &Out) { + llvm_unreachable( + "The Microsoft C++ ABI does not have vtables (use vftables instead)!"); +} + +void MicrosoftMangleContext::mangleCXXVFTable( + const CXXRecordDecl *Derived, ArrayRef BasePath, + raw_ostream &Out) { // ::= ?_7 // [] @ // NOTE: here is always 'B' (const). // is always '6' for vftables. MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "\01??_7"; - Mangler.mangleName(RD); - Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const. - // TODO: If the class has more than one vtable, mangle in the class it came - // from. + Mangler.mangleName(Derived); + Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const. + for (ArrayRef::iterator I = BasePath.begin(), + E = BasePath.end(); + I != E; ++I) { + Mangler.mangleName(*I); + } Mangler.getStream() << '@'; } diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index ffa01681c5..c28aeefd99 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -999,10 +999,6 @@ public: dumpLayout(llvm::errs()); } - bool isMicrosoftABI() const { - return VTables.isMicrosoftABI(); - } - uint64_t getNumThunks() const { return Thunks.size(); } @@ -1157,7 +1153,7 @@ void VTableBuilder::ComputeThisAdjustments() { // Add it. VTableThunks[VTableIndex].This = ThisAdjustment; - if (isa(MD) && !isMicrosoftABI()) { + if (isa(MD)) { // Add an adjustment for the deleting destructor as well. VTableThunks[VTableIndex + 1].This = ThisAdjustment; } @@ -1188,8 +1184,6 @@ void VTableBuilder::ComputeThisAdjustments() { break; case VTableComponent::CK_DeletingDtorPointer: // We've already added the thunk when we saw the complete dtor pointer. - // FIXME: check how this works in the Microsoft ABI - // while working on the multiple inheritance patch. continue; } @@ -1326,15 +1320,9 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD, assert(ReturnAdjustment.isEmpty() && "Destructor can't have return adjustment!"); - // FIXME: Should probably add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - // Add both the complete destructor and the deleting destructor. - Components.push_back(VTableComponent::MakeCompleteDtor(DD)); - Components.push_back(VTableComponent::MakeDeletingDtor(DD)); - } else { - // Add the scalar deleting destructor. - Components.push_back(VTableComponent::MakeDeletingDtor(DD)); - } + // Add both the complete destructor and the deleting destructor. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); } else { // Add the return adjustment if necessary. if (!ReturnAdjustment.isEmpty()) @@ -1693,18 +1681,12 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, if (Base.getBase() == MostDerivedClass) VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); - // FIXME: Should probably add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - // Add the offset to top. - CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; - Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); + // Add the offset to top. + CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; + Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); - // Next, add the RTTI. - Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); - } else { - // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere - // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway. - } + // Next, add the RTTI. + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); uint64_t AddressPoint = Components.size(); @@ -1722,16 +1704,10 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, const CXXMethodDecl *MD = I->first; const MethodInfo &MI = I->second; if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - // FIXME: Should probably add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] - = MI.VTableIndex - AddressPoint; - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] - = MI.VTableIndex + 1 - AddressPoint; - } else { - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] - = MI.VTableIndex - AddressPoint; - } + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] + = MI.VTableIndex - AddressPoint; + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] + = MI.VTableIndex + 1 - AddressPoint; } else { MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint; } @@ -2044,8 +2020,6 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << DD->getQualifiedNameAsString(); if (IsComplete) Out << "() [complete]"; - else if (isMicrosoftABI()) - Out << "() [scalar deleting]"; else Out << "() [deleting]"; @@ -2230,18 +2204,11 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { MD); if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - // FIXME: Should add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - GlobalDecl GD(DD, Dtor_Complete); - assert(MethodVTableIndices.count(GD)); - uint64_t VTableIndex = MethodVTableIndices[GD]; - IndicesMap[VTableIndex] = MethodName + " [complete]"; - IndicesMap[VTableIndex + 1] = MethodName + " [deleting]"; - } else { - GlobalDecl GD(DD, Dtor_Deleting); - assert(MethodVTableIndices.count(GD)); - IndicesMap[MethodVTableIndices[GD]] = MethodName + " [scalar deleting]"; - } + GlobalDecl GD(DD, Dtor_Complete); + assert(MethodVTableIndices.count(GD)); + uint64_t VTableIndex = MethodVTableIndices[GD]; + IndicesMap[VTableIndex] = MethodName + " [complete]"; + IndicesMap[VTableIndex + 1] = MethodName + " [deleting]"; } else { assert(MethodVTableIndices.count(MD)); IndicesMap[MethodVTableIndices[MD]] = MethodName; @@ -2352,10 +2319,12 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) { VTableThunks.size(), VTableThunks.data(), Builder.getAddressPoints(), - Builder.isMicrosoftABI()); + /*IsMicrosoftABI=*/false); } void VTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) { + assert(!IsMicrosoftABI && "Shouldn't be called in this ABI!"); + const VTableLayout *&Entry = VTableLayouts[RD]; // Check if we've computed this information before. @@ -3132,6 +3101,55 @@ static void EnumerateVFPtrs( } } +/// CalculatePathToMangle - Calculate the subset of records that should be used +/// to mangle the vftable for the given vfptr. +/// Should only be called if a class has multiple vftables. +static void +CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) { + // FIXME: In some rare cases this code produces a slightly incorrect mangling. + // It's very likely that the vbtable mangling code can be adjusted to mangle + // both vftables and vbtables correctly. + + VFPtrInfo::BasePath &FullPath = VFPtr.PathToBaseWithVFPtr; + if (FullPath.empty()) { + // Mangle the class's own vftable. + assert(RD->getNumVBases() && + "Something's wrong: if the most derived " + "class has more than one vftable, it can only have its own " + "vftable if it has vbases"); + VFPtr.PathToMangle.push_back(RD); + return; + } + + unsigned Begin = 0; + + // First, skip all the bases before the vbase. + if (VFPtr.LastVBase) { + while (FullPath[Begin] != VFPtr.LastVBase) { + Begin++; + assert(Begin < FullPath.size()); + } + } + + // Then, put the rest of the base path in the reverse order. + for (unsigned I = FullPath.size(); I != Begin; --I) { + const CXXRecordDecl *CurBase = FullPath[I - 1], + *ItsBase = (I == 1) ? RD : FullPath[I - 2]; + bool BaseIsVirtual = false; + for (CXXRecordDecl::base_class_const_iterator J = ItsBase->bases_begin(), + F = ItsBase->bases_end(); J != F; ++J) { + if (J->getType()->getAsCXXRecordDecl() == CurBase) { + BaseIsVirtual = J->isVirtual(); + break; + } + } + + // Should skip the current base if it is a non-virtual base with no siblings. + if (BaseIsVirtual || ItsBase->getNumBases() != 1) + VFPtr.PathToMangle.push_back(CurBase); + } +} + static void EnumerateVFPtrs(ASTContext &Context, const CXXRecordDecl *ForClass, MicrosoftVFTableContext::VFPtrListTy &Result) { Result.clear(); @@ -3140,6 +3158,10 @@ static void EnumerateVFPtrs(ASTContext &Context, const CXXRecordDecl *ForClass, EnumerateVFPtrs(Context, ForClass, ClassLayout, BaseSubobject(ForClass, CharUnits::Zero()), 0, VFPtrInfo::BasePath(), VisitedVBases, Result); + if (Result.size() > 1) { + for (unsigned I = 0, E = Result.size(); I != E; ++I) + CalculatePathToMangle(ForClass, Result[I]); + } } void MicrosoftVFTableContext::computeVTableRelatedInformation( diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 4932c07844..7dd850be0b 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -280,7 +280,7 @@ static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF, "No kext in Microsoft ABI"); GD = GD.getCanonicalDecl(); CodeGenModule &CGM = CGF.CGM; - llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD); + llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits()); Ty = Ty->getPointerTo()->getPointerTo(); VTable = CGF.Builder.CreateBitCast(VTable, Ty); assert(VTable && "BuildVirtualCall = kext vtbl pointer is null"); diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 37f678f4b5..3a1c8d198d 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -303,6 +303,29 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) = 0; + /// Emits the VTable definitions required for the given record type. + virtual void emitVTableDefinitions(CodeGenVTables &CGVT, + const CXXRecordDecl *RD) = 0; + + /// Get the address point of the vtable for the given base subobject while + /// building a constructor or a destructor. On return, NeedsVirtualOffset + /// tells if a virtual base adjustment is needed in order to get the offset + /// of the base subobject. + virtual llvm::Value *getVTableAddressPointInStructor( + CodeGenFunction &CGF, const CXXRecordDecl *RD, BaseSubobject Base, + const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) = 0; + + /// Get the address point of the vtable for the given base subobject while + /// building a constexpr. + virtual llvm::Constant * + getVTableAddressPointForConstExpr(BaseSubobject Base, + const CXXRecordDecl *VTableClass) = 0; + + /// Get the address of the vtable for the given record decl which should be + /// used for the vptr at the given offset in RD. + virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, + CharUnits VPtrOffset) = 0; + /// Build a virtual function pointer in the ABI-specific way. virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, @@ -319,9 +342,7 @@ public: /// Emit any tables needed to implement virtual inheritance. For Itanium, /// this emits virtual table tables. For the MSVC++ ABI, this emits virtual /// base tables. - virtual void - EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) = 0; + virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0; virtual void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResultType); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 392fe85f64..c1226d5681 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1878,39 +1878,19 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, const CXXRecordDecl *NearestVBase, CharUnits OffsetFromNearestVBase, const CXXRecordDecl *VTableClass) { - const CXXRecordDecl *RD = Base.getBase(); - // Compute the address point. - llvm::Value *VTableAddressPoint; - - bool NeedsVTTParam = CGM.getCXXABI().NeedsVTTParameter(CurGD); - - // Check if we need to use a vtable from the VTT. - if (NeedsVTTParam && (RD->getNumVBases() || NearestVBase)) { - // Get the secondary vpointer index. - uint64_t VirtualPointerIndex = - CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base); - - /// Load the VTT. - llvm::Value *VTT = LoadCXXVTT(); - if (VirtualPointerIndex) - VTT = Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex); - - // And load the address point from the VTT. - VTableAddressPoint = Builder.CreateLoad(VTT); - } else { - llvm::Constant *VTable = CGM.getVTables().GetAddrOfVTable(VTableClass); - uint64_t AddressPoint = - CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base); - VTableAddressPoint = - Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint); - } + bool NeedsVirtualOffset; + llvm::Value *VTableAddressPoint = + CGM.getCXXABI().getVTableAddressPointInStructor( + *this, VTableClass, Base, NearestVBase, NeedsVirtualOffset); + if (!VTableAddressPoint) + return; // Compute where to store the address point. llvm::Value *VirtualOffset = 0; CharUnits NonVirtualOffset = CharUnits::Zero(); - if (NeedsVTTParam && NearestVBase) { + if (NeedsVirtualOffset) { // We need to use the virtual base offset offset because the virtual base // might have a different offset in the most derived class. VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(*this, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 5e3d38284b..61ce344c38 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1053,7 +1053,11 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. - if (!isa(Method)) + // FIXME: Add proper support for debug info for virtual calls in + // the Microsoft ABI, where we may use multiple vptrs to make a vftable + // lookup if we have multiple or virtual inheritance. + if (!isa(Method) && + !CGM.getTarget().getCXXABI().isMicrosoft()) VIndex = CGM.getVTableContext().getMethodVTableIndex(Method); ContainingType = RecordTy; } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 2d3afc96f2..f4d6861c8b 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -53,9 +53,6 @@ private: NextFieldOffsetInChars(CharUnits::Zero()), LLVMStructAlignment(CharUnits::One()) { } - void AppendVTablePointer(BaseSubobject Base, llvm::Constant *VTable, - const CXXRecordDecl *VTableClass); - void AppendField(const FieldDecl *Field, uint64_t FieldOffset, llvm::Constant *InitExpr); @@ -72,8 +69,7 @@ private: bool Build(InitListExpr *ILE); void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase, - llvm::Constant *VTable, const CXXRecordDecl *VTableClass, - CharUnits BaseOffset); + const CXXRecordDecl *VTableClass, CharUnits BaseOffset); llvm::Constant *Finalize(QualType Ty); CharUnits getAlignment(const llvm::Constant *C) const { @@ -88,23 +84,6 @@ private: } }; -void ConstStructBuilder::AppendVTablePointer(BaseSubobject Base, - llvm::Constant *VTable, - const CXXRecordDecl *VTableClass) { - // Find the appropriate vtable within the vtable group. - uint64_t AddressPoint = - CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base); - llvm::Value *Indices[] = { - llvm::ConstantInt::get(CGM.Int64Ty, 0), - llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint) - }; - llvm::Constant *VTableAddressPoint = - llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices); - - // Add the vtable at the start of the object. - AppendBytes(Base.getBaseOffset(), VTableAddressPoint); -} - void ConstStructBuilder:: AppendField(const FieldDecl *Field, uint64_t FieldOffset, llvm::Constant *InitCst) { @@ -424,15 +403,19 @@ struct BaseInfo { } void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, - bool IsPrimaryBase, llvm::Constant *VTable, + bool IsPrimaryBase, const CXXRecordDecl *VTableClass, CharUnits Offset) { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); if (const CXXRecordDecl *CD = dyn_cast(RD)) { // Add a vtable pointer, if we need one and it hasn't already been added. - if (CD->isDynamicClass() && !IsPrimaryBase) - AppendVTablePointer(BaseSubobject(CD, Offset), VTable, VTableClass); + if (CD->isDynamicClass() && !IsPrimaryBase) { + llvm::Constant *VTableAddressPoint = + CGM.getCXXABI().getVTableAddressPointForConstExpr( + BaseSubobject(CD, Offset), VTableClass); + AppendBytes(Offset, VTableAddressPoint); + } // Accumulate and sort bases, in order to visit them in address order, which // may not be the same as declaration order. @@ -453,7 +436,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl; Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase, - VTable, VTableClass, Offset + Base.Offset); + VTableClass, Offset + Base.Offset); } } @@ -560,11 +543,7 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM, const RecordDecl *RD = ValTy->castAs()->getDecl(); const CXXRecordDecl *CD = dyn_cast(RD); - llvm::Constant *VTable = 0; - if (CD && CD->isDynamicClass()) - VTable = CGM.getVTables().GetAddrOfVTable(CD); - - Builder.Build(Val, RD, false, VTable, CD, CharUnits::Zero()); + Builder.Build(Val, RD, false, CD, CharUnits::Zero()); return Builder.Finalize(ValTy); } diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index a02292e4ae..ea1456f825 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -19,7 +19,8 @@ using namespace clang; using namespace CodeGen; static llvm::Constant * -GetAddrOfVTTVTable(CodeGenVTables &CGVT, const CXXRecordDecl *MostDerivedClass, +GetAddrOfVTTVTable(CodeGenVTables &CGVT, CodeGenModule &CGM, + const CXXRecordDecl *MostDerivedClass, const VTTVTable &VTable, llvm::GlobalVariable::LinkageTypes Linkage, llvm::DenseMap &AddressPoints) { @@ -27,7 +28,7 @@ GetAddrOfVTTVTable(CodeGenVTables &CGVT, const CXXRecordDecl *MostDerivedClass, assert(VTable.getBaseOffset().isZero() && "Most derived class vtable must have a zero offset!"); // This is a regular vtable. - return CGVT.GetAddrOfVTable(MostDerivedClass); + return CGM.getCXXABI().getAddrOfVTable(MostDerivedClass, CharUnits()); } return CGVT.GenerateConstructionVTable(MostDerivedClass, @@ -52,7 +53,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, for (const VTTVTable *i = Builder.getVTTVTables().begin(), *e = Builder.getVTTVTables().end(); i != e; ++i) { VTableAddressPoints.push_back(VTableAddressPointsMapTy()); - VTables.push_back(GetAddrOfVTTVTable(*this, RD, *i, Linkage, + VTables.push_back(GetAddrOfVTTVTable(*this, CGM, RD, *i, Linkage, VTableAddressPoints.back())); } @@ -106,7 +107,7 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { StringRef Name = OutName.str(); // This will also defer the definition of the VTT. - (void) GetAddrOfVTable(RD); + (void) CGM.getCXXABI().getAddrOfVTable(RD, CharUnits()); VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false); diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 3585c42dc9..59b90b0814 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -498,6 +498,7 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) // FIXME: This is a temporary solution to force generation of vftables in // Microsoft ABI. Remove when we thread VFTableContext through CodeGen. VFTContext->getVFPtrOffsets(MD->getParent()); + return; } const VTableContext::ThunkInfoVectorTy *ThunkInfoVector = @@ -629,53 +630,6 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, return llvm::ConstantArray::get(ArrayType, Inits); } -llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { - llvm::GlobalVariable *&VTable = VTables[RD]; - if (VTable) - return VTable; - - // Queue up this v-table for possible deferred emission. - CGM.addDeferredVTable(RD); - - SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, Out); - Out.flush(); - StringRef Name = OutName.str(); - - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(CGM.Int8PtrTy, - VTContext.getVTableLayout(RD).getNumVTableComponents()); - - VTable = - CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, - llvm::GlobalValue::ExternalLinkage); - VTable->setUnnamedAddr(true); - return VTable; -} - -void -CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, - llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) { - const VTableLayout &VTLayout = VTContext.getVTableLayout(RD); - - // Create and set the initializer. - llvm::Constant *Init = - CreateVTableInitializer(RD, - VTLayout.vtable_component_begin(), - VTLayout.getNumVTableComponents(), - VTLayout.vtable_thunk_begin(), - VTLayout.getNumVTableThunks()); - VTable->setInitializer(Init); - - // Set the correct linkage. - VTable->setLinkage(Linkage); - - // Set the right visibility. - CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable); -} - llvm::GlobalVariable * CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, @@ -818,35 +772,10 @@ CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) { if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) DI->completeClassData(RD); - if (VFTContext.isValid()) { - // FIXME: This is a temporary solution to force generation of vftables in - // Microsoft ABI. Remove when we thread VFTableContext through CodeGen. - VFTContext->getVFPtrOffsets(RD); - } - - // First off, check whether we've already emitted the v-table and - // associated stuff. - llvm::GlobalVariable *VTable = GetAddrOfVTable(RD); - if (VTable->hasInitializer()) - return; - - llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); - EmitVTableDefinition(VTable, Linkage, RD); - if (RD->getNumVBases()) - CGM.getCXXABI().EmitVirtualInheritanceTables(Linkage, RD); - - // If this is the magic class __cxxabiv1::__fundamental_type_info, - // we will emit the typeinfo for the fundamental types. This is the - // same behaviour as GCC. - const DeclContext *DC = RD->getDeclContext(); - if (RD->getIdentifier() && - RD->getIdentifier()->isStr("__fundamental_type_info") && - isa(DC) && - cast(DC)->getIdentifier() && - cast(DC)->getIdentifier()->isStr("__cxxabiv1") && - DC->getParent()->isTranslationUnit()) - CGM.EmitFundamentalRTTIDescriptors(); + CGM.getCXXABI().emitVirtualInheritanceTables(RD); + + CGM.getCXXABI().emitVTableDefinitions(*this, RD); } /// At this point in the translation unit, does it appear that can we diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index e4f5366bae..9b95952e5e 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -35,9 +35,6 @@ class CodeGenVTables { // classes? VTableContext VTContext; OwningPtr VFTContext; - - /// VTables - All the vtables which have been defined. - llvm::DenseMap VTables; /// VTableAddressPointsMapTy - Address points for a single vtable. typedef llvm::DenseMap VTableAddressPointsMapTy; @@ -65,6 +62,7 @@ class CodeGenVTables { /// doesn't contain any incomplete types. void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk); +public: /// CreateVTableInitializer - Create a vtable initializer for the given record /// decl. /// \param Components - The vtable components; this is really an array of @@ -75,7 +73,6 @@ class CodeGenVTables { const VTableLayout::VTableThunkTy *VTableThunks, unsigned NumVTableThunks); -public: CodeGenVTables(CodeGenModule &CGM); VTableContext &getVTableContext() { return VTContext; } @@ -95,14 +92,6 @@ public: /// class decl. uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); - /// GetAddrOfVTable - Get the address of the vtable for the given record decl. - llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD); - - /// EmitVTableDefinition - Emit the definition of the given vtable. - void EmitVTableDefinition(llvm::GlobalVariable *VTable, - llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); - /// GenerateConstructionVTable - Generate a construction vtable for the given /// base subobject. llvm::GlobalVariable * diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 96b97bc180..c2f9570990 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -250,7 +250,6 @@ class CodeGenModule : public CodeGenTypeCache { /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; - friend class CodeGenVTables; CGObjCRuntime* ObjCRuntime; CGOpenCLRuntime* OpenCLRuntime; @@ -915,6 +914,10 @@ public: void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired); + /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the + /// builtin types. + void EmitFundamentalRTTIDescriptors(); + /// \brief Appends Opts to the "Linker Options" metadata value. void AppendLinkerOptions(StringRef Opts); @@ -1068,10 +1071,6 @@ private: /// given type. void EmitFundamentalRTTIDescriptor(QualType Type); - /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the - /// builtin types. - void EmitFundamentalRTTIDescriptors(); - /// EmitDeferred - Emit any needed decls for which code generation /// was deferred. void EmitDeferred(); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index b08e9b7462..2934e6307e 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -34,6 +34,9 @@ using namespace CodeGen; namespace { class ItaniumCXXABI : public CodeGen::CGCXXABI { + /// VTables - All the vtables which have been defined. + llvm::DenseMap VTables; + protected: bool UseARMMethodPtrABI; bool UseARMGuardVarABI; @@ -142,6 +145,20 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); + void emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD); + + llvm::Value *getVTableAddressPointInStructor( + CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, + BaseSubobject Base, const CXXRecordDecl *NearestVBase, + bool &NeedsVirtualOffset); + + llvm::Constant * + getVTableAddressPointForConstExpr(BaseSubobject Base, + const CXXRecordDecl *VTableClass); + + llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, + CharUnits VPtrOffset); + llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This, llvm::Type *Ty); @@ -150,8 +167,7 @@ public: CXXDtorType DtorType, SourceLocation CallLoc, llvm::Value *This); - void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); + void emitVirtualInheritanceTables(const CXXRecordDecl *RD); StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; } StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; } @@ -888,6 +904,113 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, This, VTT, VTTTy, ArgBeg, ArgEnd); } +void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, + const CXXRecordDecl *RD) { + llvm::GlobalVariable *VTable = getAddrOfVTable(RD, CharUnits()); + if (VTable->hasInitializer()) + return; + + VTableContext &VTContext = CGM.getVTableContext(); + const VTableLayout &VTLayout = VTContext.getVTableLayout(RD); + llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); + + // Create and set the initializer. + llvm::Constant *Init = CGVT.CreateVTableInitializer( + RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(), + VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks()); + VTable->setInitializer(Init); + + // Set the correct linkage. + VTable->setLinkage(Linkage); + + // Set the right visibility. + CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable); + + // If this is the magic class __cxxabiv1::__fundamental_type_info, + // we will emit the typeinfo for the fundamental types. This is the + // same behaviour as GCC. + const DeclContext *DC = RD->getDeclContext(); + if (RD->getIdentifier() && + RD->getIdentifier()->isStr("__fundamental_type_info") && + isa(DC) && cast(DC)->getIdentifier() && + cast(DC)->getIdentifier()->isStr("__cxxabiv1") && + DC->getParent()->isTranslationUnit()) + CGM.EmitFundamentalRTTIDescriptors(); +} + +llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor( + CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, + const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) { + bool NeedsVTTParam = CGM.getCXXABI().NeedsVTTParameter(CGF.CurGD); + NeedsVirtualOffset = (NeedsVTTParam && NearestVBase); + + llvm::Value *VTableAddressPoint; + if (NeedsVTTParam && (Base.getBase()->getNumVBases() || NearestVBase)) { + // Get the secondary vpointer index. + uint64_t VirtualPointerIndex = + CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base); + + /// Load the VTT. + llvm::Value *VTT = CGF.LoadCXXVTT(); + if (VirtualPointerIndex) + VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex); + + // And load the address point from the VTT. + VTableAddressPoint = CGF.Builder.CreateLoad(VTT); + } else { + llvm::Constant *VTable = + CGM.getCXXABI().getAddrOfVTable(VTableClass, CharUnits()); + uint64_t AddressPoint = CGM.getVTableContext().getVTableLayout(VTableClass) + .getAddressPoint(Base); + VTableAddressPoint = + CGF.Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint); + } + + return VTableAddressPoint; +} + +llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr( + BaseSubobject Base, const CXXRecordDecl *VTableClass) { + llvm::Constant *VTable = getAddrOfVTable(VTableClass, CharUnits()); + + // Find the appropriate vtable within the vtable group. + uint64_t AddressPoint = + CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base); + llvm::Value *Indices[] = { + llvm::ConstantInt::get(CGM.Int64Ty, 0), + llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint) + }; + + return llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices); +} + +llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, + CharUnits VPtrOffset) { + assert(VPtrOffset.isZero() && "Itanium ABI only supports zero vptr offsets"); + + llvm::GlobalVariable *&VTable = VTables[RD]; + if (VTable) + return VTable; + + // Queue up this v-table for possible deferred emission. + CGM.addDeferredVTable(RD); + + SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, Out); + Out.flush(); + StringRef Name = OutName.str(); + + VTableContext &VTContext = CGM.getVTableContext(); + llvm::ArrayType *ArrayType = llvm::ArrayType::get( + CGM.Int8PtrTy, VTContext.getVTableLayout(RD).getNumVTableComponents()); + + VTable = CGM.CreateOrReplaceCXXRuntimeVariable( + Name, ArrayType, llvm::GlobalValue::ExternalLinkage); + VTable->setUnnamedAddr(true); + return VTable; +} + llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This, @@ -919,11 +1042,10 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, /*ImplicitParam=*/0, QualType(), 0, 0); } -void ItaniumCXXABI::EmitVirtualInheritanceTables( - llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { +void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) { CodeGenVTables &VTables = CGM.getVTables(); llvm::GlobalVariable *VTT = VTables.GetAddrOfVTT(RD); - VTables.EmitVTTDefinition(VTT, Linkage, RD); + VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD); } void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index e5d7c49a64..cfdbaa2957 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/VTableBuilder.h" +#include "llvm/ADT/StringSet.h" using namespace clang; using namespace CodeGen; @@ -150,6 +151,20 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); + void emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD); + + llvm::Value *getVTableAddressPointInStructor( + CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, + BaseSubobject Base, const CXXRecordDecl *NearestVBase, + bool &NeedsVirtualOffset); + + llvm::Constant * + getVTableAddressPointForConstExpr(BaseSubobject Base, + const CXXRecordDecl *VTableClass); + + llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, + CharUnits VPtrOffset); + llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This, llvm::Type *Ty); @@ -158,8 +173,7 @@ public: CXXDtorType DtorType, SourceLocation CallLoc, llvm::Value *This); - void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); + void emitVirtualInheritanceTables(const CXXRecordDecl *RD); void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *DeclPtr, @@ -303,7 +317,16 @@ public: const MemberPointerType *MPT); private: - /// VBTables - All the vbtables which have been referenced. + typedef std::pair VFTableIdTy; + typedef llvm::DenseMap VFTablesMapTy; + /// \brief All the vftables that have been referenced. + VFTablesMapTy VFTablesMap; + + /// \brief This set holds the record decls we've deferred vtable emission for. + llvm::SmallPtrSet DeferredVFTables; + + + /// \brief All the vbtables which have been referenced. llvm::DenseMap VBTablesMap; /// Info on the global variable used to guard initialization of static locals. @@ -616,6 +639,116 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd); } +void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, + const CXXRecordDecl *RD) { + MicrosoftVFTableContext &VFTContext = CGM.getVFTableContext(); + MicrosoftVFTableContext::VFPtrListTy VFPtrs = VFTContext.getVFPtrOffsets(RD); + llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); + + for (MicrosoftVFTableContext::VFPtrListTy::iterator I = VFPtrs.begin(), + E = VFPtrs.end(); I != E; ++I) { + llvm::GlobalVariable *VTable = getAddrOfVTable(RD, I->VFPtrFullOffset); + if (VTable->hasInitializer()) + continue; + + const VTableLayout &VTLayout = + VFTContext.getVFTableLayout(RD, I->VFPtrFullOffset); + llvm::Constant *Init = CGVT.CreateVTableInitializer( + RD, VTLayout.vtable_component_begin(), + VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(), + VTLayout.getNumVTableThunks()); + VTable->setInitializer(Init); + + VTable->setLinkage(Linkage); + CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable); + } +} + +llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor( + CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, + const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) { + NeedsVirtualOffset = (NearestVBase != 0); + + llvm::Value *VTableAddressPoint = + getAddrOfVTable(VTableClass, Base.getBaseOffset()); + if (!VTableAddressPoint) { + assert(Base.getBase()->getNumVBases() && + !CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr()); + } + return VTableAddressPoint; +} + +static void mangleVFTableName(CodeGenModule &CGM, const CXXRecordDecl *RD, + const VFPtrInfo &VFPtr, SmallString<256> &Name) { + llvm::raw_svector_ostream Out(Name); + CGM.getCXXABI().getMangleContext().mangleCXXVFTable( + RD, VFPtr.PathToMangle, Out); +} + +llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr( + BaseSubobject Base, const CXXRecordDecl *VTableClass) { + llvm::Constant *VTable = getAddrOfVTable(VTableClass, Base.getBaseOffset()); + assert(VTable && "Couldn't find a vftable for the given base?"); + return VTable; +} + +llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, + CharUnits VPtrOffset) { + // getAddrOfVTable may return 0 if asked to get an address of a vtable which + // shouldn't be used in the given record type. We want to cache this result in + // VFTablesMap, thus a simple zero check is not sufficient. + VFTableIdTy ID(RD, VPtrOffset); + VFTablesMapTy::iterator I; + bool Inserted; + llvm::tie(I, Inserted) = VFTablesMap.insert( + std::make_pair(ID, static_cast(0))); + if (!Inserted) + return I->second; + + llvm::GlobalVariable *&VTable = I->second; + + MicrosoftVFTableContext &VFTContext = CGM.getVFTableContext(); + const MicrosoftVFTableContext::VFPtrListTy &VFPtrs = + VFTContext.getVFPtrOffsets(RD); + + if (DeferredVFTables.insert(RD)) { + // We haven't processed this record type before. + // Queue up this v-table for possible deferred emission. + CGM.addDeferredVTable(RD); + +#ifndef NDEBUG + // Create all the vftables at once in order to make sure each vftable has + // a unique mangled name. + llvm::StringSet<> ObservedMangledNames; + for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) { + SmallString<256> Name; + mangleVFTableName(CGM, RD, VFPtrs[J], Name); + if (!ObservedMangledNames.insert(Name.str())) + llvm_unreachable("Already saw this mangling before?"); + } +#endif + } + + for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) { + if (VFPtrs[J].VFPtrFullOffset != VPtrOffset) + continue; + + llvm::ArrayType *ArrayType = llvm::ArrayType::get( + CGM.Int8PtrTy, + VFTContext.getVFTableLayout(RD, VFPtrs[J].VFPtrFullOffset) + .getNumVTableComponents()); + + SmallString<256> Name; + mangleVFTableName(CGM, RD, VFPtrs[J], Name); + VTable = CGM.CreateOrReplaceCXXRuntimeVariable( + Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage); + VTable->setUnnamedAddr(true); + break; + } + + return VTable; +} + llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This, @@ -674,9 +807,10 @@ MicrosoftCXXABI::EnumerateVBTables(const CXXRecordDecl *RD) { return VBTables; } -void MicrosoftCXXABI::EmitVirtualInheritanceTables( - llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { +void MicrosoftCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) { const VBTableVector &VBTables = EnumerateVBTables(RD); + llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); + for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end(); I != E; ++I) { I->EmitVBTableDefinition(CGM, RD, Linkage); diff --git a/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp new file mode 100644 index 0000000000..92db9a789b --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-constexpr-vs-inheritance.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct A { + constexpr A(int x) : x(x) {} + virtual void f(); + int x; +}; + +A a(42); +// CHECK: @"\01?a@@3UA@@A" = global { [1 x i8*]*, i32 } { [1 x i8*]* @"\01??_7A@@6B@", i32 42 }, align 4 + +struct B { + constexpr B(int y) : y(y) {} + virtual void g(); + int y; +}; + +struct C : A, B { + constexpr C() : A(777), B(13) {} +}; + +C c; +// CHECK: @"\01?c@@3UC@@A" = global { [1 x i8*]*, i32, [1 x i8*]*, i32 } { [1 x i8*]* @"\01??_7C@@6BA@@@", i32 777, [1 x i8*]* @"\01??_7C@@6BB@@@", i32 13 } diff --git a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp index 9059e6f028..fc59e1751f 100644 --- a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp @@ -145,3 +145,39 @@ void call_grandchild_right(GrandchildOverride *obj) { // Just make sure we don't crash. obj->right(); } + +void emit_ctors() { + Left l; + // CHECK: define {{.*}} @"\01??0Left@@QAE@XZ" + // CHECK-NOT: getelementptr + // CHECK: store [1 x i8*]* @"\01??_7Left@@6B@" + // CHECK: ret + + Right r; + // CHECK: define {{.*}} @"\01??0Right@@QAE@XZ" + // CHECK-NOT: getelementptr + // CHECK: store [1 x i8*]* @"\01??_7Right@@6B@" + // CHECK: ret + + ChildOverride co; + // CHECK: define {{.*}} @"\01??0ChildOverride@@QAE@XZ" + // CHECK: %[[THIS:.*]] = load %struct.ChildOverride** + // CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %this1 to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4 + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7ChildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: ret + + GrandchildOverride gc; + // CHECK: define {{.*}} @"\01??0GrandchildOverride@@QAE@XZ" + // CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride** + // CHECK: %[[VFPTR:.*]] = bitcast %struct.GrandchildOverride* %this1 to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BLeft@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 4 + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7GrandchildOverride@@6BRight@@@", [1 x i8*]** %[[VFPTR]] + // CHECK: ret +} diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp index f9d65f44f2..2c831ca2d4 100644 --- a/test/CodeGenCXX/microsoft-abi-structors.cpp +++ b/test/CodeGenCXX/microsoft-abi-structors.cpp @@ -71,8 +71,8 @@ void C::foo() {} void check_vftable_offset() { C c; // The vftable pointer should point at the beginning of the vftable. -// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to i8*** -// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7C@basic@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]] +// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to [2 x i8*]** +// CHECK: store [2 x i8*]* @"\01??_7C@basic@@6B@", [2 x i8*]** [[THIS_PTR]] } void call_complete_dtor(C *obj_ptr) { @@ -161,7 +161,8 @@ C::C() { // CHECK-NEXT: br label %[[SKIP_VBASES]] // // CHECK: [[SKIP_VBASES]] - // CHECK: @"\01??_7C@constructors@@6B@" + // Class C does not define or override methods, so shouldn't change the vfptr. + // CHECK-NOT: @"\01??_7C@constructors@@6B@" // CHECK: ret } diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp index ecbb843379..064a3ffda9 100644 --- a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp @@ -7,10 +7,26 @@ struct VBase { }; struct B : virtual VBase { + B(); virtual void foo(); virtual void bar(); }; +B::B() { + // CHECK: @"\01??0B@@QAE@XZ" + // CHECK: %[[THIS:.*]] = load %struct.B** + // CHECK: br i1 %{{.*}}, label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]] + // CHECK: %[[SKIP_VBASES]] + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 0 + // CHECK: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* + // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[THIS_i8]], i32 %{{.*}} + // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to [2 x i8*]** + // CHECK: store [2 x i8*]* @"\01??_7B@@6B@", [2 x i8*]** %[[VFPTR]] + // FIXME: Should initialize the vtorDisp here. + // CHECK: ret +} + void B::foo() { // CHECK: define x86_thiscallcc void @"\01?foo@B@@UAEXXZ"(i8* // diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp index bd0666b7d6..a0436c8e81 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp @@ -19,6 +19,8 @@ // RUN: FileCheck --check-prefix=RET-THUNKS-Test4 %s < %t // RUN: FileCheck --check-prefix=RET-THUNKS-Test5 %s < %t +// RUN: FileCheck --check-prefix=MANGLING %s < %t + struct Empty { // Doesn't have a vftable! }; @@ -51,6 +53,9 @@ struct Test1: A, B { // NO-THUNKS-Test1: VFTable indices for 'no_thunks::Test1' (1 entries) // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f() + // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BB@@@" + // Overrides only the left child's method (A::f), needs no thunks. virtual void f(); }; @@ -102,6 +107,8 @@ struct Test4 : Empty, A { // NO-THUNKS-Test4: VFTable indices for 'no_thunks::Test4' (1 entries). // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f() + // MANGLING-DAG: @"\01??_7Test4@no_thunks@@6B@" + virtual void f(); }; @@ -127,6 +134,11 @@ struct Test5: Test1, Test2 { // NO-THUNKS-Test5: VFTable indices for 'no_thunks::Test5' (1 entries). // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z() + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test1@1@@" + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test2@1@@" + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test1@1@@" + // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test2@1@@" + virtual void z(); }; @@ -143,6 +155,9 @@ struct Test6: Test1 { // NO-THUNKS-Test6: VFTable indices for 'no_thunks::Test6' (1 entries). // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f() + // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BB@@@" + // Overrides both no_thunks::Test1::f and A::f. virtual void f(); }; @@ -203,6 +218,9 @@ struct Test9: A, D { // NO-THUNKS-Test9: VFTable indices for 'no_thunks::Test9' (1 entries). // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h() + // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BD@1@@" + virtual void h(); }; @@ -228,6 +246,9 @@ struct Test1: A, D { // PURE-VIRTUAL-Test1-NEXT: via vfptr at offset 4 // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g() + // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BD@1@@" + // Overrides only the right child's method (pure_virtual::D::g), needs this adjustment but // not thunks. virtual void g(); @@ -254,6 +275,9 @@ struct Test1 : B, C { // THIS-THUNKS-Test1: VFTable indices for 'this_adjustment::Test1' (1 entries). // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g() + // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BB@@@" + // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BC@@@" + virtual void g(); }; @@ -278,6 +302,10 @@ struct Test2 : A, B, C { // THIS-THUNKS-Test2-NEXT: via vfptr at offset 4 // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g() + // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BA@@@" + // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BB@@@" + // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BC@@@" + virtual void g(); }; @@ -337,6 +365,8 @@ struct Test1 : Ret1 { // RET-THUNKS-Test1: VFTable indices for 'return_adjustment::Test1' (1 entries). // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo() + // MANGLING-DAG: @"\01??_7Test1@return_adjustment@@6B@" + virtual this_adjustment::Test1* foo(); }; diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp index 9a065d4c02..82e8f1c516 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - > %t 2>&1 -// RUN: FileCheck --check-prefix=EMITS-VTABLE %s < %t -// RUN: FileCheck --check-prefix=NO-VTABLE %s < %t +// RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t +// RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t // RUN: FileCheck --check-prefix=CHECK-A %s < %t // RUN: FileCheck --check-prefix=CHECK-B %s < %t // RUN: FileCheck --check-prefix=CHECK-C %s < %t @@ -10,19 +10,12 @@ // RUN: FileCheck --check-prefix=CHECK-G %s < %t // RUN: FileCheck --check-prefix=CHECK-I %s < %t -// FIXME: Currently, we only test VFTableContext in the AST, but still use -// VTableContext for CodeGen. We should remove the "Vtable" checks below when we -// completely switch from VTableContext to VFTableContext. -// Currently, the order of Vtable vs VFTable output depends on whether the -// v*table info was required by a constructor or a method definition. - struct A { // CHECK-A: VFTable for 'A' (3 entries) // CHECK-A-NEXT: 0 | void A::f() // CHECK-A-NEXT: 1 | void A::g() // CHECK-A-NEXT: 2 | void A::h() - - // CHECK-A: Vtable for 'A' (3 entries) + // CHECK-A: VFTable indices for 'A' (3 entries) // CHECK-A-NEXT: 0 | void A::f() // CHECK-A-NEXT: 1 | void A::g() // CHECK-A-NEXT: 2 | void A::h() @@ -33,20 +26,17 @@ struct A { int ia; }; A a; -// EMITS-VTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*] +// EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*] struct B : A { - // CHECK-B: Vtable for 'B' (5 entries) + // CHECK-B: VFTable for 'A' in 'B' (5 entries) // CHECK-B-NEXT: 0 | void B::f() // CHECK-B-NEXT: 1 | void A::g() // CHECK-B-NEXT: 2 | void A::h() // CHECK-B-NEXT: 3 | void B::i() // CHECK-B-NEXT: 4 | void B::j() - - // CHECK-B: VFTable for 'A' in 'B' (5 entries) + // CHECK-B: VFTable indices for 'B' (3 entries) // CHECK-B-NEXT: 0 | void B::f() - // CHECK-B-NEXT: 1 | void A::g() - // CHECK-B-NEXT: 2 | void A::h() // CHECK-B-NEXT: 3 | void B::i() // CHECK-B-NEXT: 4 | void B::j() @@ -55,7 +45,7 @@ struct B : A { virtual void j(); }; B b; -// EMITS-VTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] +// EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] struct C { // CHECK-C: VFTable for 'C' (2 entries) @@ -65,25 +55,17 @@ struct C { // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] // CHECK-C-NEXT: 1 | void C::f() - // CHECK-C: Vtable for 'C' (2 entries) - // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] - // CHECK-C-NEXT: 1 | void C::f() - // CHECK-C: VTable indices for 'C' (2 entries). - // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] - // CHECK-C-NEXT: 1 | void C::f() - virtual ~C(); virtual void f(); }; void C::f() {} -// NO-VTABLE-NOT: @"\01??_7C@@6B@" +// NO-VFTABLE-NOT: @"\01??_7C@@6B@" struct D { - // CHECK-D: Vtable for 'D' (2 entries) + // CHECK-D: VFTable for 'D' (2 entries) // CHECK-D-NEXT: 0 | void D::f() // CHECK-D-NEXT: 1 | D::~D() [scalar deleting] - - // CHECK-D: VFTable for 'D' (2 entries) + // CHECK-D: VFTable indices for 'D' (2 entries) // CHECK-D-NEXT: 0 | void D::f() // CHECK-D-NEXT: 1 | D::~D() [scalar deleting] @@ -91,7 +73,7 @@ struct D { virtual ~D(); }; D d; -// EMITS-VTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*] +// EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*] struct E : A { // CHECK-E: VFTable for 'A' in 'E' (5 entries) @@ -104,35 +86,15 @@ struct E : A { // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] // CHECK-E-NEXT: 4 | void E::i() - // CHECK-E: Vtable for 'E' (5 entries) - // CHECK-E-NEXT: 0 | void A::f() - // CHECK-E-NEXT: 1 | void A::g() - // CHECK-E-NEXT: 2 | void A::h() - // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] - // CHECK-E-NEXT: 4 | void E::i() - // CHECK-E: VTable indices for 'E' (2 entries). - // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] - // CHECK-E-NEXT: 4 | void E::i() - // ~E would be the key method, but it isn't used, and MS ABI has no key // methods. virtual ~E(); virtual void i(); }; void E::i() {} -// NO-VTABLE-NOT: @"\01??_7E@@6B@" +// NO-VFTABLE-NOT: @"\01??_7E@@6B@" struct F : A { - // CHECK-F: Vtable for 'F' (5 entries) - // CHECK-F-NEXT: 0 | void A::f() - // CHECK-F-NEXT: 1 | void A::g() - // CHECK-F-NEXT: 2 | void A::h() - // CHECK-F-NEXT: 3 | void F::i() - // CHECK-F-NEXT: 4 | F::~F() [scalar deleting] - // CHECK-F: VTable indices for 'F' (2 entries). - // CHECK-F-NEXT: 3 | void F::i() - // CHECK-F-NEXT: 4 | F::~F() [scalar deleting] - // CHECK-F: VFTable for 'A' in 'F' (5 entries) // CHECK-F-NEXT: 0 | void A::f() // CHECK-F-NEXT: 1 | void A::g() @@ -147,7 +109,7 @@ struct F : A { virtual ~F(); }; F f; -// EMITS-VTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] +// EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] struct G : E { // CHECK-G: VFTable for 'A' in 'E' in 'G' (6 entries) @@ -162,31 +124,19 @@ struct G : E { // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] // CHECK-G-NEXT: 5 | void G::j() - // CHECK-G: Vtable for 'G' (6 entries) - // CHECK-G-NEXT: 0 | void G::f() - // CHECK-G-NEXT: 1 | void A::g() - // CHECK-G-NEXT: 2 | void A::h() - // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] - // CHECK-G-NEXT: 4 | void E::i() - // CHECK-G-NEXT: 5 | void G::j() - // CHECK-G: VTable indices for 'G' (3 entries). - // CHECK-G-NEXT: 0 | void G::f() - // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] - // CHECK-G-NEXT: 5 | void G::j() - virtual void f(); // overrides A::f() virtual ~G(); virtual void j(); }; void G::j() {} -// NO-VTABLE-NOT: @"\01??_7G@@6B@" +// NO-VFTABLE-NOT: @"\01??_7G@@6B@" // Test that the usual Itanium-style key method does not emit a vtable. struct H { virtual void f(); }; void H::f() {} -// NO-VTABLE-NOT: @"\01??_7H@@6B@" +// NO-VFTABLE-NOT: @"\01??_7H@@6B@" struct Empty { }; diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp index cf9e4c012c..24872609d5 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp @@ -18,6 +18,8 @@ // RUN: FileCheck --check-prefix=RET-W %s < %t // RUN: FileCheck --check-prefix=RET-T %s < %t +// RUN: FileCheck --check-prefix=MANGLING %s < %t + struct Empty { }; struct A { @@ -38,6 +40,8 @@ struct C: virtual A { // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0 // VTABLE-C-NEXT: 0 | void C::f() + // MANGLING-DAG: @"\01??_7C@@6B@" + ~C(); // Currently required to have correct record layout, see PR16406 virtual void f(); }; @@ -58,6 +62,9 @@ struct D: virtual A { // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0 // VTABLE-D-NEXT: 0 | void D::f() + // MANGLING-DAG: @"\01??_7D@@6B0@@" + // MANGLING-DAG: @"\01??_7D@@6BA@@@" + virtual void f(); virtual void h(); }; @@ -71,6 +78,7 @@ struct X { int x; }; // X and A get reordered in the layout since X doesn't have a vfptr while A has. struct Y : X, A { }; +// MANGLING-DAG: @"\01??_7Y@Test1@@6B@" struct Z : virtual Y { // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). @@ -78,6 +86,8 @@ struct Z : virtual Y { // TEST1-NEXT: 1 | void A::z() // TEST1-NOT: VFTable indices for 'Test1::Z' + + // MANGLING-DAG: @"\01??_7Z@Test1@@6B@" }; Z z; @@ -99,6 +109,10 @@ struct X: virtual A, virtual B { // TEST2: VFTable indices for 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void Test2::X::h() + // MANGLING-DAG: @"\01??_7X@Test2@@6B01@@" + // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@" + // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@" + virtual void h(); }; @@ -107,7 +121,9 @@ X x; namespace Test3 { -struct X : virtual A { }; +struct X : virtual A { + // MANGLING-DAG: @"\01??_7X@Test3@@6B@" +}; struct Y: virtual X { // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). @@ -115,6 +131,8 @@ struct Y: virtual X { // TEST3-NEXT: 1 | void A::z() // TEST3-NOT: VFTable indices for 'Test3::Y' + + // MANGLING-DAG: @"\01??_7Y@Test3@@6B@" }; Y y; @@ -134,6 +152,8 @@ struct X: virtual C { // TEST4-NEXT: 1 | void A::z() // TEST4-NOT: VFTable indices for 'Test4::X' + + // MANGLING-DAG: @"\01??_7X@Test4@@6B@" }; X x; @@ -143,6 +163,7 @@ namespace Test5 { // New methods are added to the base's vftable. struct X : A { + // MANGLING-DAG: @"\01??_7X@Test5@@6B@" virtual void g(); }; @@ -158,6 +179,9 @@ struct Y : virtual X { // TEST5: VFTable indices for 'Test5::Y' (1 entries). // TEST5-NEXT: 0 | void Test5::Y::h() + // MANGLING-DAG: @"\01??_7Y@Test5@@6B01@@" + // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@" + virtual void h(); }; @@ -172,6 +196,8 @@ struct X : A, virtual Empty { // TEST6-NEXT: 1 | void A::z() // TEST6-NOT: VFTable indices for 'Test6::X' + + // MANGLING-DAG: @"\01??_7X@Test6@@6B@" }; X x; @@ -179,7 +205,9 @@ X x; namespace Test7 { -struct X : C { }; +struct X : C { + // MANGLING-DAG: @"\01??_7X@Test7@@6B@" +}; struct Y : virtual X { // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). @@ -191,6 +219,8 @@ struct Y : virtual X { // TEST7-NEXT: 0 | this adjustment: 12 non-virtual // TEST7-NOT: VFTable indices for 'Test7::Y' + + // MANGLING-DAG: @"\01??_7Y@Test7@@6B@" }; Y y; @@ -210,6 +240,9 @@ struct X : D, C { // TEST8: VFTable indices for 'Test8::X' (1 entries). // TEST8-NEXT: via vbtable index 1, vfptr at offset 0 + // MANGLING-DAG: @"\01??_7X@Test8@@6BA@@@" + // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@" + virtual void f(); }; @@ -231,6 +264,9 @@ struct Y : virtual X { // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries). // TEST9-Y-NEXT: 0 | void Test9::Y::h() + // MANGLING-DAG: @"\01??_7Y@Test9@@6B01@@" + // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@" + virtual void h(); }; @@ -248,6 +284,13 @@ struct Z : Y, virtual B { // TEST9-Z-NEXT: 0 | void B::g() // TEST9-Z-NOT: VFTable indices for 'Test9::Z' + + // MANGLING-DAG: @"\01??_7Z@Test9@@6BX@1@@" + // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@" + + // FIXME this one is wrong: + // INCORRECT MANGLING-DAG: @"\01??_7Z@Test9@@6BB@@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7Z@Test9@@6B@" }; Z z; @@ -275,6 +318,16 @@ struct W : Z, D, virtual A, virtual B { // TEST9-W-NEXT: 0 | this adjustment: -8 non-virtual // TEST9-W-NOT: VFTable indices for 'Test9::W' + + // MANGLING-DAG: @"\01??_7W@Test9@@6BA@@@" + // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@" + // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@" + + // FIXME: these two are wrong: + // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BB@@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6B@" + // INCORRECT MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@Z@1@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7W@Test9@@6BY@1@@" }; W w; @@ -320,6 +373,16 @@ struct T : Z, D, virtual A, virtual B { // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::g() + // MANGLING-DAG: @"\01??_7T@Test9@@6BA@@@" + // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@" + // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@" + + // FIXME: these two are wrong: + // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BB@@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6B@" + // INCORRECT MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@Z@1@@" + // MANGLING-DAG-SHOULD-BE: @"\01??_7T@Test9@@6BY@1@@" + virtual void f(); virtual void g(); virtual void h(); diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp index a8d4520b5e..5014eaf264 100644 --- a/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -27,12 +27,6 @@ int main() { // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: } -// basic_iostream's deleting dtor calls its complete dtor, then -// operator delete(). -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr -// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev -// CHECK: call {{.*}} @_ZdlPv - // basic_istream's complete dtor calls the base dtor, // then its virtual base's base dtor. // CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr @@ -45,6 +39,12 @@ int main() { // CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev // CHECK: call {{.*}} @_ZdlPv +// basic_iostream's deleting dtor calls its complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr +// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev +// CHECK: call {{.*}} @_ZdlPv + // basic_istream's base dtor is a no-op. // CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* {{.*}}%this, i8** %vtt) unnamed_addr // CHECK-NOT: call