MS ABI: Don't try to emit VF/VB-Tables for extern class templates

There will be an explicit template instantiation in another translation
unit which will provide the definition of the VF/VB-Tables.

This fixes PR22932.

llvm-svn: 232680
This commit is contained in:
David Majnemer 2015-03-18 22:04:43 +00:00
parent 2d56abacd1
commit a03849b2e7
6 changed files with 116 additions and 100 deletions

View File

@ -2589,7 +2589,9 @@ public:
// Only include the RTTI component if we know that we will provide a
// definition of the vftable.
HasRTTIComponent = Context.getLangOpts().RTTIData &&
!MostDerivedClass->hasAttr<DLLImportAttr>();
!MostDerivedClass->hasAttr<DLLImportAttr>() &&
MostDerivedClass->getTemplateSpecializationKind() !=
TSK_ExplicitInstantiationDeclaration;
LayoutVFTable();

View File

@ -743,7 +743,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return DiscardableODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
llvm_unreachable("Should not have been asked to emit this");
return llvm::GlobalVariable::ExternalLinkage;
case TSK_ExplicitInstantiationDefinition:
return NonDiscardableODRLinkage;

View File

@ -1851,7 +1851,8 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
OldGV->eraseFromParent();
}
if (supportsCOMDAT() && GV->isWeakForLinker())
if (supportsCOMDAT() && GV->isWeakForLinker() &&
!GV->hasAvailableExternallyLinkage())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
return GV;

View File

@ -1487,102 +1487,97 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
#endif
}
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;
VPtrInfo *const *VFPtrI =
std::find_if(VFPtrs.begin(), VFPtrs.end(), [&](VPtrInfo *VPI) {
return VPI->FullOffsetInMDC == VPtrOffset;
});
if (VFPtrI == VFPtrs.end()) {
VFTablesMap[ID] = nullptr;
return nullptr;
}
VPtrInfo *VFPtr = *VFPtrI;
uint64_t NumVTableSlots =
VTContext.getVFTableLayout(RD, VFPtrs[J]->FullOffsetInMDC)
.getNumVTableComponents();
llvm::GlobalValue::LinkageTypes VTableLinkage =
llvm::GlobalValue::ExternalLinkage;
llvm::ArrayType *VTableType =
llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
if (getContext().getLangOpts().RTTIData) {
VTableLinkage = llvm::GlobalValue::PrivateLinkage;
VTableName = "";
}
SmallString<256> VFTableName;
mangleVFTableName(getMangleContext(), RD, VFPtr, VFTableName);
VTable = CGM.getModule().getNamedGlobal(VFTableName);
if (!VTable) {
// Create a backing variable for the contents of VTable. The VTable may
// or may not include space for a pointer to RTTI data.
llvm::GlobalValue *VFTable = VTable = new llvm::GlobalVariable(
CGM.getModule(), VTableType, /*isConstant=*/true, VTableLinkage,
/*Initializer=*/nullptr, VTableName);
VTable->setUnnamedAddr(true);
llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD);
bool VFTableComesFromAnotherTU =
llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage) ||
llvm::GlobalValue::isExternalLinkage(VFTableLinkage);
bool VTableAliasIsRequred =
!VFTableComesFromAnotherTU && getContext().getLangOpts().RTTIData;
// Only insert a pointer into the VFTable for RTTI data if we are not
// importing it. We never reference the RTTI data directly so there is no
// need to make room for it.
if (getContext().getLangOpts().RTTIData &&
!RD->hasAttr<DLLImportAttr>()) {
llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
llvm::ConstantInt::get(CGM.IntTy, 1)};
// Create a GEP which points just after the first entry in the VFTable,
// this should be the location of the first virtual method.
llvm::Constant *VTableGEP =
llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
// The symbol for the VFTable is an alias to the GEP. It is
// transparent, to other modules, what the nature of this symbol is; all
// that matters is that the alias be the address of the first virtual
// method.
VFTable = llvm::GlobalAlias::create(
cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
/*AddressSpace=*/0, llvm::GlobalValue::ExternalLinkage,
VFTableName.str(), VTableGEP, &CGM.getModule());
} else {
// We don't need a GlobalAlias to be a symbol for the VTable if we won't
// be referencing any RTTI data. The GlobalVariable will end up being
// an appropriate definition of the VFTable.
VTable->setName(VFTableName.str());
}
VFTable->setUnnamedAddr(true);
if (RD->hasAttr<DLLImportAttr>())
VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
else if (RD->hasAttr<DLLExportAttr>())
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::isInternalLinkage(VFTableLinkage) ||
llvm::GlobalValue::isWeakODRLinkage(VFTableLinkage) ||
llvm::GlobalValue::isLinkOnceODRLinkage(VFTableLinkage)) {
// The alias is going to be dropped into a Comdat, no need to make it
// weak.
if (!llvm::GlobalValue::isInternalLinkage(VFTableLinkage))
VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
llvm::Comdat *C =
CGM.getModule().getOrInsertComdat(VFTable->getName());
// We must indicate which VFTable is larger to support linking between
// translation units which do and do not have RTTI data. The largest
// VFTable contains the RTTI data; translation units which reference
// the smaller VFTable always reference it relative to the first
// virtual method.
C->setSelectionKind(llvm::Comdat::Largest);
VTable->setComdat(C);
} else {
llvm_unreachable("unexpected linkage for vftable!");
}
} else {
if (llvm::GlobalValue::isWeakForLinker(VFTableLinkage))
VTable->setComdat(
CGM.getModule().getOrInsertComdat(VTable->getName()));
}
VFTable->setLinkage(VFTableLinkage);
CGM.setGlobalVisibility(VFTable, RD);
VFTablesMap[ID] = VFTable;
}
break;
if (llvm::GlobalValue *VFTable =
CGM.getModule().getNamedGlobal(VFTableName)) {
VFTablesMap[ID] = VFTable;
return VTableAliasIsRequred
? cast<llvm::GlobalVariable>(
cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
: cast<llvm::GlobalVariable>(VFTable);
}
uint64_t NumVTableSlots =
VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC)
.getNumVTableComponents();
llvm::GlobalValue::LinkageTypes VTableLinkage =
VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage;
StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str();
llvm::ArrayType *VTableType =
llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
// Create a backing variable for the contents of VTable. The VTable may
// or may not include space for a pointer to RTTI data.
llvm::GlobalValue *VFTable;
VTable = new llvm::GlobalVariable(CGM.getModule(), VTableType,
/*isConstant=*/true, VTableLinkage,
/*Initializer=*/nullptr, VTableName);
VTable->setUnnamedAddr(true);
llvm::Comdat *C = nullptr;
if (!VFTableComesFromAnotherTU &&
(llvm::GlobalValue::isWeakForLinker(VFTableLinkage) ||
(llvm::GlobalValue::isLocalLinkage(VFTableLinkage) &&
VTableAliasIsRequred)))
C = CGM.getModule().getOrInsertComdat(VFTableName.str());
// Only insert a pointer into the VFTable for RTTI data if we are not
// importing it. We never reference the RTTI data directly so there is no
// need to make room for it.
if (VTableAliasIsRequred) {
llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
llvm::ConstantInt::get(CGM.IntTy, 1)};
// Create a GEP which points just after the first entry in the VFTable,
// this should be the location of the first virtual method.
llvm::Constant *VTableGEP =
llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
if (llvm::GlobalValue::isWeakForLinker(VFTableLinkage)) {
VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
if (C)
C->setSelectionKind(llvm::Comdat::Largest);
}
VFTable = llvm::GlobalAlias::create(
cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
/*AddressSpace=*/0, VFTableLinkage, VFTableName.str(), VTableGEP,
&CGM.getModule());
VFTable->setUnnamedAddr(true);
} else {
// We don't need a GlobalAlias to be a symbol for the VTable if we won't
// be referencing any RTTI data.
// The GlobalVariable will end up being an appropriate definition of the
// VFTable.
VFTable = VTable;
}
if (C)
VTable->setComdat(C);
if (RD->hasAttr<DLLImportAttr>())
VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
else if (RD->hasAttr<DLLExportAttr>())
VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
VFTablesMap[ID] = VFTable;
return VTable;
}
@ -1811,9 +1806,6 @@ void MicrosoftCXXABI::emitVBTableDefinition(const VPtrInfo &VBT,
llvm::ArrayType::get(CGM.IntTy, Offsets.size());
llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
GV->setInitializer(Init);
// Set the right visibility.
CGM.setGlobalVisibility(GV, RD);
}
llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,

View File

@ -528,3 +528,14 @@ D d;
// CHECK-DAG: @"\01??_8D@Test29@@7BB@1@@" = linkonce_odr unnamed_addr constant [2 x i32] zeroinitializer
}
namespace Test30 {
struct A {};
template <class> struct B : virtual A {
B() {}
};
extern template class B<int>;
template B<int>::B();
// CHECK-DAG: @"\01??_8?$B@H@Test30@@7B@" = external unnamed_addr constant [2 x i32]{{$}}
}

View File

@ -3,7 +3,6 @@
// RTTI-DAG: $"\01??_7S@@6B@" = comdat largest
// RTTI-DAG: $"\01??_7V@@6B@" = comdat largest
// RTTI-DAG: $"\01??_7W@?A@@6B@" = comdat largest
struct S {
virtual ~S();
@ -36,7 +35,18 @@ struct W {
virtual ~W();
} w;
}
// RTTI-DAG: [[VTABLE_W:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4W@?A@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)], comdat($"\01??_7W@?A@@6B@")
// RTTI-DAG: @"\01??_7W@?A@@6B@" = internal unnamed_addr alias getelementptr inbounds ([2 x i8*], [2 x i8*]* @2, i32 0, i32 1)
// RTTI-DAG: [[VTABLE_W:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4W@?A@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)]
// RTTI-DAG: @"\01??_7W@?A@@6B@" = internal unnamed_addr alias getelementptr inbounds ([2 x i8*], [2 x i8*]* [[VTABLE_W]], i32 0, i32 1)
// NO-RTTI-DAG: @"\01??_7W@?A@@6B@" = internal unnamed_addr constant [1 x i8*] [i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)]
struct X {};
template <class> struct Y : virtual X {
Y() {}
virtual ~Y();
};
extern template class Y<int>;
template Y<int>::Y();
// RTTI-DAG: @"\01??_7?$Y@H@@6B@" = external unnamed_addr constant [1 x i8*]
// NO-RTTI-DAG: @"\01??_7?$Y@H@@6B@" = external unnamed_addr constant [1 x i8*]