aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-10-14 05:06:54 -0700
committerNathan Sidwell <nathan@acm.org>2020-10-14 05:08:36 -0700
commit9068711f210e02a2b80f46813e47f338718c94dc (patch)
treeb2a62b225ec9f6fb533a3c190a8dc0f8df03d1c1
parent252c9967ba785aedf3b39e2cd50237d0f32fe3bd (diff)
downloadgcc-9068711f210e02a2b80f46813e47f338718c94dc.zip
gcc-9068711f210e02a2b80f46813e47f338718c94dc.tar.gz
gcc-9068711f210e02a2b80f46813e47f338718c94dc.tar.bz2
c++: Instantiation with local extern [PR97395]
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.
-rw-r--r--gcc/cp/name-lookup.c22
-rw-r--r--gcc/testsuite/g++.dg/lookup/extern-redecl2.C18
2 files changed, 33 insertions, 7 deletions
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index e3f3712..5dcaab4 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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
index 0000000..9c5caa6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/extern-redecl2.C
@@ -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]> ();
+ }
+}