diff options
| author | David Blaikie <dblaikie@gmail.com> | 2017-01-27 23:11:10 +0000 |
|---|---|---|
| committer | David Blaikie <dblaikie@gmail.com> | 2017-01-27 23:11:10 +0000 |
| commit | eb21001111696d5e86ba233336974934fa24d421 (patch) | |
| tree | 5e52a1dc58a1efb9978afad34bc16a4baa1ce338 | |
| parent | 3db9974b2d4a0d5092eccbf2e1384d66ab1e6a46 (diff) | |
| download | bcm5719-llvm-eb21001111696d5e86ba233336974934fa24d421.tar.gz bcm5719-llvm-eb21001111696d5e86ba233336974934fa24d421.zip | |
Fix linkage of static locals in available_externally functions to be DiscardableODR/linkonce_odr
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.
Reviewers: rsmith, mehdi_amini
Differential Revision: https://reviews.llvm.org/D29233
llvm-svn: 293344
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 32 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/explicit-instantiation.cpp | 17 |
2 files changed, 37 insertions, 12 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a8732d729ca..07721b2ba7c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8892,22 +8892,30 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, 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 5.2.2: "Each COMDAT group [for a static local variable] must + // be emitted in any object with references to the symbol for the object it + // contains, whether inline or out-of-line." + // Similar behavior is observed with MSVC. An alternative ABI could use + // StrongODR/AvailableExternally to match the function, but none are + // known/supported currently. + if (StaticLocalLinkage == GVA_StrongODR || + StaticLocalLinkage == GVA_AvailableExternally) + return GVA_DiscardableODR; + return StaticLocalLinkage; } // MSVC treats in-class initialized static data members as definitions. diff --git a/clang/test/CodeGenCXX/explicit-instantiation.cpp b/clang/test/CodeGenCXX/explicit-instantiation.cpp index fb571187876..85857fb6fb8 100644 --- a/clang/test/CodeGenCXX/explicit-instantiation.cpp +++ b/clang/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>::f() {} 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>(); +} +} |

