This fixes 81247. There are two parts,
firstly it seems pointless to parse try and parse a namespace body when
there's a missing '{'. I changed the parser to immediately close the
new namespace and return in that case.
However, the bug is in my updated do_pushdecl handling. When the
incoming decl's CONTEXT is not CURRENT_NAMESPACE, we search the context
for a matching decl, but push into CURRENT_NAMESPACE if there's no
match. But I'd not updated OLD, which holds the current binding for
UPDATE_BINDING's use. In this case that meant we silently smashed the
existing binding to a namespace.
This behaviour of pushing into current namespace does seem odd, but it's
what the previous code did. I don't fully understand why.
nathan
--
Nathan Sidwell
2017-06-29 Nathan Sidwell <nat...@acm.org>
PR c++/81247
* parser.c (cp_parser_namespace_definition): Immediately close the
namespace if there's no open-brace.
* name-lookup.c (do_pushdecl): Reset OLD when pushing into new
namespace.
PR c++/81247
* g++.dg/parse/pr81247-[abc].C: New.
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c (revision 249796)
+++ cp/name-lookup.c (working copy)
@@ -2422,6 +2422,9 @@ do_pushdecl (tree decl, bool is_friend)
{
ns = current_namespace;
slot = find_namespace_slot (ns, name, true);
+ /* Update OLD to reflect the namespace we're going to be
+ pushing into. */
+ old = MAYBE_STAT_DECL (*slot);
}
old = update_binding (level, binding, slot, old, decl, is_friend);
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 249796)
+++ cp/parser.c (working copy)
@@ -18397,13 +18397,14 @@ cp_parser_namespace_definition (cp_parse
warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace);
/* Look for the `{' to validate starting the namespace. */
- cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
+ if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+ {
+ /* Parse the body of the namespace. */
+ cp_parser_namespace_body (parser);
- /* Parse the body of the namespace. */
- cp_parser_namespace_body (parser);
-
- /* Look for the final `}'. */
- cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+ /* Look for the final `}'. */
+ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+ }
if (has_visibility)
pop_visibility (1);
Index: testsuite/g++.dg/parse/pr81247-a.C
===================================================================
--- testsuite/g++.dg/parse/pr81247-a.C (revision 0)
+++ testsuite/g++.dg/parse/pr81247-a.C (working copy)
@@ -0,0 +1,13 @@
+// PR c++/81247 ICE
+
+namespace N // { dg-message "previous declaration" }
+// { dg-error "expected" "" { target *-*-* } .+1 }
+template < typename T > class A
+{ // { dg-error "redeclared as different" }
+ template < T > friend class N;
+};
+
+void f ()
+{
+ A < int > a1; // { dg-message "required from here" }
+}
Index: testsuite/g++.dg/parse/pr81247-b.C
===================================================================
--- testsuite/g++.dg/parse/pr81247-b.C (revision 0)
+++ testsuite/g++.dg/parse/pr81247-b.C (working copy)
@@ -0,0 +1,14 @@
+// PR c++/81247 confused error
+
+namespace N { // { dg-message "previous declaration" }
+}
+
+template < typename T > class A
+{ // { dg-error "redeclared as different" }
+ template < T > friend class N;
+};
+
+void f ()
+{
+ A < int > a1;
+}
Index: testsuite/g++.dg/parse/pr81247-c.C
===================================================================
--- testsuite/g++.dg/parse/pr81247-c.C (revision 0)
+++ testsuite/g++.dg/parse/pr81247-c.C (working copy)
@@ -0,0 +1,13 @@
+// PR c++/81247 confused error
+
+namespace N { // { dg-message "previous declaration" }
+ template < typename T > class A
+ { // { dg-error "conflicts with a previous" }
+ template < T > friend class N;
+ };
+}
+
+void f ()
+{
+ N::A < int > a1;
+}