c++: duplicate block-scope extern [PR 97877]
authorNathan Sidwell <nathan@acm.org>
Tue, 17 Nov 2020 21:16:47 +0000 (13:16 -0800)
committerNathan Sidwell <nathan@acm.org>
Tue, 17 Nov 2020 21:28:08 +0000 (13:28 -0800)
We ICED with a duplicated block-scope extern, as duplicate_decls was
dropping the decl_lang_specific of olddecl.  Simplys adding
appropriate retrofitting and copying turned out to be insufficient
because you can get a block-scope using decl also matching the extern.
The latter seems a little suspicious and I have asked CWG for advice.
While there robustified the assert about releasing olddecls'
lang-specific -- if it had one, the new decl better have one.

PR c++/97877
gcc/cp/
* decl.c (duplicate_decls): Deal with duplicated DECL_LOCAL_DECL_P
decls.  Extend decl_lang_specific checking assert.
gcc/testsuite/
* g++.dg/lookup/pr97877.C: New.

gcc/cp/decl.c
gcc/testsuite/g++.dg/lookup/pr97877.C [new file with mode: 0644]

index 89bae06cd6bbb1a70ffc2fd868314a09575777d9..d90e9840f401232b344440ef454a8084ae81e33c 100644 (file)
@@ -2452,6 +2452,20 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
   if (! DECL_COMDAT (olddecl))
     DECL_COMDAT (newdecl) = 0;
 
+  if (VAR_OR_FUNCTION_DECL_P (newdecl) && DECL_LOCAL_DECL_P (newdecl))
+    {
+      if (!DECL_LOCAL_DECL_P (olddecl))
+       /* This can happen if olddecl was brought in from the
+          enclosing namespace via a using-decl.  The new decl is
+          then not a block-scope extern at all.  */
+       DECL_LOCAL_DECL_P (newdecl) = false;
+      else
+       {
+         retrofit_lang_decl (newdecl);
+         DECL_LOCAL_DECL_ALIAS (newdecl) = DECL_LOCAL_DECL_ALIAS (olddecl);
+       }
+    }
+
   new_template_info = NULL_TREE;
   if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
     {
@@ -2735,8 +2749,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
      with that from NEWDECL below.  */
   if (DECL_LANG_SPECIFIC (olddecl))
     {
-      gcc_assert (DECL_LANG_SPECIFIC (olddecl)
-                 != DECL_LANG_SPECIFIC (newdecl));
+      gcc_checking_assert (DECL_LANG_SPECIFIC (newdecl)
+                          && (DECL_LANG_SPECIFIC (olddecl)
+                              != DECL_LANG_SPECIFIC (newdecl)));
       ggc_free (DECL_LANG_SPECIFIC (olddecl));
     }
 
diff --git a/gcc/testsuite/g++.dg/lookup/pr97877.C b/gcc/testsuite/g++.dg/lookup/pr97877.C
new file mode 100644 (file)
index 0000000..294edd2
--- /dev/null
@@ -0,0 +1,8 @@
+// PR 97877, duplicate decls smashed decl_lang_specific
+
+void f ()
+{
+  extern int a;
+  extern int a;
+  a = 2;
+}