c++: Instantiation with local extern [PR97395]
authorNathan Sidwell <nathan@acm.org>
Wed, 14 Oct 2020 12:06:54 +0000 (05:06 -0700)
committerNathan Sidwell <nathan@acm.org>
Wed, 14 Oct 2020 12:08:36 +0000 (05:08 -0700)
It turns out that pushdecl_with_scope has somewhat strange behaviour,
which probably made more sense way back.  Unfortunately making it
somewhat saner turned into a rathole.  Instead use a
push_nested_namespace around pushing the alias -- this is similar to
some of the friend handling we already have.

gcc/cp/
* name-lookup.c (push_local_extern_decl_alias): Push into alias's
namespace and use pushdecl.
(do_pushdecl_with_scope): Clarify behaviour.
gcc/testsuite/
* g++.dg/lookup/extern-redecl2.C: New.

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

index e3f3712b1f0631ebf5128bfeab8e0e77c2f31301..5dcaab4d1dfe9f1d4fd80ea0ffb62027ecc90eaa 100644 (file)
@@ -38,7 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 
 static cxx_binding *cxx_binding_make (tree value, tree type);
 static cp_binding_level *innermost_nonclass_level (void);
-static tree do_pushdecl_with_scope (tree x, cp_binding_level *, bool hiding);
+static tree do_pushdecl (tree decl, bool hiding);
 static void set_identifier_type_value_with_scope (tree id, tree decl,
                                                  cp_binding_level *b);
 static name_hint maybe_suggest_missing_std_header (location_t location,
@@ -2975,8 +2975,9 @@ push_local_extern_decl_alias (tree decl)
 
          /* Expected default linkage is from the namespace.  */
          TREE_PUBLIC (alias) = TREE_PUBLIC (ns);
-         alias = do_pushdecl_with_scope (alias, NAMESPACE_LEVEL (ns),
-                                         /* hiding= */true);
+         push_nested_namespace (ns);
+         alias = do_pushdecl (alias, /* hiding= */true);
+         pop_nested_namespace (ns);
        }
     }
 
@@ -3848,10 +3849,17 @@ constructor_name_p (tree name, tree type)
 /* Same as pushdecl, but define X in binding-level LEVEL.  We rely on the
    caller to set DECL_CONTEXT properly.
 
-   Note that this must only be used when X will be the new innermost
-   binding for its name, as we tack it onto the front of IDENTIFIER_BINDING
-   without checking to see if the current IDENTIFIER_BINDING comes from a
-   closer binding level than LEVEL.  */
+   Warning: For class and block-scope this must only be used when X
+   will be the new innermost binding for its name, as we tack it onto
+   the front of IDENTIFIER_BINDING without checking to see if the
+   current IDENTIFIER_BINDING comes from a closer binding level than
+   LEVEL.
+
+   Warning: For namespace scope, this will look in LEVEL for an
+   existing binding to match, but if not found will push the decl into
+   CURRENT_NAMESPACE.  Use push_nested_namespace/pushdecl/
+   pop_nested_namespace if you really need to push it into a foreign
+   namespace.  */
 
 static tree
 do_pushdecl_with_scope (tree x, cp_binding_level *level, bool hiding = false)
diff --git a/gcc/testsuite/g++.dg/lookup/extern-redecl2.C b/gcc/testsuite/g++.dg/lookup/extern-redecl2.C
new file mode 100644 (file)
index 0000000..9c5caa6
--- /dev/null
@@ -0,0 +1,18 @@
+// PR 97395
+// ICE injecting hidden decl in wrong namespace
+
+namespace pr {
+  template<typename WW>
+  void
+  kp ()
+  {
+    extern WW hz;
+  }
+
+  void
+  n5 ()
+  {
+    kp<int[]> ();
+    kp<int[1]> ();
+  }
+}