r293344 - Fix linkage of static locals in available_externally functions to be DiscardableODR/linkonce_odr

David Blaikie via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 27 15:11:10 PST 2017


Author: dblaikie
Date: Fri Jan 27 17:11:10 2017
New Revision: 293344

URL: http://llvm.org/viewvc/llvm-project?rev=293344&view=rev
Log:
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

Modified:
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=293344&r1=293343&r2=293344&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jan 27 17:11:10 2017
@@ -8892,22 +8892,30 @@ static GVALinkage basicGVALinkageForVari
     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));
+    // ObjC Blocks can create local variables that don't have a FunctionDecl
+    // LexicalContext.
+    if (!LexicalContext)
+      return GVA_DiscardableODR;
 
-    // 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;
+    // 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.

Modified: cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp?rev=293344&r1=293343&r2=293344&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp Fri Jan 27 17:11:10 2017
@@ -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>();
+}
+}




More information about the cfe-commits mailing list