summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2017-01-27 23:11:10 +0000
committerDavid Blaikie <dblaikie@gmail.com>2017-01-27 23:11:10 +0000
commiteb21001111696d5e86ba233336974934fa24d421 (patch)
tree5e52a1dc58a1efb9978afad34bc16a4baa1ce338
parent3db9974b2d4a0d5092eccbf2e1384d66ab1e6a46 (diff)
downloadbcm5719-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.cpp32
-rw-r--r--clang/test/CodeGenCXX/explicit-instantiation.cpp17
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>();
+}
+}
OpenPOWER on IntegriCloud