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
This commit is contained in:
John McCall 2010-08-04 08:34:44 +00:00
Родитель 72905cfa81
Коммит cbfe50224b
9 изменённых файлов: 180 добавлений и 118 удалений

Просмотреть файл

@ -244,11 +244,9 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
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 @@ static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context,
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 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
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::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty,
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 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty,
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);
}

Просмотреть файл

@ -2925,39 +2925,7 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
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 *

Просмотреть файл

@ -216,6 +216,57 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
}
}
/// 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());

Просмотреть файл

@ -270,6 +270,11 @@ public:
/// 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()),

Просмотреть файл

@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fno-rtti -fexceptions %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: @_ZTIN5test11AE = weak_odr constant
// CHECK: @_ZTIN5test11BE = weak_odr constant
// CHECK: @_ZTIN5test11CE = weak_odr constant
// CHECK: @_ZTIN5test11DE = weak_odr constant
// CHECK: @_ZTIPN5test11DE = weak_odr constant {{.*}} @_ZTIN5test11DE
// CHECK: @_ZTIN5test11AE = weak_odr hidden constant
// CHECK: @_ZTIN5test11BE = weak_odr hidden constant
// CHECK: @_ZTIN5test11CE = weak_odr hidden constant
// CHECK: @_ZTIN5test11DE = weak_odr hidden constant
// CHECK: @_ZTIPN5test11DE = weak_odr hidden constant {{.*}} @_ZTIN5test11DE
// PR6974: this shouldn't crash
namespace test0 {
@ -18,9 +18,12 @@ namespace test0 {
}
namespace test1 {
// These classes have key functions defined out-of-line.
// Under normal circumstances, we wouldn't generate RTTI for them;
// under -fno-rtti, we generate RTTI only when required by EH.
// These classes have key functions defined out-of-line. Under
// normal circumstances, we wouldn't generate RTTI for them; under
// -fno-rtti, we generate RTTI only when required by EH. But
// everything gets hidden visibility because we assume that all
// users are also compiled under -fno-rtti and therefore will be
// emitting RTTI regardless of key function.
class A { virtual void foo(); };
class B { virtual void foo(); };
class C { virtual void foo(); };

Просмотреть файл

@ -14,60 +14,60 @@ namespace __cxxabiv1 {
__fundamental_type_info::~__fundamental_type_info() { }
}
// CHECK: @_ZTIv = weak_odr constant
// CHECK: @_ZTIPv = weak_odr constant
// CHECK: @_ZTIPKv = weak_odr constant
// CHECK: @_ZTIDi = weak_odr constant
// CHECK: @_ZTIPDi = weak_odr constant
// CHECK: @_ZTIPKDi = weak_odr constant
// CHECK: @_ZTIDs = weak_odr constant
// CHECK: @_ZTIPDs = weak_odr constant
// CHECK: @_ZTIPKDs = weak_odr constant
// CHECK: @_ZTIy = weak_odr constant
// CHECK: @_ZTIPy = weak_odr constant
// CHECK: @_ZTIPKy = weak_odr constant
// CHECK: @_ZTIx = weak_odr constant
// CHECK: @_ZTIPx = weak_odr constant
// CHECK: @_ZTIPKx = weak_odr constant
// CHECK: @_ZTIw = weak_odr constant
// CHECK: @_ZTIPw = weak_odr constant
// CHECK: @_ZTIPKw = weak_odr constant
// CHECK: @_ZTIt = weak_odr constant
// CHECK: @_ZTIPt = weak_odr constant
// CHECK: @_ZTIPKt = weak_odr constant
// CHECK: @_ZTIs = weak_odr constant
// CHECK: @_ZTIPs = weak_odr constant
// CHECK: @_ZTIPKs = weak_odr constant
// CHECK: @_ZTIm = weak_odr constant
// CHECK: @_ZTIPm = weak_odr constant
// CHECK: @_ZTIPKm = weak_odr constant
// CHECK: @_ZTIl = weak_odr constant
// CHECK: @_ZTIPl = weak_odr constant
// CHECK: @_ZTIPKl = weak_odr constant
// CHECK: @_ZTIj = weak_odr constant
// CHECK: @_ZTIPj = weak_odr constant
// CHECK: @_ZTIPKj = weak_odr constant
// CHECK: @_ZTIi = weak_odr constant
// CHECK: @_ZTIPi = weak_odr constant
// CHECK: @_ZTIPKi = weak_odr constant
// CHECK: @_ZTIh = weak_odr constant
// CHECK: @_ZTIPh = weak_odr constant
// CHECK: @_ZTIPKh = weak_odr constant
// CHECK: @_ZTIf = weak_odr constant
// CHECK: @_ZTIPf = weak_odr constant
// CHECK: @_ZTIPKf = weak_odr constant
// CHECK: @_ZTIe = weak_odr constant
// CHECK: @_ZTIPe = weak_odr constant
// CHECK: @_ZTIPKe = weak_odr constant
// CHECK: @_ZTId = weak_odr constant
// CHECK: @_ZTIPd = weak_odr constant
// CHECK: @_ZTIPKd = weak_odr constant
// CHECK: @_ZTIc = weak_odr constant
// CHECK: @_ZTIPc = weak_odr constant
// CHECK: @_ZTIPKc = weak_odr constant
// CHECK: @_ZTIb = weak_odr constant
// CHECK: @_ZTIPb = weak_odr constant
// CHECK: @_ZTIPKb = weak_odr constant
// CHECK: @_ZTIa = weak_odr constant
// CHECK: @_ZTIPa = weak_odr constant
// CHECK: @_ZTIPKa = weak_odr constant
// CHECK: @_ZTIv = constant
// CHECK: @_ZTIPv = constant
// CHECK: @_ZTIPKv = constant
// CHECK: @_ZTIDi = constant
// CHECK: @_ZTIPDi = constant
// CHECK: @_ZTIPKDi = constant
// CHECK: @_ZTIDs = constant
// CHECK: @_ZTIPDs = constant
// CHECK: @_ZTIPKDs = constant
// CHECK: @_ZTIy = constant
// CHECK: @_ZTIPy = constant
// CHECK: @_ZTIPKy = constant
// CHECK: @_ZTIx = constant
// CHECK: @_ZTIPx = constant
// CHECK: @_ZTIPKx = constant
// CHECK: @_ZTIw = constant
// CHECK: @_ZTIPw = constant
// CHECK: @_ZTIPKw = constant
// CHECK: @_ZTIt = constant
// CHECK: @_ZTIPt = constant
// CHECK: @_ZTIPKt = constant
// CHECK: @_ZTIs = constant
// CHECK: @_ZTIPs = constant
// CHECK: @_ZTIPKs = constant
// CHECK: @_ZTIm = constant
// CHECK: @_ZTIPm = constant
// CHECK: @_ZTIPKm = constant
// CHECK: @_ZTIl = constant
// CHECK: @_ZTIPl = constant
// CHECK: @_ZTIPKl = constant
// CHECK: @_ZTIj = constant
// CHECK: @_ZTIPj = constant
// CHECK: @_ZTIPKj = constant
// CHECK: @_ZTIi = constant
// CHECK: @_ZTIPi = constant
// CHECK: @_ZTIPKi = constant
// CHECK: @_ZTIh = constant
// CHECK: @_ZTIPh = constant
// CHECK: @_ZTIPKh = constant
// CHECK: @_ZTIf = constant
// CHECK: @_ZTIPf = constant
// CHECK: @_ZTIPKf = constant
// CHECK: @_ZTIe = constant
// CHECK: @_ZTIPe = constant
// CHECK: @_ZTIPKe = constant
// CHECK: @_ZTId = constant
// CHECK: @_ZTIPd = constant
// CHECK: @_ZTIPKd = constant
// CHECK: @_ZTIc = constant
// CHECK: @_ZTIPc = constant
// CHECK: @_ZTIPKc = constant
// CHECK: @_ZTIb = constant
// CHECK: @_ZTIPb = constant
// CHECK: @_ZTIPKb = constant
// CHECK: @_ZTIa = constant
// CHECK: @_ZTIPa = constant
// CHECK: @_ZTIPKa = constant

Просмотреть файл

@ -11,13 +11,16 @@
// CHECK: _ZTI1A = weak_odr constant
// CHECK: _ZTI1A = weak_odr hidden constant
// CHECK: _ZTI1B = constant
// CHECK: _ZTI1C = internal constant
// CHECK: _ZTIA10_i = weak_odr constant
// CHECK: _ZTI1TILj0EE = weak_odr hidden constant
// CHECK: _ZTI1TILj1EE = weak_odr constant
// CHECK: _ZTI1TILj2EE = external constant
// CHECK: _ZTIA10_i = weak_odr hidden constant
// CHECK: _ZTIFN12_GLOBAL__N_11DEvE = internal constant
// CHECK: _ZTIFvN12_GLOBAL__N_11DEE = internal constant
// CHECK: _ZTIFvvE = weak_odr
// CHECK: _ZTIFvvE = weak_odr hidden constant
// CHECK: _ZTIM1A1C = internal constant
// CHECK: _ZTIM1AP1C = internal constant
// CHECK: _ZTIM1CPS_ = internal constant
@ -26,7 +29,7 @@
// CHECK: _ZTIN12_GLOBAL__N_11DE = internal constant
// CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant
// CHECK: _ZTIP1C = internal constant
// CHECK: _ZTIPFvvE = weak_odr constant
// CHECK: _ZTIPFvvE = weak_odr hidden constant
// CHECK: _ZTIPM1Ci = internal constant
// CHECK: _ZTIPN12_GLOBAL__N_11DE = internal constant
// CHECK: _ZTIPP1C = internal constant
@ -118,3 +121,14 @@ namespace Arrays {
return typeid(A::a);
}
}
template <unsigned N> class T {
virtual void anchor() {}
};
template class T<1>;
template <> class T<2> { virtual void anchor(); };
void t3() {
(void) typeid(T<0>);
(void) typeid(T<1>);
(void) typeid(T<2>);
}

Просмотреть файл

@ -101,7 +101,7 @@ void use_F() {
// and hidden visibility (rdar://problem/7523229).
// CHECK-2: @_ZTV1C = weak_odr hidden constant
// CHECK-2: @_ZTS1C = weak_odr constant
// CHECK-2: @_ZTI1C = weak_odr constant
// CHECK-2: @_ZTI1C = weak_odr hidden constant
// D has a key function that is defined in this translation unit so its vtable is
// defined in the translation unit.
@ -140,7 +140,7 @@ void use_F() {
// so its vtable should have weak_odr linkage and hidden visibility.
// CHECK-8: @_ZTV1FIlE = weak_odr hidden constant
// CHECK-8: @_ZTS1FIlE = weak_odr constant
// CHECK-8: @_ZTI1FIlE = weak_odr constant
// CHECK-8: @_ZTI1FIlE = weak_odr hidden constant
// F<int> is an explicit template instantiation declaration without a
// key function, so its vtable should have external linkage.
@ -167,7 +167,7 @@ void use_F() {
// its vtable should have weak_odr linkage and hidden visibility.
// CHECK-13: @_ZTV1FIcE = weak_odr hidden constant
// CHECK-13: @_ZTS1FIcE = weak_odr constant
// CHECK-13: @_ZTI1FIcE = weak_odr constant
// CHECK-13: @_ZTI1FIcE = weak_odr hidden constant
// RUN: FileCheck --check-prefix=CHECK-G %s < %t
//

Просмотреть файл

@ -7,6 +7,6 @@ struct X { };
void f() {
// CHECK: @_ZTS1X = weak_odr constant
// CHECK: @_ZTI1X = weak_odr constant
// CHECK: @_ZTI1X = weak_odr hidden constant
(void)typeid(X&);
}