Hi,

in this pretty old issue we crash for this testcase:

namespace N
{
  namespace M = N;
  namespace M {}    // { dg-error "namespace alias" }
}

after the error message, because error recovery after error fails. We try to do:

          error ("namespace alias %qD not allowed here, assuming %qD",
             d, DECL_NAMESPACE_ALIAS (d));
          d = DECL_NAMESPACE_ALIAS (d);

but then we crash in resume_scope because:

  /* Also, resuming a non-directly nested namespace is a no-no.  */
  gcc_assert (b->level_chain == current_binding_level);

Thus, in the first patch below I changed push_namespace to stay away from this nasty situation and produce and simpler diagnostics and no special error recovery in this case: a false is returned, and the caller, cp_parser_namespace_definition, makes sure to not call a matching pop_namespace. Diagnostics is good, patch passes testing.

Alternately, the second patch below does the latter unconditionally, without even trying the "assuming" thing. Same diagnostics for the testcase at issue, no regressions in this case too. I don't have a strong personal preference, I suppose the current "assuming" thing may lead to fewer cascading errors, but I don't know for sure, certainly the second patch is simpler.

Thanks,
Paolo.

////////////////////////////////
/cp
2012-05-29  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/26155
        * name-lookup.c (push_namespace): Simply return false after error
        when error recovery is impossible.
        * name-lookup.h (push_namespace): Update prototype.
        * parser.c (cp_parser_namespace_definition): Chech push_namespace
        return value and don't call pop_namespace when false.

/testsuite
2012-05-29  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/26155
        * g++.dg/parse/namespace-alias-1.C: New.

Index: testsuite/g++.dg/parse/namespace-alias-1.C
===================================================================
--- testsuite/g++.dg/parse/namespace-alias-1.C  (revision 0)
+++ testsuite/g++.dg/parse/namespace-alias-1.C  (revision 0)
@@ -0,0 +1,7 @@
+// PR c++/26155
+
+namespace N
+{
+  namespace M = N;
+  namespace M {}    // { dg-error "namespace alias" }
+}
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 187968)
+++ cp/parser.c (working copy)
@@ -14738,6 +14738,7 @@ cp_parser_namespace_definition (cp_parser* parser)
   tree identifier, attribs;
   bool has_visibility;
   bool is_inline;
+  bool ok;
 
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
     {
@@ -14766,7 +14767,7 @@ cp_parser_namespace_definition (cp_parser* parser)
   /* Look for the `{' to start the namespace.  */
   cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
   /* Start the namespace.  */
-  push_namespace (identifier);
+  ok = push_namespace (identifier);
 
   /* "inline namespace" is equivalent to a stub namespace definition
      followed by a strong using directive.  */
@@ -14792,7 +14793,8 @@ cp_parser_namespace_definition (cp_parser* parser)
     pop_visibility (1);
 
   /* Finish the namespace.  */
-  pop_namespace ();
+  if (ok)
+    pop_namespace ();
   /* Look for the final `}'.  */
   cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
 }
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c    (revision 187968)
+++ cp/name-lookup.c    (working copy)
@@ -3512,9 +3512,10 @@ handle_namespace_attrs (tree ns, tree attributes)
 }
   
 /* Push into the scope of the NAME namespace.  If NAME is NULL_TREE, then we
-   select a name that is unique to this compilation unit.  */
+   select a name that is unique to this compilation unit.  Return false if
+   something goes very badly wrong, true otherwise.  */
 
-void
+bool
 push_namespace (tree name)
 {
   tree d = NULL_TREE;
@@ -3544,12 +3545,23 @@ push_namespace (tree name)
       d = IDENTIFIER_NAMESPACE_VALUE (name);
       if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL)
        {
+         tree dna = DECL_NAMESPACE_ALIAS (d);
          need_new = 0;
-         if (DECL_NAMESPACE_ALIAS (d))
+         if (dna)
            {
-             error ("namespace alias %qD not allowed here, assuming %qD",
-                    d, DECL_NAMESPACE_ALIAS (d));
-             d = DECL_NAMESPACE_ALIAS (d);
+             if (NAMESPACE_LEVEL (dna)->level_chain
+                 == current_binding_level)
+               {
+                 error ("namespace alias %qD not allowed here, "
+                        "assuming %qD", d, dna);
+                 d = dna;
+               }
+             else
+               {
+                 error ("namespace alias %qD not allowed here", d);
+                 timevar_cond_stop (TV_NAME_LOOKUP, subtime);
+                 return false;
+               }
            }
        }
     }
@@ -3583,6 +3595,7 @@ push_namespace (tree name)
   current_namespace = d;
 
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
+  return true;
 }
 
 /* Pop from the scope of the current namespace.  */
Index: cp/name-lookup.h
===================================================================
--- cp/name-lookup.h    (revision 187968)
+++ cp/name-lookup.h    (working copy)
@@ -308,7 +308,7 @@ extern tree push_inner_scope (tree);
 extern void pop_inner_scope (tree, tree);
 extern void push_binding_level (cp_binding_level *);
 
-extern void push_namespace (tree);
+extern bool push_namespace (tree);
 extern void pop_namespace (void);
 extern void push_nested_namespace (tree);
 extern void pop_nested_namespace (tree);
Index: testsuite/g++.dg/parse/namespace-alias-1.C
===================================================================
--- testsuite/g++.dg/parse/namespace-alias-1.C  (revision 0)
+++ testsuite/g++.dg/parse/namespace-alias-1.C  (revision 0)
@@ -0,0 +1,7 @@
+// PR c++/26155
+
+namespace N
+{
+  namespace M = N;
+  namespace M {}    // { dg-error "namespace alias" }
+}
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 187968)
+++ cp/parser.c (working copy)
@@ -14738,6 +14738,7 @@ cp_parser_namespace_definition (cp_parser* parser)
   tree identifier, attribs;
   bool has_visibility;
   bool is_inline;
+  bool ok;
 
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
     {
@@ -14766,7 +14767,7 @@ cp_parser_namespace_definition (cp_parser* parser)
   /* Look for the `{' to start the namespace.  */
   cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE);
   /* Start the namespace.  */
-  push_namespace (identifier);
+  ok = push_namespace (identifier);
 
   /* "inline namespace" is equivalent to a stub namespace definition
      followed by a strong using directive.  */
@@ -14792,7 +14793,8 @@ cp_parser_namespace_definition (cp_parser* parser)
     pop_visibility (1);
 
   /* Finish the namespace.  */
-  pop_namespace ();
+  if (ok)
+    pop_namespace ();
   /* Look for the final `}'.  */
   cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
 }
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c    (revision 187968)
+++ cp/name-lookup.c    (working copy)
@@ -3512,9 +3512,10 @@ handle_namespace_attrs (tree ns, tree attributes)
 }
   
 /* Push into the scope of the NAME namespace.  If NAME is NULL_TREE, then we
-   select a name that is unique to this compilation unit.  */
+   select a name that is unique to this compilation unit.  Return false if
+   something goes badly wrong, true otherwise.  */
 
-void
+bool
 push_namespace (tree name)
 {
   tree d = NULL_TREE;
@@ -3547,9 +3548,9 @@ push_namespace (tree name)
          need_new = 0;
          if (DECL_NAMESPACE_ALIAS (d))
            {
-             error ("namespace alias %qD not allowed here, assuming %qD",
-                    d, DECL_NAMESPACE_ALIAS (d));
-             d = DECL_NAMESPACE_ALIAS (d);
+             error ("namespace alias %qD not allowed here", d);
+             timevar_cond_stop (TV_NAME_LOOKUP, subtime);
+             return false;
            }
        }
     }
@@ -3583,6 +3584,7 @@ push_namespace (tree name)
   current_namespace = d;
 
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
+  return true;
 }
 
 /* Pop from the scope of the current namespace.  */
Index: cp/name-lookup.h
===================================================================
--- cp/name-lookup.h    (revision 187968)
+++ cp/name-lookup.h    (working copy)
@@ -308,7 +308,7 @@ extern tree push_inner_scope (tree);
 extern void pop_inner_scope (tree, tree);
 extern void push_binding_level (cp_binding_level *);
 
-extern void push_namespace (tree);
+extern bool push_namespace (tree);
 extern void pop_namespace (void);
 extern void push_nested_namespace (tree);
 extern void pop_nested_namespace (tree);

Reply via email to