From ee3f72299ca53c40154890c79fa1afde82ea8fd1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 12 Mar 2010 04:49:06 +0000 Subject: [PATCH] Give explicit template instantiations weak linkage (but don't defer them). Fixes PR6578. llvm-svn: 98328 --- clang/lib/CodeGen/CodeGenModule.cpp | 18 ++++++++++-------- clang/lib/CodeGen/CodeGenModule.h | 3 ++- .../temp/temp.spec/temp.explicit/p1-emit.cpp | 4 ++-- .../test/CodeGenCXX/explicit-instantiation.cpp | 4 ++-- clang/test/CodeGenCXX/mangle-exprs.cpp | 10 +++++----- clang/test/CodeGenCXX/mangle-template.cpp | 4 ++-- clang/test/CodeGenCXX/mangle.cpp | 16 ++++++++-------- clang/test/CodeGenCXX/member-templates.cpp | 4 ++-- clang/test/CodeGenCXX/template-linkage.cpp | 10 +++++----- clang/test/CodeGenCXX/temporaries.cpp | 2 +- 10 files changed, 39 insertions(+), 36 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c67948d27f08..7314dae8131d 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -285,8 +285,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, break; case TSK_ExplicitInstantiationDefinition: - // FIXME: explicit instantiation definitions should use weak linkage - return CodeGenModule::GVA_StrongExternal; + return CodeGenModule::GVA_ExplicitTemplateInstantiation; case TSK_ExplicitInstantiationDeclaration: case TSK_ImplicitInstantiation: @@ -335,7 +334,8 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { // In C99 mode, 'inline' functions are guaranteed to have a strong // definition somewhere else, so we can use available_externally linkage. return llvm::Function::AvailableExternallyLinkage; - } else if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) { + } else if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation || + Linkage == GVA_ExplicitTemplateInstantiation) { // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because // a) if all references in this translation unit are optimized away, we @@ -589,6 +589,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. + // Implicit template instantiations can also be deferred in C++. if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) return true; @@ -1043,15 +1044,15 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { switch (TSK) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - - // FIXME: ExplicitInstantiationDefinition should be weak! - case TSK_ExplicitInstantiationDefinition: return CodeGenModule::GVA_StrongExternal; - + case TSK_ExplicitInstantiationDeclaration: llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. + case TSK_ExplicitInstantiationDefinition: + return CodeGenModule::GVA_ExplicitTemplateInstantiation; + case TSK_ImplicitInstantiation: return CodeGenModule::GVA_TemplateInstantiation; } @@ -1171,7 +1172,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage); else GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - } else if (Linkage == GVA_TemplateInstantiation) + } else if (Linkage == GVA_TemplateInstantiation || + Linkage == GVA_ExplicitTemplateInstantiation) GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon && !D->hasExternalStorage() && !D->getInit() && diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 40dc56388981..9077adedd0b9 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -437,7 +437,8 @@ public: GVA_C99Inline, GVA_CXXInline, GVA_StrongExternal, - GVA_TemplateInstantiation + GVA_TemplateInstantiation, + GVA_ExplicitTemplateInstantiation }; llvm::GlobalVariable::LinkageTypes diff --git a/clang/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp b/clang/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp index 70eb69641867..d8f7b52145dd 100644 --- a/clang/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp @@ -12,10 +12,10 @@ T X::member1; template T X::member2 = 17; -// CHECK: @_ZN1XIiE7member1E = global i32 0 +// CHECK: @_ZN1XIiE7member1E = weak global i32 0 template int X::member1; -// CHECK: @_ZN1XIiE7member2E = global i32 17 +// CHECK: @_ZN1XIiE7member2E = weak global i32 17 template int X::member2; // For implicit instantiation of diff --git a/clang/test/CodeGenCXX/explicit-instantiation.cpp b/clang/test/CodeGenCXX/explicit-instantiation.cpp index ab9174e8f406..0b1712e062ee 100644 --- a/clang/test/CodeGenCXX/explicit-instantiation.cpp +++ b/clang/test/CodeGenCXX/explicit-instantiation.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o %t %s -// RUN: grep "define i32 @_ZNK4plusIillEclERKiRKl" %t | count 1 +// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s template struct plus { @@ -11,4 +10,5 @@ Result plus::operator()(const T& t, const U& u) const { return t + u; } +// CHECK: define linkonce_odr i32 @_ZNK4plusIillEclERKiRKl template struct plus; diff --git a/clang/test/CodeGenCXX/mangle-exprs.cpp b/clang/test/CodeGenCXX/mangle-exprs.cpp index cdad39852c9f..fe36c0b4a7a6 100644 --- a/clang/test/CodeGenCXX/mangle-exprs.cpp +++ b/clang/test/CodeGenCXX/mangle-exprs.cpp @@ -30,15 +30,15 @@ namespace Casts { template T f() { return T(); } - // CHECK: define void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE + // CHECK: define linkonce_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE template void implicit<4>(void*); - // CHECK: define void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK: define linkonce_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void cstyle<4>(void*); - // CHECK: define void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK: define linkonce_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void functional<4>(void*); - // CHECK: define void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK: define linkonce_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void static_<4>(void*); - // CHECK: define i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv + // CHECK: define linkonce_odr i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv template T<6> f<6>(); } diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp index 57f30a762ed0..384ce45e1cb2 100644 --- a/clang/test/CodeGenCXX/mangle-template.cpp +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -82,7 +82,7 @@ namespace test7 { X(U*, typename int_c<(meta::value + meta::value)>::type *) { } }; - // CHECK: define void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE + // CHECK: define linkonce_odr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE template X::X(double*, float*); } @@ -101,6 +101,6 @@ namespace test8 { template void f(int_c::type::value>) { } - // CHECK: define void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE + // CHECK: define linkonce_odr void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE template void f(int_c); } diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp index 3f966902a218..e8ab2c77a8be 100644 --- a/clang/test/CodeGenCXX/mangle.cpp +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -250,26 +250,26 @@ void f() { __fill_a(); } namespace Expressions { // Unary operators. -// CHECK: define void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i +// CHECK: define linkonce_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i template void f1(int (*)[(-i) + 2]) { }; template void f1<1>(int (*)[1]); -// CHECK: define void @_ZN11Expressions2f2ILi1EEEvPApsT__i +// CHECK: define linkonce_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i template void f2(int (*)[+i]) { }; template void f2<1>(int (*)[1]); // Binary operators. -// CHECK: define void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i +// CHECK: define linkonce_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i template void f3(int (*)[i+i]) { }; template void f3<1>(int (*)[2]); -// CHECK: define void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i +// CHECK: define linkonce_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i template void f4(int (*)[2 + i+i]) { }; template void f4<1>(int (*)[4]); // The ternary operator. -// CHECK: define void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i +// CHECK: define linkonce_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i template void f4(int (*)[b ? 1 : 2]) { }; template void f4(int (*)[1]); } @@ -305,7 +305,7 @@ template > class Alloc T *allocate(int, const void*) { return 0; } }; -// CHECK: define i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv +// CHECK: define linkonce_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv template class Alloc; } @@ -369,7 +369,7 @@ namespace test0 { namespace test1 { template struct X { }; template class Y, typename T> void f(Y) { } - // CHECK: define void @_ZN5test11fINS_1XEiEEvT_IT0_E + // CHECK: define linkonce_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E template void f(X); } @@ -447,7 +447,7 @@ namespace test7 { void g(zed<&foo::bar>*) {} } -// CHECK: define void @_ZN5test81AILZNS_1B5valueEEE3incEv +// CHECK: define linkonce_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv namespace test8 { template class A { void inc() { counter++; } }; class B { static int value; }; diff --git a/clang/test/CodeGenCXX/member-templates.cpp b/clang/test/CodeGenCXX/member-templates.cpp index 355ba20e171f..f82224780e62 100644 --- a/clang/test/CodeGenCXX/member-templates.cpp +++ b/clang/test/CodeGenCXX/member-templates.cpp @@ -15,8 +15,8 @@ struct B { template B::B(T) {} -// CHECK: define void @_ZN1BC1IiEET_(%struct.B* %this, i32) -// CHECK: define void @_ZN1BC2IiEET_(%struct.B* %this, i32) +// CHECK: define linkonce_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) +// CHECK: define linkonce_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) template B::B(int); template diff --git a/clang/test/CodeGenCXX/template-linkage.cpp b/clang/test/CodeGenCXX/template-linkage.cpp index 5d573d6e829b..03451bed1589 100644 --- a/clang/test/CodeGenCXX/template-linkage.cpp +++ b/clang/test/CodeGenCXX/template-linkage.cpp @@ -6,19 +6,19 @@ template struct A { // Explicit instantiations have external linkage. -// CHECK: define void @_ZN1AIiE1gEv( +// CHECK: define linkonce_odr void @_ZN1AIiE1gEv( template void A::g(); -// CHECK: define void @_ZN1AIfE1fEf( -// CHECK: define void @_ZN1AIfE1gEv( +// CHECK: define linkonce_odr void @_ZN1AIfE1fEf( +// CHECK: define linkonce_odr void @_ZN1AIfE1gEv( // FIXME: This should also emit the vtable. template struct A; -// CHECK: define void @_Z1fIiEvT_ +// CHECK: define linkonce_odr void @_Z1fIiEvT_ template void f(T) { } template void f(int); -// CHECK: define void @_Z1gIiEvT_ +// CHECK: define linkonce_odr void @_Z1gIiEvT_ template inline void g(T) { } template void g(int); diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp index 3b624afd0ad1..7d2d201a46df 100644 --- a/clang/test/CodeGenCXX/temporaries.cpp +++ b/clang/test/CodeGenCXX/temporaries.cpp @@ -256,7 +256,7 @@ namespace PR6199 { struct B { operator A(); }; - // CHECK: define void @_ZN6PR61992f2IiEENS_1AET_ + // CHECK: define linkonce_odr void @_ZN6PR61992f2IiEENS_1AET_ template A f2(T) { B b; // CHECK: call void @_ZN6PR61991BcvNS_1AEEv