c++: Fix static local vars in extern "C".
authorJason Merrill <jason@redhat.com>
Thu, 13 Feb 2020 15:42:04 +0000 (16:42 +0100)
committerJason Merrill <jason@redhat.com>
Thu, 13 Feb 2020 21:29:25 +0000 (22:29 +0100)
Since my patch for PR 91476 moved visibility determination sooner, a local
static in a vague linkage function now gets TREE_PUBLIC set before
retrofit_lang_decl calls set_decl_linkage, which was making decl_linkage
think that it has external linkage.  It still has no linkage according to
the standard.

gcc/cp/ChangeLog
2020-02-13  Jason Merrill  <jason@redhat.com>

PR c++/93643
PR c++/91476
* tree.c (decl_linkage): Always lk_none for locals.

gcc/cp/ChangeLog
gcc/cp/tree.c
gcc/testsuite/g++.dg/lookup/extern-c-static1.C [new file with mode: 0644]

index e0dd0388e14e9ed93f76b8610367d483d8b787e5..8d7d91ce719cd1cd4574c4fe6bbdcf13652e93d4 100644 (file)
@@ -1,3 +1,9 @@
+2020-02-13  Jason Merrill  <jason@redhat.com>
+
+       PR c++/93643
+       PR c++/91476
+       * tree.c (decl_linkage): Always lk_none for locals.
+
 2020-02-12  Jason Merrill  <jason@redhat.com>
 
        PR c++/92583
index 736ef6fe667202389e7d3861782286a331d10d63..72b3a720ee8ce549890ee308e9b3382b243ac7b1 100644 (file)
@@ -5266,6 +5266,10 @@ decl_linkage (tree decl)
   if (TREE_CODE (decl) == FIELD_DECL)
     return lk_none;
 
+  /* Things in local scope do not have linkage.  */
+  if (decl_function_context (decl))
+    return lk_none;
+
   /* Things that are TREE_PUBLIC have external linkage.  */
   if (TREE_PUBLIC (decl))
     return lk_external;
@@ -5285,11 +5289,6 @@ decl_linkage (tree decl)
   if (TREE_CODE (decl) == CONST_DECL)
     return decl_linkage (TYPE_NAME (DECL_CONTEXT (decl)));
 
-  /* Things in local scope do not have linkage, if they don't have
-     TREE_PUBLIC set.  */
-  if (decl_function_context (decl))
-    return lk_none;
-
   /* Members of the anonymous namespace also have TREE_PUBLIC unset, but
      are considered to have external linkage for language purposes, as do
      template instantiations on targets without weak symbols.  DECLs really
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-static1.C b/gcc/testsuite/g++.dg/lookup/extern-c-static1.C
new file mode 100644 (file)
index 0000000..0ba8d67
--- /dev/null
@@ -0,0 +1,27 @@
+// PR c++/93643
+
+void* callback(const char* name);
+
+extern "C" {
+
+  inline void f1()
+  {
+    static void (*f)();
+    f = (void(*)()) callback("f1");
+    f();
+  }
+
+  inline void f2()
+  {
+    static void (*f)();
+    f = (void(*)()) callback("f2");
+    f();
+  }
+
+} // extern "C"
+
+int main()
+{
+  f1();
+  f2();
+}