dblaikie created this revision. As Mehdi put it, entities should either be available_externally+weak_odr, or linkonce_odr+linkonce_odr. While some functions are emitted a_e/weak, their local variables were emitted a_e/linkonce_odr.
While it might be nice to emit them a_e/weak, the Itanium ABI (& best guess at MSVC's behavior as well) requires the local to be linkonce/linkonce. https://reviews.llvm.org/D29233 Files: lib/AST/ASTContext.cpp test/CodeGenCXX/explicit-instantiation.cpp Index: test/CodeGenCXX/explicit-instantiation.cpp =================================================================== --- test/CodeGenCXX/explicit-instantiation.cpp +++ test/CodeGenCXX/explicit-instantiation.cpp @@ -5,6 +5,9 @@ // This check logically is attached to 'template int S<int>::i;' below. // CHECK: @_ZN1SIiE1iE = weak_odr global i32 +// This check is logically attached to 'template int ExportedStaticLocal::f<int>()' below. +// CHECK-OPT: @_ZZN19ExportedStaticLocal1fIiEEvvE1i = linkonce_odr global + template<typename T, typename U, typename Result> struct plus { Result operator()(const T& t, const U& u) const; @@ -153,3 +156,17 @@ template <typename T> void S<T>::g() {} template <typename T> int S<T>::i; template <typename T> void S<T>::S2::h() {} + +namespace ExportedStaticLocal { +void sink(int&); +template <typename T> +inline void f() { + static int i; + sink(i); +} +// See the check line at the top of the file. +extern template void f<int>(); +void use() { + f<int>(); +} +} Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8892,22 +8892,27 @@ return GVA_Internal; if (VD->isStaticLocal()) { - GVALinkage StaticLocalLinkage = GVA_DiscardableODR; const DeclContext *LexicalContext = VD->getParentFunctionOrMethod(); while (LexicalContext && !isa<FunctionDecl>(LexicalContext)) LexicalContext = LexicalContext->getLexicalParent(); - // Let the static local variable inherit its linkage from the nearest - // enclosing function. - if (LexicalContext) - StaticLocalLinkage = - Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext)); - - // GVA_StrongODR function linkage is stronger than what we need, - // downgrade to GVA_DiscardableODR. - // This allows us to discard the variable if we never end up needing it. - return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR - : StaticLocalLinkage; + // ObjC Blocks can create local variables that don't have a FunctionDecl + // LexicalContext. + if (!LexicalContext) + return GVA_DiscardableODR; + + // Otherwise, let the static local variable inherit its linkage from the + // nearest enclosing function. + auto StaticLocalLinkage = + Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext)); + + // Itanium ABI (& MSVC seems to do similarly) requires static locals in + // inline functions to be emitted anywhere they're needed, even if the + // function they are local to is emitted StrongODR/AvailableExternally. + if (StaticLocalLinkage == GVA_StrongODR || + StaticLocalLinkage == GVA_AvailableExternally) + return GVA_DiscardableODR; + return StaticLocalLinkage; } // MSVC treats in-class initialized static data members as definitions.
Index: test/CodeGenCXX/explicit-instantiation.cpp =================================================================== --- test/CodeGenCXX/explicit-instantiation.cpp +++ test/CodeGenCXX/explicit-instantiation.cpp @@ -5,6 +5,9 @@ // This check logically is attached to 'template int S<int>::i;' below. // CHECK: @_ZN1SIiE1iE = weak_odr global i32 +// This check is logically attached to 'template int ExportedStaticLocal::f<int>()' below. +// CHECK-OPT: @_ZZN19ExportedStaticLocal1fIiEEvvE1i = linkonce_odr global + template<typename T, typename U, typename Result> struct plus { Result operator()(const T& t, const U& u) const; @@ -153,3 +156,17 @@ template <typename T> void S<T>::g() {} template <typename T> int S<T>::i; template <typename T> void S<T>::S2::h() {} + +namespace ExportedStaticLocal { +void sink(int&); +template <typename T> +inline void f() { + static int i; + sink(i); +} +// See the check line at the top of the file. +extern template void f<int>(); +void use() { + f<int>(); +} +} Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8892,22 +8892,27 @@ return GVA_Internal; if (VD->isStaticLocal()) { - GVALinkage StaticLocalLinkage = GVA_DiscardableODR; const DeclContext *LexicalContext = VD->getParentFunctionOrMethod(); while (LexicalContext && !isa<FunctionDecl>(LexicalContext)) LexicalContext = LexicalContext->getLexicalParent(); - // Let the static local variable inherit its linkage from the nearest - // enclosing function. - if (LexicalContext) - StaticLocalLinkage = - Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext)); - - // GVA_StrongODR function linkage is stronger than what we need, - // downgrade to GVA_DiscardableODR. - // This allows us to discard the variable if we never end up needing it. - return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR - : StaticLocalLinkage; + // ObjC Blocks can create local variables that don't have a FunctionDecl + // LexicalContext. + if (!LexicalContext) + return GVA_DiscardableODR; + + // Otherwise, let the static local variable inherit its linkage from the + // nearest enclosing function. + auto StaticLocalLinkage = + Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext)); + + // Itanium ABI (& MSVC seems to do similarly) requires static locals in + // inline functions to be emitted anywhere they're needed, even if the + // function they are local to is emitted StrongODR/AvailableExternally. + if (StaticLocalLinkage == GVA_StrongODR || + StaticLocalLinkage == GVA_AvailableExternally) + return GVA_DiscardableODR; + return StaticLocalLinkage; } // MSVC treats in-class initialized static data members as definitions.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits