]> granicus.if.org Git - clang/commitdiff
Emit standard-library RTTI with external linkage, not weak_odr.
authorJohn McCall <rjmccall@apple.com>
Wed, 4 Aug 2010 08:34:44 +0000 (08:34 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 4 Aug 2010 08:34:44 +0000 (08:34 +0000)
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

lib/CodeGen/CGRTTI.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGenCXX/exceptions-no-rtti.cpp
test/CodeGenCXX/rtti-fundamental.cpp
test/CodeGenCXX/rtti-linkage.cpp
test/CodeGenCXX/vtable-linkage.cpp
test/SemaCXX/typeid-ref.cpp

index 1cca97702ddd0aa4ff05764e07182bd09ca00c18..0724fdfba35679b85fc44c79c4d12243d97cbc53 100644 (file)
@@ -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);
 }
 
index 9cb64c6d5b3b6a6d2bbe59338d09b3380302e76e..db405d3673ae3a864daf69ad1e05849ca1b892a1 100644 (file)
@@ -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 *
index 63d79132b1fd07c64fa3d880fb078d87dab06b47..d2be5af14a4ad924c0fafa6ae56577e1dac78894 100644 (file)
@@ -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());
 
index 2cb345a8a23cc9895ba92c997734a7705c08c4d2..a4d8368d4d9edc164ae244b60dc4dff733c65f6b 100644 (file)
@@ -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()),
index c26abb26af9c83511377b0b6dc36936760cd209a..01be1cc4b065d96b79ecce4c0afae7cbaddc78ed 100644 (file)
@@ -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(); };
index 6826321cd5ebde3ded12b4125974e1007b278024..7f80d99b70e1f7c38cfca8136ac0a0f8dda03a3b 100644 (file)
@@ -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
index f8c1167b53db03d1d255eb739de8c7e1a038f3bc..a8b62f7bc3bfc5313ead45146285d561236aae20 100644 (file)
 
 
 
-// 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>);
+}
index 9b93a316bec544e8959e45b0d59fe21d41e80086..67980edf7be2924d050d42925d46d2737da288e6 100644 (file)
@@ -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
 //
index da0016970bee9cb9907ff7701ef8cf45ab7fc136..362b919fa375b98ae50a4430fc3d8e2e3637a01b 100644 (file)
@@ -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&);
 }