From: John McCall Date: Wed, 4 Aug 2010 08:34:44 +0000 (+0000) Subject: Emit standard-library RTTI with external linkage, not weak_odr. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cbfe50224b19119e759802bd0c1463269dffd09e;p=clang 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 1cca97702d..0724fdfba3 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -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(Ty)) return TypeInfoIsInStandardLibrary(BuiltinTy); @@ -258,6 +256,15 @@ static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, if (const PointerType *PointerTy = dyn_cast(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(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(Ty)) + CGM.setTypeVisibility(GV, cast(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 9cb64c6d5b..db405d3673 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -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()) { - 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 63d79132b1..d2be5af14a 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -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()) + 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(GD.getDecl()); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 2cb345a8a2..a4d8368d4d 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -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(GD.getDecl())) return GetAddrOfCXXConstructor(cast(GD.getDecl()), diff --git a/test/CodeGenCXX/exceptions-no-rtti.cpp b/test/CodeGenCXX/exceptions-no-rtti.cpp index c26abb26af..01be1cc4b0 100644 --- a/test/CodeGenCXX/exceptions-no-rtti.cpp +++ b/test/CodeGenCXX/exceptions-no-rtti.cpp @@ -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(); }; diff --git a/test/CodeGenCXX/rtti-fundamental.cpp b/test/CodeGenCXX/rtti-fundamental.cpp index 6826321cd5..7f80d99b70 100644 --- a/test/CodeGenCXX/rtti-fundamental.cpp +++ b/test/CodeGenCXX/rtti-fundamental.cpp @@ -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 diff --git a/test/CodeGenCXX/rtti-linkage.cpp b/test/CodeGenCXX/rtti-linkage.cpp index f8c1167b53..a8b62f7bc3 100644 --- a/test/CodeGenCXX/rtti-linkage.cpp +++ b/test/CodeGenCXX/rtti-linkage.cpp @@ -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 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>); +} diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp index 9b93a316be..67980edf7b 100644 --- a/test/CodeGenCXX/vtable-linkage.cpp +++ b/test/CodeGenCXX/vtable-linkage.cpp @@ -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 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 // diff --git a/test/SemaCXX/typeid-ref.cpp b/test/SemaCXX/typeid-ref.cpp index da0016970b..362b919fa3 100644 --- a/test/SemaCXX/typeid-ref.cpp +++ b/test/SemaCXX/typeid-ref.cpp @@ -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&); }