Emit standard-library RTTI with external linkage, not weak_odr.
Apply hidden visibility to most RTTI; libstdc++ does not rely on exact
pointer equality for the type info (just the type info names). Apply
the same optimization to RTTI that we do to vtables.
Fixes PR5962.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110192 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 1cca977..0724fdf 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -244,11 +244,9 @@
return TypeInfoIsInStandardLibrary(BuiltinTy);
}
-/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
-/// the given type exists somewhere else, and that we should not emit the type
-/// information in this translation unit.
-static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context,
- QualType Ty) {
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
// Type info for builtin types is defined in the standard library.
if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
return TypeInfoIsInStandardLibrary(BuiltinTy);
@@ -258,6 +256,15 @@
if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
return TypeInfoIsInStandardLibrary(PointerTy);
+ return false;
+}
+
+/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
+/// the given type exists somewhere else, and that we should not emit the type
+/// information in this translation unit. Assumes that it is not a
+/// standard-library type.
+static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context,
+ QualType Ty) {
// If RTTI is disabled, don't consider key functions.
if (!Context.getLangOptions().RTTI) return false;
@@ -456,8 +463,7 @@
Fields.push_back(VTable);
}
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty,
- bool Force) {
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
@@ -469,19 +475,26 @@
llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
if (OldGV && !OldGV->isDeclaration())
return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
-
+
// Check if there is already an external RTTI descriptor for this type.
- if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty))
+ bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty);
+ if (!Force &&
+ (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty)))
return GetAddrOfExternalRTTIDescriptor(Ty);
- llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
+ // Emit the standard library with external linkage.
+ llvm::GlobalVariable::LinkageTypes Linkage;
+ if (IsStdLib)
+ Linkage = llvm::GlobalValue::ExternalLinkage;
+ else
+ Linkage = getTypeInfoLinkage(Ty);
// Add the vtable pointer.
BuildVTablePointer(cast<Type>(Ty));
// And the name.
Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage));
-
+
switch (Ty->getTypeClass()) {
default: assert(false && "Unhandled type class!");
@@ -551,7 +564,15 @@
OldGV->replaceAllUsesWith(NewPtr);
OldGV->eraseFromParent();
}
-
+
+ // GCC only relies on the uniqueness of the type names, not the
+ // type_infos themselves, so we can emit these as hidden symbols.
+ if (const RecordType *RT = dyn_cast<RecordType>(Ty))
+ CGM.setTypeVisibility(GV, cast<CXXRecordDecl>(RT->getDecl()),
+ /*ForRTTI*/ true);
+ else if (Linkage == llvm::GlobalValue::WeakODRLinkage)
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+
return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 9cb64c6..db405d3 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -2925,39 +2925,7 @@
VTable->setLinkage(Linkage);
// Set the right visibility.
- CGM.setGlobalVisibility(VTable, RD);
-
- // It's okay to have multiple copies of a vtable, so don't make the
- // dynamic linker unique them. Suppress this optimization if it's
- // possible that there might be unresolved references elsewhere
- // which can only be resolved by this emission.
- if (Linkage == llvm::GlobalVariable::WeakODRLinkage &&
- VTable->getVisibility() == llvm::GlobalVariable::DefaultVisibility &&
- !RD->hasAttr<VisibilityAttr>()) {
- switch (RD->getTemplateSpecializationKind()) {
-
- // Every use of a non-template or explicitly-specialized class's
- // vtable has to emit it.
- case TSK_ExplicitSpecialization:
- case TSK_Undeclared:
- // Implicit instantiations can ignore the possibility of an
- // explicit instantiation declaration because there necessarily
- // must be an EI definition somewhere with default visibility.
- case TSK_ImplicitInstantiation:
- // If there's a key function, there may be translation units
- // that don't have the key function's definition.
- if (!CGM.Context.getKeyFunction(RD))
- // Otherwise, drop the visibility to hidden.
- VTable->setVisibility(llvm::GlobalValue::HiddenVisibility);
- break;
-
- // We have to disable the optimization if this is an EI definition
- // because there might be EI declarations in other shared objects.
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ExplicitInstantiationDeclaration:
- break;
- }
- }
+ CGM.setTypeVisibility(VTable, RD, /*ForRTTI*/ false);
}
llvm::GlobalVariable *
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 63d7913..d2be5af 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -216,6 +216,57 @@
}
}
+/// Set the symbol visibility of type information (vtable and RTTI)
+/// associated with the given type.
+void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
+ const CXXRecordDecl *RD,
+ bool IsForRTTI) const {
+ setGlobalVisibility(GV, RD);
+
+ // We want to drop the visibility to hidden for weak type symbols.
+ // This isn't possible if there might be unresolved references
+ // elsewhere that rely on this symbol being visible.
+
+ // Preconditions.
+ if (GV->getLinkage() != llvm::GlobalVariable::WeakODRLinkage ||
+ GV->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
+ return;
+
+ // Don't override an explicit visibility attribute.
+ if (RD->hasAttr<VisibilityAttr>())
+ return;
+
+ switch (RD->getTemplateSpecializationKind()) {
+ // We have to disable the optimization if this is an EI definition
+ // because there might be EI declarations in other shared objects.
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitInstantiationDeclaration:
+ return;
+
+ // Every use of a non-template or explicitly-specialized class's
+ // type information has to emit it.
+ case TSK_ExplicitSpecialization:
+ case TSK_Undeclared:
+ break;
+
+ // Implicit instantiations can ignore the possibility of an
+ // explicit instantiation declaration because there necessarily
+ // must be an EI definition somewhere with default visibility.
+ case TSK_ImplicitInstantiation:
+ break;
+ }
+
+ // If there's a key function, there may be translation units
+ // that don't have the key function's definition. But ignore
+ // this if we're emitting RTTI under -fno-rtti.
+ if (!IsForRTTI || Features.RTTI)
+ if (Context.getKeyFunction(RD))
+ return;
+
+ // Otherwise, drop the visibility to hidden.
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+}
+
llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 2cb345a..a4d8368 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -270,6 +270,11 @@
/// GlobalValue.
void setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const;
+ /// setTypeVisibility - Set the visibility for the given global
+ /// value which holds information about a type.
+ void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D,
+ bool IsForRTTI) const;
+
llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) {
if (isa<CXXConstructorDecl>(GD.getDecl()))
return GetAddrOfCXXConstructor(cast<CXXConstructorDecl>(GD.getDecl()),