Patchwork [C++0x] avoid extra tentative parse in range-based for loops

login
register
mail settings
Submitter Rodrigo Rivas
Date Dec. 27, 2010, 3:41 p.m.
Message ID <AANLkTikxjg1MXh52qAeyv6POcG_0pOL3baM4sjudhJKu@mail.gmail.com>
Download mbox | patch
Permalink /patch/76794/
State New
Headers show

Comments

Rodrigo Rivas - Dec. 27, 2010, 3:41 p.m.
On Wed, Dec 22, 2010 at 6:37 PM, Jason Merrill <jason@redhat.com> wrote:
> As you mentioned, this now needs a tweak for the colon autocorrect patch.
Ok. I've added it to cp_parser_for_init_statement, as it is here where
the colon is parsed.

>>       /* If the tentative parse failed, then we shall need to look for an
>>         expression-statement.  */
>
> This comment is in the wrong place now; it should stay with the call to
> cp_parser_parse_definitely.
Right. Moved.

>> +      if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
>> +       {
>> +         /* It is a range-for, consume the ':' */
>> +         cp_lexer_consume_token (parser->lexer);
>> +         if (cxx_dialect < cxx0x)
>> +           {
>> +             error_at (cp_lexer_peek_token (parser->lexer)->location,
>> +                       "range-based-for loops are not allowed "
>> +                       "in C++98 mode");
>> +           }
>> +         else if (*decl && *decl != error_mark_node )
>> +           is_range_for = true;
>> +         /* Else an error has been found in the declaration. It should
>> have
>> +            been reported by now, so no message is required.  */
>> +       }
>
> I think error-recovery will be better if we always set is_range_for when we
> see a colon.
Even if we are in cxx98 mode? Certainly we would avoid a cascade of errors.

What do you think of the proposed patch? I added a few tests for
error_mark_node to avoid cascaded errors once the first has been
reported. Also, the testcase range-for9.C now emits just one error
(the right one).

Regards.
Rodrigo

--

Changelog:

gcc/cp/

2010-12-27  Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>

	* cp-tree.h (begin_for_scope): New prototype.
	(begin_for_stmt): Update prototype.
	(begin_range_for_stmt): Update prototype.
	* init.c (build_vec_init): Update call to begin_for_stmt.
	* parser.c (cp_parser_for): New.
	(cp_parser_c_for): Add three new parameters.
	(cp_parser_range_for): Likewise. Most parsing code removed.
	(cp_parser_iteration_statement): Call cp_parser_for instead of
	cp_parser_c_for and cp_parser_range_for.
	(cp_parser_for_init_statement): Add new parameter and return type.
	(cp_parser_block_declaration): Update call to
	cp_parser_simple_declaration.
	(cp_parser_simple_declaration): Add new parameter.
	Update call to cp_parser_init_declarator.
	(cp_parser_init_declarator): Add new parameter.
	* pt.c (tsubst_expr): Update call to begin_for_stmt.
	* semantics.c (begin_for_scope): New.
	(begin_for_stmt): Add two new parameters.
	(begin_range_for_stmt): Likewise.

gcc/testsuite/

2010-12-27  Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>

	* g++.dg/cpp0x/range-for4.C: Delete useless include and duplicated
	comment.
	* g++.dg/cpp0x/range-for8.C: New.
	* g++.dg/cpp0x/range-for9.C: New.
Jason Merrill - Jan. 12, 2011, 11:53 p.m.
Applied, sorry for the delay.

Jason

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7b18973..dddbc01 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5214,12 +5214,13 @@  extern tree begin_do_stmt			(void);
 extern void finish_do_body			(tree);
 extern void finish_do_stmt			(tree, tree);
 extern tree finish_return_stmt			(tree);
-extern tree begin_for_stmt			(void);
+extern tree begin_for_scope			(tree *);
+extern tree begin_for_stmt			(tree, tree);
 extern void finish_for_init_stmt		(tree);
 extern void finish_for_cond			(tree, tree);
 extern void finish_for_expr			(tree, tree);
 extern void finish_for_stmt			(tree);
-extern tree begin_range_for_stmt		(void);
+extern tree begin_range_for_stmt		(tree, tree);
 extern void finish_range_for_decl		(tree, tree, tree);
 extern void finish_range_for_stmt		(tree);
 extern tree finish_break_stmt			(void);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 9c3dd32..2075649 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3117,7 +3117,7 @@  build_vec_init (tree base, tree maxindex, tree init,
       tree elt_init;
       tree to;
 
-      for_stmt = begin_for_stmt ();
+      for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
       finish_for_init_stmt (for_stmt);
       finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 743d774..71e13d1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1863,12 +1863,14 @@  static tree cp_parser_condition
   (cp_parser *);
 static tree cp_parser_iteration_statement
   (cp_parser *);
-static void cp_parser_for_init_statement
-  (cp_parser *);
-static tree  cp_parser_c_for
-  (cp_parser *);
-static tree  cp_parser_range_for
+static bool cp_parser_for_init_statement
+  (cp_parser *, tree *decl);
+static tree cp_parser_for
   (cp_parser *);
+static tree cp_parser_c_for
+  (cp_parser *, tree, tree);
+static tree cp_parser_range_for
+  (cp_parser *, tree, tree, tree);
 static tree cp_parser_jump_statement
   (cp_parser *);
 static void cp_parser_declaration_statement
@@ -1888,7 +1890,7 @@  static void cp_parser_declaration
 static void cp_parser_block_declaration
   (cp_parser *, bool);
 static void cp_parser_simple_declaration
-  (cp_parser *, bool);
+  (cp_parser *, bool, tree *);
 static void cp_parser_decl_specifier_seq
   (cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, int *);
 static tree cp_parser_storage_class_specifier_opt
@@ -1938,7 +1940,7 @@  static tree cp_parser_decltype
 /* Declarators [gram.dcl.decl] */
 
 static tree cp_parser_init_declarator
-  (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *);
+  (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *, tree *);
 static cp_declarator *cp_parser_declarator
   (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
 static cp_declarator *cp_parser_direct_declarator
@@ -8696,21 +8698,38 @@  cp_parser_condition (cp_parser* parser)
   return cp_parser_expression (parser, /*cast_p=*/false, NULL);
 }
 
-/* Parses a traditional for-statement until the closing ')', not included. */
+/* Parses a for-statement or range-for-statement until the closing ')',
+   not included. */
 
 static tree
-cp_parser_c_for (cp_parser *parser)
+cp_parser_for (cp_parser *parser)
 {
-  /* Normal for loop */
-  tree stmt;
-  tree condition = NULL_TREE;
-  tree expression = NULL_TREE;
+  tree init, scope, decl;
+  bool is_range_for;
 
   /* Begin the for-statement.  */
-  stmt = begin_for_stmt ();
+  scope = begin_for_scope (&init);
 
   /* Parse the initialization.  */
-  cp_parser_for_init_statement (parser);
+  is_range_for = cp_parser_for_init_statement (parser, &decl);
+
+  if (is_range_for)
+    return cp_parser_range_for (parser, scope, init, decl);
+  else
+    return cp_parser_c_for (parser, scope, init);
+}
+
+static tree
+cp_parser_c_for (cp_parser *parser, tree scope, tree init)
+{
+  /* Normal for loop */
+  tree condition = NULL_TREE;
+  tree expression = NULL_TREE;
+  tree stmt;
+
+  stmt = begin_for_stmt (scope, init);
+  /* The for-init-statement has already been parsed in
+     cp_parser_for_init_statement, so no work is needed here.  */
   finish_for_init_stmt (stmt);
 
   /* If there's a condition, process it.  */
@@ -8731,60 +8750,27 @@  cp_parser_c_for (cp_parser *parser)
 /* Tries to parse a range-based for-statement:
 
   range-based-for:
-    type-specifier-seq declarator : expression
-
-  If succesful, assigns to *DECL the DECLARATOR and to *EXPR the
-  expression. Note that the *DECL is returned unfinished, so
-  later you should call cp_finish_decl().
+    decl-specifier-seq declarator : expression
 
-  Returns TRUE iff a range-based for is parsed. */
+  The decl-specifier-seq declarator and the `:' are already parsed by
+  cp_parser_for_init_statement. If processing_template_decl it returns a
+  newly created RANGE_FOR_STMT; if not, it is converted to a
+  regular FOR_STMT.  */
 
 static tree
-cp_parser_range_for (cp_parser *parser)
+cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
 {
-  tree stmt, range_decl, range_expr;
-  cp_decl_specifier_seq type_specifiers;
-  cp_declarator *declarator;
-  const char *saved_message;
-  tree attributes, pushed_scope;
-  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+  tree stmt, range_expr;
 
-  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.  */
-  saved_message = parser->type_definition_forbidden_message;
-  parser->type_definition_forbidden_message
-    = G_("types may not be defined in range-based for loops");
-  /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, /*is_declaration==*/true,
-				/*is_trailing_return=*/false,
-				&type_specifiers);
-  /* Restore the saved message.  */
-  parser->type_definition_forbidden_message = saved_message;
-  /* If all is well, we might be looking at a declaration.  */
-  if (cp_parser_error_occurred (parser))
+  /* If the variable from a range-for is not actually used, GCC would issue
+     "unused variable" warnings, and the user could do little to prevent them.
+     So we always mark it as used.  */
+  if (range_decl != error_mark_node)
     {
-      cp_parser_abort_tentative_parse (parser);
-      stmt = NULL_TREE;
-      goto out;
+      TREE_USED (range_decl) = 1;
+      DECL_READ_P (range_decl) = 1;
     }
-  /* Parse the declarator.  */
-  declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
-				     /*ctor_dtor_or_conv_p=*/NULL,
-				     /*parenthesized_p=*/NULL,
-				     /*member_p=*/false);
-  /* Parse the attributes.  */
-  attributes = cp_parser_attributes_opt (parser);
-  /* The next token should be `:'. */
-  if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
-    cp_parser_simulate_error (parser);
 
-  /* Check if it is a range-based for */
-  if (!cp_parser_parse_definitely (parser))
-    return NULL_TREE;
-
-  cp_parser_require (parser, CPP_COLON, RT_COLON);
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     {
       bool expr_non_constant_p;
@@ -8793,29 +8779,18 @@  cp_parser_range_for (cp_parser *parser)
   else
     range_expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
 
-  /* If in template, STMT is converted to a normal for-statements
+  /* If in template, STMT is converted to a normal for-statement
      at instantiation. If not, it is done just ahead. */
   if (processing_template_decl)
-    stmt = begin_range_for_stmt ();
-  else
-    stmt = begin_for_stmt ();
-
-  /* Create the declaration. It must be after begin{,_range}_for_stmt(). */
-  range_decl = start_decl (declarator, &type_specifiers,
-			   /*initialized_p=*/SD_INITIALIZED,
-			   attributes, /*prefix_attributes=*/NULL_TREE,
-			   &pushed_scope);
-  /* No scope allowed here */
-  pop_scope (pushed_scope);
-
-  if (TREE_CODE (stmt) == RANGE_FOR_STMT)
-    finish_range_for_decl (stmt, range_decl, range_expr);
+    {
+      stmt = begin_range_for_stmt (scope, init);
+      finish_range_for_decl (stmt, range_decl, range_expr);
+    }
   else
-    /* 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;
+    {
+      stmt = begin_for_stmt (scope, init);
+      stmt = cp_convert_range_for (stmt, range_decl, range_expr);
+    }
   return stmt;
 }
 
@@ -8856,63 +8831,71 @@  cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
   tree iter_type, begin_expr, end_expr;
   tree condition, expression;
 
-  /* Find out the type deduced by the declaration
-   * `auto &&__range = range_expr' */
-  range_type = cp_build_reference_type (make_auto (), true);
-  range_type = do_auto_deduction (range_type, range_expr,
-				  type_uses_auto (range_type));
-
-  /* Create the __range variable */
-  range_temp = build_decl (input_location, VAR_DECL,
-			   get_identifier ("__for_range"), range_type);
-  TREE_USED (range_temp) = 1;
-  DECL_ARTIFICIAL (range_temp) = 1;
-  pushdecl (range_temp);
-  cp_finish_decl (range_temp, range_expr,
-		  /*is_constant_init*/false, NULL_TREE,
-		  LOOKUP_ONLYCONVERTING);
-
-  range_temp = convert_from_reference (range_temp);
-
-  if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
-    {
-      /* If RANGE_TEMP is an array we will use pointer arithmetic */
-      iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
-      begin_expr = range_temp;
-      end_expr
-	= build_binary_op (input_location, PLUS_EXPR,
-			   range_temp,
-			   array_type_nelts_top (TREE_TYPE (range_temp)), 0);
-    }
+  if (range_decl == error_mark_node || range_expr == error_mark_node)
+    /* If an error happened previously do nothing or else a lot of
+       unhelpful errors would be issued.  */
+    begin_expr = end_expr = iter_type = error_mark_node;
   else
     {
-      /* If it is not an array, we must call begin(__range)/end__range() */
-      VEC(tree,gc) *vec;
-
-      begin_expr = get_identifier ("begin");
-      vec = make_tree_vector ();
-      VEC_safe_push (tree, gc, vec, range_temp);
-      begin_expr = perform_koenig_lookup (begin_expr, vec,
-					  /*include_std=*/true);
-      begin_expr = finish_call_expr (begin_expr, &vec, false, true,
-				     tf_warning_or_error);
-      release_tree_vector (vec);
-
-      end_expr = get_identifier ("end");
-      vec = make_tree_vector ();
-      VEC_safe_push (tree, gc, vec, range_temp);
-      end_expr = perform_koenig_lookup (end_expr, vec,
-					/*include_std=*/true);
-      end_expr = finish_call_expr (end_expr, &vec, false, true,
-				   tf_warning_or_error);
-      release_tree_vector (vec);
-
-      /* The unqualified type of the __begin and __end temporaries should
-      * be the same as required by the multiple auto declaration */
-      iter_type = cv_unqualified (TREE_TYPE (begin_expr));
-      if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
-	error ("inconsistent begin/end types in range-based for: %qT and %qT",
-	       TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
+      /* Find out the type deduced by the declaration
+       * `auto &&__range = range_expr' */
+      range_type = cp_build_reference_type (make_auto (), true);
+      range_type = do_auto_deduction (range_type, range_expr,
+				      type_uses_auto (range_type));
+
+      /* Create the __range variable */
+      range_temp = build_decl (input_location, VAR_DECL,
+			       get_identifier ("__for_range"), range_type);
+      TREE_USED (range_temp) = 1;
+      DECL_ARTIFICIAL (range_temp) = 1;
+      pushdecl (range_temp);
+      cp_finish_decl (range_temp, range_expr,
+		      /*is_constant_init*/false, NULL_TREE,
+		      LOOKUP_ONLYCONVERTING);
+
+      range_temp = convert_from_reference (range_temp);
+
+      if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
+	{
+	  /* If RANGE_TEMP is an array we will use pointer arithmetic */
+	  iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
+	  begin_expr = range_temp;
+	  end_expr
+	      = build_binary_op (input_location, PLUS_EXPR,
+				 range_temp,
+				 array_type_nelts_top (TREE_TYPE (range_temp)),
+				 0);
+	}
+      else
+	{
+	  /* If it is not an array, we must call begin(__range)/end__range() */
+	  VEC(tree,gc) *vec;
+
+	  begin_expr = get_identifier ("begin");
+	  vec = make_tree_vector ();
+	  VEC_safe_push (tree, gc, vec, range_temp);
+	  begin_expr = perform_koenig_lookup (begin_expr, vec,
+					      /*include_std=*/true);
+	  begin_expr = finish_call_expr (begin_expr, &vec, false, true,
+					 tf_warning_or_error);
+	  release_tree_vector (vec);
+
+	  end_expr = get_identifier ("end");
+	  vec = make_tree_vector ();
+	  VEC_safe_push (tree, gc, vec, range_temp);
+	  end_expr = perform_koenig_lookup (end_expr, vec,
+					    /*include_std=*/true);
+	  end_expr = finish_call_expr (end_expr, &vec, false, true,
+				       tf_warning_or_error);
+	  release_tree_vector (vec);
+
+	  /* The unqualified type of the __begin and __end temporaries should
+	   * be the same as required by the multiple auto declaration */
+	  iter_type = cv_unqualified (TREE_TYPE (begin_expr));
+	  if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
+	    error ("inconsistent begin/end types in range-based for: %qT and %qT",
+		   TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
+	}
     }
 
   /* The new for initialization statement */
@@ -9041,12 +9024,7 @@  cp_parser_iteration_statement (cp_parser* parser)
 	/* Look for the `('.  */
 	cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 
-	if (cxx_dialect == cxx0x)
-	  statement = cp_parser_range_for (parser);
-	else
-	  statement = NULL_TREE;
-	if (statement == NULL_TREE)
-	  statement = cp_parser_c_for (parser);
+	statement = cp_parser_for (parser);
 
 	/* Look for the `)'.  */
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -9070,14 +9048,15 @@  cp_parser_iteration_statement (cp_parser* parser)
   return statement;
 }
 
-/* Parse a for-init-statement.
+/* Parse a for-init-statement or the declarator of a range-based-for.
+   Returns true if a range-based-for declaration is seen.
 
    for-init-statement:
      expression-statement
      simple-declaration  */
 
-static void
-cp_parser_for_init_statement (cp_parser* parser)
+static bool
+cp_parser_for_init_statement (cp_parser* parser, tree *decl)
 {
   /* If the next token is a `;', then we have an empty
      expression-statement.  Grammatically, this is also a
@@ -9087,19 +9066,45 @@  cp_parser_for_init_statement (cp_parser* parser)
      declaration.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
     {
+      bool is_range_for = false;
+      bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+      parser->colon_corrects_to_scope_p = false;
+
       /* We're going to speculatively look for a declaration, falling back
 	 to an expression, if necessary.  */
       cp_parser_parse_tentatively (parser);
       /* Parse the declaration.  */
       cp_parser_simple_declaration (parser,
-				    /*function_definition_allowed_p=*/false);
+				    /*function_definition_allowed_p=*/false,
+				    decl);
+      parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+	{
+	  /* It is a range-for, consume the ':' */
+	  cp_lexer_consume_token (parser->lexer);
+	  is_range_for = true;
+	  if (cxx_dialect < cxx0x)
+	    {
+	      error_at (cp_lexer_peek_token (parser->lexer)->location,
+			"range-based-for loops are not allowed "
+			"in C++98 mode");
+	      *decl = error_mark_node;
+	    }
+	}
+      else
+	  /* The ';' is not consumed yet because we told
+	     cp_parser_simple_declaration not to.  */
+	  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+      if (cp_parser_parse_definitely (parser))
+	return is_range_for;
       /* If the tentative parse failed, then we shall need to look for an
 	 expression-statement.  */
-      if (cp_parser_parse_definitely (parser))
-	return;
     }
-
+  /* If we are here, it is an expression-statement.  */
   cp_parser_expression_statement (parser, NULL_TREE);
+  return false;
 }
 
 /* Parse a jump-statement.
@@ -9586,7 +9591,8 @@  cp_parser_block_declaration (cp_parser *parser,
     cp_parser_static_assert (parser, /*member_p=*/false);
   /* Anything else must be a simple-declaration.  */
   else
-    cp_parser_simple_declaration (parser, !statement_p);
+    cp_parser_simple_declaration (parser, !statement_p,
+				  /*maybe_range_for_decl*/NULL);
 }
 
 /* Parse a simple-declaration.
@@ -9599,16 +9605,25 @@  cp_parser_block_declaration (cp_parser *parser,
      init-declarator-list , init-declarator
 
    If FUNCTION_DEFINITION_ALLOWED_P is TRUE, then we also recognize a
-   function-definition as a simple-declaration.  */
+   function-definition as a simple-declaration.
+
+   If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the
+   parsed declaration if it is an uninitialized single declarator not followed
+   by a `;', or to error_mark_node otherwise. Either way, the trailing `;',
+   if present, will not be consumed.  */
 
 static void
 cp_parser_simple_declaration (cp_parser* parser,
-			      bool function_definition_allowed_p)
+			      bool function_definition_allowed_p,
+			      tree *maybe_range_for_decl)
 {
   cp_decl_specifier_seq decl_specifiers;
   int declares_class_or_enum;
   bool saw_declarator;
 
+  if (maybe_range_for_decl)
+    *maybe_range_for_decl = NULL_TREE;
+
   /* Defer access checks until we know what is being declared; the
      checks for names appearing in the decl-specifier-seq should be
      done as if we were in the scope of the thing being declared.  */
@@ -9683,6 +9698,8 @@  cp_parser_simple_declaration (cp_parser* parser,
 	  token = cp_lexer_peek_token (parser->lexer);
 	  gcc_assert (token->type == CPP_COMMA);
 	  cp_lexer_consume_token (parser->lexer);
+	  if (maybe_range_for_decl)
+	    *maybe_range_for_decl = error_mark_node;
 	}
       else
 	saw_declarator = true;
@@ -9693,7 +9710,8 @@  cp_parser_simple_declaration (cp_parser* parser,
 					function_definition_allowed_p,
 					/*member_p=*/false,
 					declares_class_or_enum,
-					&function_definition_p);
+					&function_definition_p,
+					maybe_range_for_decl);
       /* If an error occurred while parsing tentatively, exit quickly.
 	 (That usually happens when in the body of a function; each
 	 statement is treated as a declaration-statement until proven
@@ -9723,13 +9741,15 @@  cp_parser_simple_declaration (cp_parser* parser,
 	      return;
 	    }
 	}
+      if (maybe_range_for_decl && *maybe_range_for_decl == NULL_TREE)
+	*maybe_range_for_decl = decl;
       /* The next token should be either a `,' or a `;'.  */
       token = cp_lexer_peek_token (parser->lexer);
       /* If it's a `,', there are more declarators to come.  */
       if (token->type == CPP_COMMA)
 	/* will be consumed next time around */;
       /* If it's a `;', we are done.  */
-      else if (token->type == CPP_SEMICOLON)
+      else if (token->type == CPP_SEMICOLON || maybe_range_for_decl)
 	break;
       /* Anything else is an error.  */
       else
@@ -9767,7 +9787,8 @@  cp_parser_simple_declaration (cp_parser* parser,
     }
 
   /* Consume the `;'.  */
-  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+  if (!maybe_range_for_decl)
+      cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
  done:
   pop_deferring_access_checks ();
@@ -14380,7 +14401,13 @@  cp_parser_asm_definition (cp_parser* parser)
    have been completely parsed.
 
    FUNCTION_DEFINITION_P may be NULL if FUNCTION_DEFINITION_ALLOWED_P
-   is FALSE.  */
+   is FALSE.
+
+   If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the
+   parsed declaration if it is an uninitialized single declarator not followed
+   by a `;', or to error_mark_node otherwise. Either way, the trailing `;',
+   if present, will not be consumed.  If returned, this declarator will be
+   created with SD_INITIALIZED but will not call cp_finish_decl.  */
 
 static tree
 cp_parser_init_declarator (cp_parser* parser,
@@ -14389,7 +14416,8 @@  cp_parser_init_declarator (cp_parser* parser,
 			   bool function_definition_allowed_p,
 			   bool member_p,
 			   int declares_class_or_enum,
-			   bool* function_definition_p)
+			   bool* function_definition_p,
+			   tree* maybe_range_for_decl)
 {
   cp_token *token = NULL, *asm_spec_start_token = NULL,
            *attributes_start_token = NULL;
@@ -14410,6 +14438,7 @@  cp_parser_init_declarator (cp_parser* parser,
   int ctor_dtor_or_conv_p;
   bool friend_p;
   tree pushed_scope = NULL;
+  bool range_for_decl_p = false;
 
   /* Gather the attributes that were provided with the
      decl-specifiers.  */
@@ -14553,6 +14582,8 @@  cp_parser_init_declarator (cp_parser* parser,
     {
       is_initialized = SD_INITIALIZED;
       initialization_kind = token->type;
+      if (maybe_range_for_decl)
+	*maybe_range_for_decl = error_mark_node;
 
       if (token->type == CPP_EQ
 	  && function_declarator_p (declarator))
@@ -14571,8 +14602,13 @@  cp_parser_init_declarator (cp_parser* parser,
       if (token->type != CPP_COMMA
 	  && token->type != CPP_SEMICOLON)
 	{
-	  cp_parser_error (parser, "expected initializer");
-	  return error_mark_node;
+	  if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node)
+	    range_for_decl_p = true;
+	  else
+	    {
+	      cp_parser_error (parser, "expected initializer");
+	      return error_mark_node;
+	    }
 	}
       is_initialized = SD_UNINITIALIZED;
       initialization_kind = CPP_EOF;
@@ -14605,7 +14641,8 @@  cp_parser_init_declarator (cp_parser* parser,
       if (parser->in_unbraced_linkage_specification_p)
 	decl_specifiers->storage_class = sc_extern;
       decl = start_decl (declarator, decl_specifiers,
-			 is_initialized, attributes, prefix_attributes,
+			 range_for_decl_p? SD_INITIALIZED : is_initialized,
+			 attributes, prefix_attributes,
 			 &pushed_scope);
       /* Adjust location of decl if declarator->id_loc is more appropriate:
 	 set, and decl wasn't merged with another decl, in which case its
@@ -14719,7 +14756,7 @@  cp_parser_init_declarator (cp_parser* parser,
 
   /* Finish processing the declaration.  But, skip friend
      declarations.  */
-  if (!friend_p && decl && decl != error_mark_node)
+  if (!friend_p && decl && decl != error_mark_node && !range_for_decl_p)
     {
       cp_finish_decl (decl,
 		      initializer, !is_non_constant_init,
@@ -20073,7 +20110,8 @@  cp_parser_single_declaration (cp_parser* parser,
 				        /*function_definition_allowed_p=*/true,
 				        member_p,
 				        declares_class_or_enum,
-				        &function_definition_p);
+				        &function_definition_p,
+					NULL);
 
     /* 7.1.1-1 [dcl.stc]
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ae6aed0..498f8eb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12052,7 +12052,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
       }
 
     case FOR_STMT:
-      stmt = begin_for_stmt ();
+      stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
       RECUR (FOR_INIT_STMT (t));
       finish_for_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
@@ -12066,7 +12066,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case RANGE_FOR_STMT:
       {
         tree decl, expr;
-        stmt = begin_for_stmt ();
+        stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
         decl = RANGE_FOR_DECL (t);
         decl = tsubst (decl, args, complain, in_decl);
         maybe_push_decl (decl);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 25b9932..6be6cc7 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -827,21 +827,44 @@  finish_return_stmt (tree expr)
   return r;
 }
 
-/* Begin a for-statement.  Returns a new FOR_STMT if appropriate.  */
+/* Begin the scope of a for-statement or a range-for-statement.
+   Both the returned trees are to be used in a call to
+   begin_for_stmt or begin_range_for_stmt.  */
 
 tree
-begin_for_stmt (void)
+begin_for_scope (tree *init)
+{
+  tree scope = NULL_TREE;
+  if (flag_new_for_scope > 0)
+    scope = do_pushlevel (sk_for);
+
+  if (processing_template_decl)
+    *init = push_stmt_list ();
+  else
+    *init = NULL_TREE;
+
+  return scope;
+}
+
+/* Begin a for-statement.  Returns a new FOR_STMT.
+   SCOPE and INIT should be the return of begin_for_scope,
+   or both NULL_TREE  */
+
+tree
+begin_for_stmt (tree scope, tree init)
 {
   tree r;
 
   r = build_stmt (input_location, FOR_STMT, NULL_TREE, NULL_TREE,
 		  NULL_TREE, NULL_TREE);
 
-  if (flag_new_for_scope > 0)
-    TREE_CHAIN (r) = do_pushlevel (sk_for);
-
-  if (processing_template_decl)
-    FOR_INIT_STMT (r) = push_stmt_list ();
+  if (scope == NULL_TREE)
+    {
+      gcc_assert (!init);
+      scope = begin_for_scope (&init);
+    }
+  FOR_INIT_STMT (r) = init;
+  TREE_CHAIN (r) = scope;
 
   return r;
 }
@@ -925,18 +948,29 @@  finish_for_stmt (tree for_stmt)
 }
 
 /* Begin a range-for-statement.  Returns a new RANGE_FOR_STMT.
+   SCOPE and INIT should be the return of begin_for_scope,
+   or both NULL_TREE  .
    To finish it call finish_for_stmt(). */
 
 tree
-begin_range_for_stmt (void)
+begin_range_for_stmt (tree scope, tree init)
 {
   tree r;
 
   r = build_stmt (input_location, RANGE_FOR_STMT,
 		  NULL_TREE, NULL_TREE, NULL_TREE);
 
-  if (flag_new_for_scope > 0)
-    TREE_CHAIN (r) = do_pushlevel (sk_for);
+  if (scope == NULL_TREE)
+    {
+      gcc_assert (!init);
+      scope = begin_for_scope (&init);
+    }
+
+  /* RANGE_FOR_STMTs do not use nor save the init tree, so we
+     pop it now.  */
+  if (init)
+    pop_stmt_list (init);
+  TREE_CHAIN (r) = scope;
 
   return r;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for4.C b/gcc/testsuite/g++.dg/cpp0x/range-for4.C
index 96c0d90..afbcf14 100644
--- a/gcc/testsuite/g++.dg/cpp0x/range-for4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for4.C
@@ -3,8 +3,6 @@ 
 // { dg-do run }
 // { dg-options "-std=c++0x" }
 
-#include <cstdio>
-
 /* Preliminary declarations */
 namespace pre
 {
@@ -48,7 +46,6 @@  container run_me_just_once()
 }
 
 /* Template with dependent expression. */
-/* Template with dependent expression. */
 template<typename T> int test1(const T &r)
 {
   int t = 0;
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for8.C b/gcc/testsuite/g++.dg/cpp0x/range-for8.C
new file mode 100644
index 0000000..641dfe0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for8.C
@@ -0,0 +1,16 @@ 
+// Test for range-based for loop when the declarator declares
+// a new type
+
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+#include <initializer_list>
+
+void test()
+{
+    for (struct S { } *x : { (S*)0, (S*)0 } )
+        ;
+
+    for (struct S { } x : { S(), S() } )
+        ;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for9.C b/gcc/testsuite/g++.dg/cpp0x/range-for9.C
new file mode 100644
index 0000000..96e9cb6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for9.C
@@ -0,0 +1,11 @@ 
+// Test for range-based for loop error in C++98 mode
+
+// { dg-do compile }
+// { dg-options "-std=c++98" }
+
+void test()
+{
+    int a[] = {0,1,2};
+    for (int x : a)  // { dg-error "range-based-for" }
+        ;
+}