diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 9c1a7016459e..49e13559d7fc 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -2574,6 +2574,12 @@ public: MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)), WhichVFPtr(*Which), Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) { + // Only include the RTTI component if we know that we will provide a + // definition of the vftable. + if (Context.getLangOpts().RTTI && + !MostDerivedClass->hasAttr()) + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); + LayoutVFTable(); if (Context.getLangOpts().DumpVTableLayouts) @@ -2915,7 +2921,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // it requires return adjustment. Insert the method info for this method. unsigned VBIndex = LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; - MethodInfo MI(VBIndex, Components.size()); + MethodInfo MI(VBIndex, Context.getLangOpts().RTTI ? Components.size() - 1 + : Components.size()); assert(!MethodInfoMap.count(MD) && "Should not have method info for this method yet!"); diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 91e6a18398b2..0df2c43d11b5 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -431,12 +431,10 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false); } -llvm::Constant * -CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, - const VTableComponent *Components, - unsigned NumComponents, - const VTableLayout::VTableThunkTy *VTableThunks, - unsigned NumVTableThunks) { +llvm::Constant *CodeGenVTables::CreateVTableInitializer( + const CXXRecordDecl *RD, const VTableComponent *Components, + unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, + unsigned NumVTableThunks, llvm::Constant *RTTI) { SmallVector Inits; llvm::Type *Int8PtrTy = CGM.Int8PtrTy; @@ -444,9 +442,6 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); - QualType ClassType = CGM.getContext().getTagDeclType(RD); - llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType); - unsigned NextVTableThunkIndex = 0; llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr; @@ -594,13 +589,14 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // V-tables are always unnamed_addr. VTable->setUnnamedAddr(true); + llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor( + CGM.getContext().getTagDeclType(Base.getBase())); + // Create and set the initializer. - llvm::Constant *Init = - CreateVTableInitializer(Base.getBase(), - VTLayout->vtable_component_begin(), - VTLayout->getNumVTableComponents(), - VTLayout->vtable_thunk_begin(), - VTLayout->getNumVTableThunks()); + llvm::Constant *Init = CreateVTableInitializer( + Base.getBase(), VTLayout->vtable_component_begin(), + VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(), + VTLayout->getNumVTableThunks(), RTTI); VTable->setInitializer(Init); return VTable; diff --git a/clang/lib/CodeGen/CGVTables.h b/clang/lib/CodeGen/CGVTables.h index ba67ed41d3e2..69cf079567e3 100644 --- a/clang/lib/CodeGen/CGVTables.h +++ b/clang/lib/CodeGen/CGVTables.h @@ -61,11 +61,10 @@ public: /// decl. /// \param Components - The vtable components; this is really an array of /// VTableComponents. - llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD, - const VTableComponent *Components, - unsigned NumComponents, - const VTableLayout::VTableThunkTy *VTableThunks, - unsigned NumVTableThunks); + llvm::Constant *CreateVTableInitializer( + const CXXRecordDecl *RD, const VTableComponent *Components, + unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks, + unsigned NumVTableThunks, llvm::Constant *RTTI); CodeGenVTables(CodeGenModule &CGM); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index d96b34eee628..a4d398a2fa74 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -750,8 +750,8 @@ public: /// \brief Gets or a creats a Microsoft TypeDescriptor. llvm::Constant *getMSTypeDescriptor(QualType Ty); /// \brief Gets or a creats a Microsoft CompleteObjectLocator. - llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD, - const VPtrInfo *Info); + llvm::Constant *getMSCompleteObjectLocator(const CXXRecordDecl *RD, + const VPtrInfo *Info); /// Gets the address of a block which requires no captures. llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 28634d8a70bc..c33eb62ce2af 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1182,11 +1182,13 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext(); const VTableLayout &VTLayout = VTContext.getVTableLayout(RD); llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); + llvm::Constant *RTTI = + CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD)); // Create and set the initializer. llvm::Constant *Init = CGVT.CreateVTableInitializer( RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(), - VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks()); + VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks(), RTTI); VTable->setInitializer(Init); // Set the correct linkage. diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index f3c79ef967ad..2e9db03e2655 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -403,9 +403,11 @@ public: private: typedef std::pair VFTableIdTy; - typedef llvm::DenseMap VFTablesMapTy; + typedef llvm::DenseMap VTablesMapTy; + typedef llvm::DenseMap VFTablesMapTy; /// \brief All the vftables that have been referenced. VFTablesMapTy VFTablesMap; + VTablesMapTy VTablesMap; /// \brief This set holds the record decls we've deferred vtable emission for. llvm::SmallPtrSet DeferredVFTables; @@ -1051,26 +1053,22 @@ void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD) { MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext(); VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD); - llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); for (VPtrInfo *Info : VFPtrs) { llvm::GlobalVariable *VTable = getAddrOfVTable(RD, Info->FullOffsetInMDC); if (VTable->hasInitializer()) continue; - if (getContext().getLangOpts().RTTI) - CGM.getMSCompleteObjectLocator(RD, Info); + + llvm::Constant *RTTI = CGM.getMSCompleteObjectLocator(RD, Info); const VTableLayout &VTLayout = VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC); llvm::Constant *Init = CGVT.CreateVTableInitializer( RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(), - VTLayout.getNumVTableThunks()); + VTLayout.getNumVTableThunks(), RTTI); + VTable->setInitializer(Init); - - VTable->setLinkage(Linkage); - - CGM.setGlobalVisibility(VTable, RD); } } @@ -1079,8 +1077,9 @@ llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor( const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) { NeedsVirtualOffset = (NearestVBase != nullptr); - llvm::Value *VTableAddressPoint = - getAddrOfVTable(VTableClass, Base.getBaseOffset()); + (void)getAddrOfVTable(VTableClass, Base.getBaseOffset()); + VFTableIdTy ID(VTableClass, Base.getBaseOffset()); + llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID]; if (!VTableAddressPoint) { assert(Base.getBase()->getNumVBases() && !CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr()); @@ -1097,9 +1096,11 @@ static void mangleVFTableName(MicrosoftMangleContext &MangleContext, 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; + (void)getAddrOfVTable(VTableClass, Base.getBaseOffset()); + VFTableIdTy ID(VTableClass, Base.getBaseOffset()); + llvm::GlobalValue *VFTable = VFTablesMap[ID]; + assert(VFTable && "Couldn't find a vftable for the given base?"); + return VFTable; } llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, @@ -1108,9 +1109,9 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, // 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; + VTablesMapTy::iterator I; bool Inserted; - std::tie(I, Inserted) = VFTablesMap.insert(std::make_pair(ID, nullptr)); + std::tie(I, Inserted) = VTablesMap.insert(std::make_pair(ID, nullptr)); if (!Inserted) return I->second; @@ -1140,21 +1141,73 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) { if (VFPtrs[J]->FullOffsetInMDC != VPtrOffset) continue; + SmallString<256> VFTableName; + mangleVFTableName(getMangleContext(), RD, VFPtrs[J], VFTableName); + StringRef VTableName = VFTableName; - llvm::ArrayType *ArrayType = llvm::ArrayType::get( - CGM.Int8PtrTy, + uint64_t NumVTableSlots = VTContext.getVFTableLayout(RD, VFPtrs[J]->FullOffsetInMDC) - .getNumVTableComponents()); + .getNumVTableComponents(); + llvm::GlobalValue::LinkageTypes VTableLinkage = + llvm::GlobalValue::ExternalLinkage; + llvm::ArrayType *VTableType = + llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots); + if (getContext().getLangOpts().RTTI) { + VTableLinkage = llvm::GlobalValue::PrivateLinkage; + VTableName = ""; + } - SmallString<256> Name; - mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name); - VTable = CGM.CreateOrReplaceCXXRuntimeVariable( - Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage); - VTable->setUnnamedAddr(true); - if (RD->hasAttr()) - VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); - else if (RD->hasAttr()) - VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + VTable = CGM.getModule().getNamedGlobal(VFTableName); + if (!VTable) { + llvm::GlobalValue *VFTable = VTable = new llvm::GlobalVariable( + CGM.getModule(), VTableType, /*isConstant=*/true, VTableLinkage, + /*Initializer=*/nullptr, VTableName); + VTable->setUnnamedAddr(true); + if (getContext().getLangOpts().RTTI && !RD->hasAttr()) { + llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0), + llvm::ConstantInt::get(CGM.IntTy, 1)}; + llvm::Constant *VTableGEP = + llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices); + VFTable = llvm::GlobalAlias::create( + cast(VTableGEP->getType())->getElementType(), + /*AddressSpace=*/0, llvm::GlobalValue::ExternalLinkage, + VFTableName.str(), VTableGEP, &CGM.getModule()); + } else { + VTable->setName(VFTableName.str()); + } + + VFTable->setUnnamedAddr(true); + if (RD->hasAttr()) + VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + else if (RD->hasAttr()) + VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + + llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD); + if (VFTable != VTable) { + if (llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage)) { + // AvailableExternally implies that we grabbed the data from another + // executable. No need to stick the alias in a Comdat. + } else if (llvm::GlobalValue::isLocalLinkage(VFTableLinkage)) { + // If it's local, it means that the virtual function table can't be + // referenced in another translation unit. No need to stick the alias + // in a Comdat. + } else if (llvm::GlobalValue::isWeakODRLinkage(VFTableLinkage) || + llvm::GlobalValue::isLinkOnceODRLinkage(VFTableLinkage)) { + // The alias is going to be dropped into a Comdat, no need to make it + // weak. + VFTableLinkage = llvm::GlobalValue::ExternalLinkage; + llvm::Comdat *C = + CGM.getModule().getOrInsertComdat(VFTable->getName()); + C->setSelectionKind(llvm::Comdat::Largest); + VTable->setComdat(C); + } else { + llvm_unreachable("unexpected linkage for vftable!"); + } + } + VFTable->setLinkage(VFTableLinkage); + CGM.setGlobalVisibility(VFTable, RD); + VFTablesMap[ID] = VFTable; + } break; } diff --git a/clang/lib/CodeGen/MicrosoftRTTI.cpp b/clang/lib/CodeGen/MicrosoftRTTI.cpp index 14dfa8545f63..51d56e94abe3 100644 --- a/clang/lib/CodeGen/MicrosoftRTTI.cpp +++ b/clang/lib/CodeGen/MicrosoftRTTI.cpp @@ -505,8 +505,10 @@ llvm::Constant *CodeGenModule::getMSTypeDescriptor(QualType Type) { Int8PtrTy); } -llvm::GlobalVariable * +llvm::Constant * CodeGenModule::getMSCompleteObjectLocator(const CXXRecordDecl *RD, const VPtrInfo *Info) { + if (!getLangOpts().RTTI) + return llvm::Constant::getNullValue(Int8PtrTy); return MSRTTIBuilder(*this, RD).getCompleteObjectLocator(Info); } diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp index 0090d95afb35..6634009097cb 100644 --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -24,6 +24,9 @@ struct External { int v; }; #define INSTVAR(var) template int var; #define INST(func) template void func(); +// The vftable for struct W is comdat largest because we have RTTI. +// M32-DAG: $"\01??_7W@@6B@" = comdat largest + //===----------------------------------------------------------------------===// // Globals @@ -518,7 +521,8 @@ struct __declspec(dllexport) W { virtual void foo() {} }; // Copy ctor: // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.W* @"\01??0W@@QAE@ABU0@@Z" // vftable: -// M32-DAG: @"\01??_7W@@6B@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void (%struct.W*)* @"\01?foo@W@@UAEXXZ" to i8*)] +// M32-DAG: [[W_VTABLE:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast (%MSRTTICompleteObjectLocator* @"\01??_R4W@@6B@" to i8*), i8* bitcast (void (%struct.W*)* @"\01?foo@W@@UAEXXZ" to i8*)], comdat $"\01??_7W@@6B@" +// M32-DAG: @"\01??_7W@@6B@" = dllexport unnamed_addr alias getelementptr inbounds ([2 x i8*]* [[W_VTABLE]], i32 0, i32 1), comdat $"\01??_7W@@6B@" // G32-DAG: @_ZTV1W = weak_odr dllexport unnamed_addr constant [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1W to i8*), i8* bitcast (void (%struct.W*)* @_ZN1W3fooEv to i8*)] struct __declspec(dllexport) X : public virtual W {};