From 782d1c333f42c650699be7f7f4679c38ab544ecd Mon Sep 17 00:00:00 2001
From: Nathan Froyd <froydnj@codesourcery.com>
Date: Thu, 16 Dec 2010 01:36:09 +0000
Subject: [PATCH] re PR c++/39859 (duplicated and unhelpful error for "c:n"
 (parser))

gcc/cp/
	PR c++/39859
	PR c++/44522
	PR c++/44523
	* parser.c (struct cp_parser): Add colon_corrects_to_scope_p field.
	(cp_parser_new): Initialize it.
	(cp_parser_nested_name_specifier_opt): Auto-correct colons to
	scopes if we are able to.
	(cp_parser_question_colon_clause): Disallow colon correction.
	(cp_parser_label_for_labeled_statement): Likewise.
	(cp_parser_range_for): Likewise.
	(cp_parser_enum_specifier): Likewise.
	(cp_parser_class_head): Likewise.
	(cp_parser_member_declaration): Likewise.

gcc/testsuite/
	PR c++/39859
	PR c++/44522
	PR c++/44523
	* g++.dg/parse/colon-autocorrect-1.C: New testcase.
	* g++.dg/parse/colon-autocorrect-2.C: New testcase.

From-SVN: r167895
---
 gcc/cp/ChangeLog                              | 16 ++++
 gcc/cp/parser.c                               | 73 ++++++++++++++++---
 gcc/testsuite/ChangeLog                       |  8 ++
 .../g++.dg/parse/colon-autocorrect-1.C        | 31 ++++++++
 .../g++.dg/parse/colon-autocorrect-2.C        | 15 ++++
 5 files changed, 132 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/parse/colon-autocorrect-1.C
 create mode 100644 gcc/testsuite/g++.dg/parse/colon-autocorrect-2.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e6a9610b29b0..0d46bcca404d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,19 @@
+2010-12-15  Nathan Froyd  <froydnj@codesourcery.com>
+
+	PR c++/39859
+	PR c++/44522
+	PR c++/44523
+	* parser.c (struct cp_parser): Add colon_corrects_to_scope_p field.
+	(cp_parser_new): Initialize it.
+	(cp_parser_nested_name_specifier_opt): Auto-correct colons to
+	scopes if we are able to.
+	(cp_parser_question_colon_clause): Disallow colon correction.
+	(cp_parser_label_for_labeled_statement): Likewise.
+	(cp_parser_range_for): Likewise.
+	(cp_parser_enum_specifier): Likewise.
+	(cp_parser_class_head): Likewise.
+	(cp_parser_member_declaration): Likewise.
+
 2010-12-15  Nathan Froyd  <froydnj@codesourcery.com>
 
 	PR c++/46852
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index cb8b79782ef8..3e6930f2c49f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1700,6 +1700,9 @@ typedef struct GTY(()) cp_parser {
      a local class.  */
   bool in_function_body;
 
+  /* TRUE if we can auto-correct a colon to a scope operator.  */
+  bool colon_corrects_to_scope_p;
+
   /* If non-NULL, then we are parsing a construct where new type
      definitions are not permitted.  The string stored here will be
      issued as an error message if a type is defined.  */
@@ -3244,6 +3247,9 @@ cp_parser_new (void)
   /* We are not parsing a function body.  */
   parser->in_function_body = false;
 
+  /* We can correct until told otherwise.  */
+  parser->colon_corrects_to_scope_p = true;
+
   /* The unparsed function queue is empty.  */
   push_unparsed_function_queues (parser);
 
@@ -4553,6 +4559,16 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
 	     template-id), nor a `::', then we are not looking at a
 	     nested-name-specifier.  */
 	  token = cp_lexer_peek_nth_token (parser->lexer, 2);
+
+	  if (token->type == CPP_COLON
+	      && parser->colon_corrects_to_scope_p
+	      && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME)
+	    {
+	      error_at (token->location,
+			"found %<:%> in nested-name-specifier, expected %<::%>");
+	      token->type = CPP_SCOPE;
+	    }
+
 	  if (token->type != CPP_SCOPE
 	      && !cp_parser_nth_token_starts_template_argument_list_p
 		  (parser, 2))
@@ -6955,12 +6971,15 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
     }
   else
     {
+      bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+      parser->colon_corrects_to_scope_p = false;
       /* Parse the expression.  */
       c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
       expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
       c_inhibit_evaluation_warnings +=
 	((logical_or_expr == truthvalue_true_node)
 	 - (logical_or_expr == truthvalue_false_node));
+      parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
     }
 
   /* The next token should be a `:'.  */
@@ -8153,6 +8172,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser)
 {
   cp_token *token;
   tree label = NULL_TREE;
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
 
   /* The next token should be an identifier.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -8163,6 +8183,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser)
       return;
     }
 
+  parser->colon_corrects_to_scope_p = false;
   switch (token->keyword)
     {
     case RID_CASE:
@@ -8241,6 +8262,8 @@ cp_parser_label_for_labeled_statement (cp_parser* parser)
       else
 	cplus_decl_attributes (&label, attrs, 0);
     }
+
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
 }
 
 /* Parse an expression-statement.
@@ -8710,7 +8733,9 @@ cp_parser_range_for (cp_parser *parser)
   cp_declarator *declarator;
   const char *saved_message;
   tree attributes, pushed_scope;
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
 
+  parser->colon_corrects_to_scope_p = false;
   cp_parser_parse_tentatively (parser);
   /* New types are not allowed in the type-specifier-seq for a
      range-based for loop.  */
@@ -8727,7 +8752,8 @@ cp_parser_range_for (cp_parser *parser)
   if (cp_parser_error_occurred (parser))
     {
       cp_parser_abort_tentative_parse (parser);
-      return NULL_TREE;
+      stmt = NULL_TREE;
+      goto out;
     }
   /* Parse the declarator.  */
   declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -8774,6 +8800,8 @@ cp_parser_range_for (cp_parser *parser)
     /* Convert the range-based for loop into a normal for-statement. */
     stmt = cp_convert_range_for (stmt, range_decl, range_expr);
 
+ out:
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
   return stmt;
 }
 
@@ -13343,6 +13371,9 @@ cp_parser_enum_specifier (cp_parser* parser)
   bool is_anonymous = false;
   tree underlying_type = NULL_TREE;
   cp_token *type_start_token = NULL;
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+  parser->colon_corrects_to_scope_p = false;
 
   /* Parse tentatively so that we can back up if we don't find a
      enum-specifier.  */
@@ -13470,7 +13501,10 @@ cp_parser_enum_specifier (cp_parser* parser)
 	{
 	  cp_parser_error (parser, "expected %<{%>");
 	  if (has_underlying_type)
-	    return NULL_TREE;
+	    {
+	      type = NULL_TREE;
+	      goto out;
+	    }
 	}
       /* An opaque-enum-specifier must have a ';' here.  */
       if ((scoped_enum_p || underlying_type)
@@ -13478,7 +13512,10 @@ cp_parser_enum_specifier (cp_parser* parser)
 	{
 	  cp_parser_error (parser, "expected %<;%> or %<{%>");
 	  if (has_underlying_type)
-	    return NULL_TREE;
+	    {
+	      type = NULL_TREE;
+	      goto out;
+	    }
 	}
     }
 
@@ -13622,6 +13659,8 @@ cp_parser_enum_specifier (cp_parser* parser)
 	  pop_nested_namespace (nested_name_specifier);
 	}
     }
+ out:
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
   return type;
 }
 
@@ -17087,6 +17126,7 @@ cp_parser_class_head (cp_parser* parser,
   bool qualified_p = false;
   bool invalid_nested_name_p = false;
   bool invalid_explicit_specialization_p = false;
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
   tree pushed_scope = NULL_TREE;
   unsigned num_templates;
   cp_token *type_start_token = NULL, *nested_name_specifier_token_start = NULL;
@@ -17095,6 +17135,7 @@ cp_parser_class_head (cp_parser* parser,
   /* Assume no template parameter lists will be used in defining the
      type.  */
   num_templates = 0;
+  parser->colon_corrects_to_scope_p = false;
 
   *bases = NULL_TREE;
 
@@ -17234,7 +17275,8 @@ cp_parser_class_head (cp_parser* parser,
   if (!cp_parser_next_token_starts_class_definition_p (parser))
     {
       cp_parser_error (parser, "expected %<{%> or %<:%>");
-      return error_mark_node;
+      type = error_mark_node;
+      goto out;
     }
 
   /* At this point, we're going ahead with the class-specifier, even
@@ -17245,13 +17287,15 @@ cp_parser_class_head (cp_parser* parser,
     {
       cp_parser_error (parser,
 		       "global qualification of class name is invalid");
-      return error_mark_node;
+      type = error_mark_node;
+      goto out;
     }
   else if (invalid_nested_name_p)
     {
       cp_parser_error (parser,
 		       "qualified name does not name a class");
-      return error_mark_node;
+      type = error_mark_node;
+      goto out;
     }
   else if (nested_name_specifier)
     {
@@ -17454,6 +17498,8 @@ cp_parser_class_head (cp_parser* parser,
   if (type)
     DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
   *attributes_p = attributes;
+ out:
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
   return type;
 }
 
@@ -17582,6 +17628,7 @@ cp_parser_member_declaration (cp_parser* parser)
   cp_token *decl_spec_token_start = NULL;
   cp_token *initializer_token_start = NULL;
   int saved_pedantic;
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
 
   /* Check for the `__extension__' keyword.  */
   if (cp_parser_extension_opt (parser, &saved_pedantic))
@@ -17640,8 +17687,10 @@ cp_parser_member_declaration (cp_parser* parser)
       return;
     }
 
+  parser->colon_corrects_to_scope_p = false;
+
   if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
-    return;
+    goto out;
 
   /* Parse the decl-specifier-seq.  */
   decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
@@ -17654,7 +17703,7 @@ cp_parser_member_declaration (cp_parser* parser)
   /* Check for an invalid type-name.  */
   if (!decl_specifiers.any_type_specifiers_p
       && cp_parser_parse_and_diagnose_invalid_type_name (parser))
-    return;
+    goto out;
   /* If there is no declarator, then the decl-specifier-seq should
      specify a type.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
@@ -17824,7 +17873,7 @@ cp_parser_member_declaration (cp_parser* parser)
 		  if (cp_lexer_next_token_is (parser->lexer,
 					      CPP_SEMICOLON))
 		    cp_lexer_consume_token (parser->lexer);
-		  return;
+		  goto out;
 		}
 
 	      if (declares_class_or_enum & 2)
@@ -17903,7 +17952,7 @@ cp_parser_member_declaration (cp_parser* parser)
 		  /* If the next token is a semicolon, consume it.  */
 		  if (token->type == CPP_SEMICOLON)
 		    cp_lexer_consume_token (parser->lexer);
-		  return;
+		  goto out;
 		}
 	      else
 		if (declarator->kind == cdk_function)
@@ -17958,11 +18007,13 @@ cp_parser_member_declaration (cp_parser* parser)
 	    }
 
 	  if (assume_semicolon)
-	    return;
+	    goto out;
 	}
     }
 
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+ out:
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
 }
 
 /* Parse a pure-specifier.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 94a48eb098b3..7de0beae8a82 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2010-12-15  Nathan Froyd  <froydnj@codesourcery.com>
+
+	PR c++/39859
+	PR c++/44522
+	PR c++/44523
+	* g++.dg/parse/colon-autocorrect-1.C: New testcase.
+	* g++.dg/parse/colon-autocorrect-2.C: New testcase.
+
 2010-12-15  Nathan Froyd  <froydnj@codesourcery.com>
 
 	PR c++/46852
diff --git a/gcc/testsuite/g++.dg/parse/colon-autocorrect-1.C b/gcc/testsuite/g++.dg/parse/colon-autocorrect-1.C
new file mode 100644
index 000000000000..8e25fbac21ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/colon-autocorrect-1.C
@@ -0,0 +1,31 @@
+// PR c++/44522
+// { dg-do compile }
+
+namespace x {
+  struct a { };
+  a A0;
+}
+
+x:a a2;				// { dg-error "nested-name-specifier" }
+x::a a3 = a2;
+
+x:a f (void)			// { dg-error "nested-name-specifier" }
+{
+  x::a a4;			// x:a would parse like a label
+  return a4;
+}
+
+x::a g (x:a a4)			// { dg-error "nested-name-specifier" }
+{
+  return a4;
+}
+
+class B
+{
+  x::a f(void)			// x:a would parse like a bitfield
+  {
+    x::a a4;
+    a4 = x:A0;			// { dg-error "nested-name-specifier" }
+    return a4;
+  }
+};
diff --git a/gcc/testsuite/g++.dg/parse/colon-autocorrect-2.C b/gcc/testsuite/g++.dg/parse/colon-autocorrect-2.C
new file mode 100644
index 000000000000..1dfcbc0681ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/colon-autocorrect-2.C
@@ -0,0 +1,15 @@
+// PR c++/44523
+// { dg-do compile }
+
+namespace x {
+  struct a { };
+}
+
+template <typename t>
+class foo {
+};
+
+foo<x::a> a1;
+foo<x:a> a2;			// { dg-error "nested-name-specifier" }
+
+x::a a3 = a2;			// { dg-error "conversion" }
-- 
GitLab