diff options
author | Nathan Sidwell <nathan@acm.org> | 2020-10-14 05:06:54 -0700 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2020-10-14 05:08:36 -0700 |
commit | 9068711f210e02a2b80f46813e47f338718c94dc (patch) | |
tree | b2a62b225ec9f6fb533a3c190a8dc0f8df03d1c1 | |
parent | 252c9967ba785aedf3b39e2cd50237d0f32fe3bd (diff) | |
download | gcc-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.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lookup/extern-redecl2.C | 18 |
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]> (); + } +} |