[comitted] c++: Fix static local vars in extern "C".

Message ID 20200213213141.9373-1-jason@redhat.com
State New
Headers show
Series
  • [comitted] c++: Fix static local vars in extern "C".
Related show

Commit Message

Jason Merrill Feb. 13, 2020, 9:31 p.m.
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.

Tested x86_64-pc-linux-gnu, applying to trunk.

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/tree.c                                 |  9 +++----
 .../g++.dg/lookup/extern-c-static1.C          | 27 +++++++++++++++++++
 2 files changed, 31 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-static1.C


base-commit: 613c932f5e5c0cc2e4b88e21d9870fa7b1a6ce5d
-- 
2.18.1

Patch

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 736ef6fe667..72b3a720ee8 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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
index 00000000000..0ba8d67ba15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-static1.C
@@ -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();
+}