diff mbox

[C++] PR 26155

Message ID 4FC51630.4000709@oracle.com
State New
Headers show

Commit Message

Paolo Carlini May 29, 2012, 6:32 p.m. UTC
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.carlini@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.carlini@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 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);
diff mbox

Patch

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);