diff mbox

[C++0x] implement range-based for loops

Message ID AANLkTinmmKSfABfMSCHTBGpZ5mv=GPqLK+gtDfKqp68n@mail.gmail.com
State New
Headers show

Commit Message

Rodrigo Rivas Sept. 7, 2010, 12:39 p.m. UTC
> Let's adjust the code factoring a bit.  Please move the variables range_decl
> and range_expr, and the calls to cp_convert_range_for and
> finish_range_for_decl, into cp_parser_range_for; factor the code to parse
> C-style for-statements into another function cp_parser_c_for; share the code
> starting with "look for the )"; and make finish_for_stmt handle
> RANGE_FOR_STMT as well.
Ok. The code looks much nicer now.

>> +  if (flag_new_for_scope > 0)
>> +    TREE_CHAIN (r) = do_pushlevel (sk_for);
>
> We should push the scope for range-fors regardless of flag_new_for_scope,
> since they didn't exist before the change to for-statement scope.  It's
> probably (past) time to deprecate that option anyway.

Yes, I don't think anybody cares about this flag any more, although
now this patch would be a bit simpler if we keep it in, just for
symmetry. Anyway I did as you suggested (I really don't care about
this flag).

>> +  /* Create the __range variable */
>> +  range_temp = create_temporary_var (range_type);
>> +  begin = create_temporary_var (iter_type);
>> +  end = create_temporary_var (iter_type);
>
> Let's actually call these __range, __begin and __end (and not set
> DECL_IGNORED_P) so that people can examine them in the debugger.
I've changed it to:

  range_temp = build_decl (input_location, VAR_DECL,
                           get_identifier ("__range"), range_type);
  TREE_USED (range_temp) = 1;
  DECL_ARTIFICIAL (range_temp) = 1;
  pushdecl (range_temp);

And so on. Now I can see it in the debugger, but I can also use these
names in the code. This makes it, effectively, a GNU extension, even
with "-std=c++0x". I don't know... being able to debug it is nice, but
to allow the user to use a non-standard feature for not real gain may
be problematic. Is it possible to prevent the user from using the
names while allowing the debugger to see them?

> Line-wrapped arguments need to line up with the (.
Argh! Vim keeps moving them around!

Regards.
--
Rodrigo.

New changelog.
--
gcc/cp/

2010-09-07  Rodrigo Rivas <rodrigorivascosta@gmail.com>

	Implement range-based for-statements.
	* cp-tree.def (RANGE_FOR_STMT): New.
	* cp-tree.h (RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY): New.
	(cp_convert_range_for): Declare.
	* pt.c (tsubst_expr): Add RANGE_FOR_STMT.
	(tsubst_copy_and_build): perform_koenig_lookup takes extra argument.
	* semantics.c (begin_range_for_stmt): New.
	(finish_range_for_decl): New.
	(finish_for_stmt): Accept also RANGE_FOR_STMT.
	(perform_koenig_lookup): Add extra argument include_std.
	* parser.c (cp_parser_c_for): New with code from
	cp_parser_iteration_statement().
	(cp_parser_range_for): New.
	(cp_convert_range_for): New.
	(cp_parser_iteration_statement): Add range-for support.
	(cp_parser_condition): Adjust comment.
	(cp_parser_postfix_expression): perform_koenig_lookup takes extra
	argument.
	* dump.c (cp_dump_tree): Add RANGE_FOR_STMT.
	* cxx-pretty-print.c (): Likewise.
	* lex.c (cxx_init): Likewise.
	* name-lookup.c (lookup_function_nonclass): Add extra argument
	include_std.
	(lookup_arg_dependent): Likewise.
	* name-lookup.h (): Likewise.

gcc/testsuite/

2010-09-07  Rodrigo Rivas <rodrigorivascosta@gmail.com>

	* g++.dg/cpp0x/range-for1.C: New.
	* g++.dg/cpp0x/range-for2.C: New.
	* g++.dg/cpp0x/range-for3.C: New.
	* g++.dg/cpp0x/range-for4.C: New.
	* g++.dg/cpp0x/range-for5.C: New.
	* g++.dg/cpp0x/range-for6.C: New.

Comments

Jakub Jelinek Sept. 7, 2010, 12:51 p.m. UTC | #1
On Tue, Sep 07, 2010 at 02:39:46PM +0200, Rodrigo Rivas wrote:
>   range_temp = build_decl (input_location, VAR_DECL,
>                            get_identifier ("__range"), range_type);
>   TREE_USED (range_temp) = 1;
>   DECL_ARTIFICIAL (range_temp) = 1;
>   pushdecl (range_temp);
> 
> And so on. Now I can see it in the debugger, but I can also use these
> names in the code. This makes it, effectively, a GNU extension, even
> with "-std=c++0x". I don't know... being able to debug it is nice, but
> to allow the user to use a non-standard feature for not real gain may
> be problematic. Is it possible to prevent the user from using the
> names while allowing the debugger to see them?

The __ prefixed identifiers are reserved for implementation, so they
shouldn't be used in arbitrary C++ code.  On the other side, they can
be used in libstdc++ or libc headers, and they are
used quite heavily in both libstdc++ and libc headers (__range just
in libc headers, __start in both libstdc++ and libc headers, __end just
in libstdc++ headers).
So perhaps __for_range, __for_start, __for_end or something similar
would be better.

	Jakub
Rodrigo Rivas Sept. 7, 2010, 3:16 p.m. UTC | #2
> On the other side, they can
> be used in libstdc++ or libc headers, and they are
> used quite heavily in both libstdc++ and libc headers (__range just
> in libc headers, __start in both libstdc++ and libc headers, __end just
> in libstdc++ headers).
True, when/if range-fors are used in these places name clashes may occur.

> So perhaps __for_range, __for_start, __for_end or something similar
> would be better.
I would vote for something more verbose, to discourage direct use and
at the same time increase the "debuggability".
"__range_for_range", "__range_for_begin", "__range_for_end" or
something like that.
Also, adding a bit of randomness would be nice, so symbols in nested
range-for-loops can be examined.

PS: I've discovered how to make the symbol not usable by the user:
just drop a $ into the name!

Regards.
Rodrigo.
Jason Merrill Sept. 7, 2010, 6:51 p.m. UTC | #3
On 09/07/2010 08:51 AM, Jakub Jelinek wrote:
> The __ prefixed identifiers are reserved for implementation, so they
> shouldn't be used in arbitrary C++ code.  On the other side, they can
> be used in libstdc++ or libc headers, and they are
> used quite heavily in both libstdc++ and libc headers (__range just
> in libc headers, __start in both libstdc++ and libc headers, __end just
> in libstdc++ headers).

But those uses are only for explanatory parameter names in prototypes; 
they wouldn't conflict with this use.

One way to avoid the extension would be to wait and fill in DECL_NAME 
after parsing the body block, so that it's not available to name lookup 
in the source.

Jason
Rodrigo Rivas Sept. 9, 2010, 9:29 a.m. UTC | #4
> One way to avoid the extension would be to wait and fill in DECL_NAME after
> parsing the body block, so that it's not available to name lookup in the
> source.

But these variables are local to the "cp_convert_range_for()" function
so they are not easily available at the end of the block. And
upgrading the FOR_STMT is just overkilling.

I tried to change the name at different points of the code and it
causes ICEs. For example:

begin = build_decl (input_location, VAR_DECL, NULL_TREE, iter_type);
TREE_USED (begin) = 1;
DECL_ARTIFICIAL (begin) = 1;
push_decl (begin);
DECL_NAME (begin) = get_identifier ("__begin");


Anyway, I think it should be better to add a suffix to these, just
like anonymous enums. That will render the extension unusable, and at
the same time solves the debugging of nested loops. Something like
this:

static GTY(()) int range_for_cnt = 0;
static tree
make_range_for_name(const char *id)
{
  char buf[40];
  sprintf(buf, "__range_for_%s_%d", id, range_for_cnt);
/* the counter is incremented outside of the function so
  all identifiers of a loop get the same number */
  return get_identifier (buf);
}

/* ... */
range = build_decl (input_location, VAR_DECL,
make_range_for_name("expr"), range_type);
/* ... */
begin = build_decl (input_location, VAR_DECL,
make_range_for_name("begin"), iter_type);
/* ... */
end = build_decl (input_location, VAR_DECL,
make_range_for_name("end"), iter_type);
/* ... */
range_for_cnt++;

What do you think?


BTW, I didn't get any response from the copyright assignment, and it's
been a month since I sent it. I tried to reply to the e-mail but
without result. Do you know where should I ask? Maybe in the general
"gcc" mailing list?

Regards.
Rodrigo
Jason Merrill Sept. 10, 2010, 5:36 p.m. UTC | #5
On 09/09/2010 05:29 AM, Rodrigo Rivas wrote:
> BTW, I didn't get any response from the copyright assignment, and it's
> been a month since I sent it. I tried to reply to the e-mail but
> without result. Do you know where should I ask? Maybe in the general
> "gcc" mailing list?

Looks like it finally went through.  :)

> Anyway, I think it should be better to add a suffix to these, just
> like anonymous enums. That will render the extension unusable, and at
> the same time solves the debugging of nested loops.

Those suffixes are to avoid clashes in the assembler; it seems a bit 
excessive to use for names that have no linkage.  As long as the names 
aren't exactly the same as the ones in the standard, I think we're fine. 
  Let's go with __for_range, __for_begin, __for_end.

> +  bool scoped;
>
> +  if (TREE_CODE (for_stmt) == RANGE_FOR_STMT)
> +    {
> +      RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt));
> +      scoped = true;
> +    }
> +  else
> +    {
> +      FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
> +      scoped = flag_new_for_scope > 0;
> +    }
> +
>    /* Pop the scope for the body of the loop.  */
> -  if (flag_new_for_scope > 0)
> +  if (scoped)

I think this will do the wrong thing (push but no pop) with 
-fno-for-scope outside a template, since we don't create a 
RANGE_FOR_STMT in that case.

Jason
Rodrigo Rivas Sept. 11, 2010, 12:22 a.m. UTC | #6
> Those suffixes are to avoid clashes in the assembler; it seems a bit
> excessive to use for names that have no linkage.  As long as the names
> aren't exactly the same as the ones in the standard, I think we're fine.
>  Let's go with __for_range, __for_begin, __for_end.

Well, there will be clashes in the debugger inside of nested
range-based-for loops:

for (int x : {1,2,3})
   for (char c : "abd")
   {
       //breakpoint here!
   }
(gdb) info locals
c = 97 'a'
__for_range = @0x8048634
__for_begin = 0x8048634 "abd"
__for_end = 0x8048638 "%d %c\n"
x = 1
__for_range = @0xbffff0fc
__for_begin = 0xbffff104
__for_end = 0xbffff110

(gdb) print __for_range
$1 = (char (&)[4]) @0x8048634: "abd"

But there you are unable to print the other __for_range, etc.
With suffixes, however, it is cooler:

(gdb) info locals
c = 97 'a'
__for_range_1 = @0x8048634
__for_begin_1 = 0x8048634 "abd"
__for_end_1 = 0x8048638 "%d %c\n"
x = 1
__for_range_0 = @0xbffff0fc
__for_begin_0 = 0xbffff104
__for_end_0 = 0xbffff110

(gdb) print __for_range_1
$1 = (char (&)[4]) @0x8048634: "abd"
(gdb) print __for_range_0
$2 = (std::initializer_list<int> &) @0xbffff0fc: {
  _M_array = 0xbffff104,
  _M_len = 3
}

If you think that it doesn't worth it, well... actually I don't care
so much about debugger symbols anyway.

>> +  bool scoped;
>>
>> +  if (TREE_CODE (for_stmt) == RANGE_FOR_STMT)
>> +    {
>> +      RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY
>> (for_stmt));
>> +      scoped = true;
>> +    }
>> +  else
>> +    {
>> +      FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
>> +      scoped = flag_new_for_scope > 0;
>> +    }
>> +
>>   /* Pop the scope for the body of the loop.  */
>> -  if (flag_new_for_scope > 0)
>> +  if (scoped)
>
> I think this will do the wrong thing (push but no pop) with -fno-for-scope
> outside a template, since we don't create a RANGE_FOR_STMT in that case.

I've double checked it, and I think that the code is correct.

In case of a range-for outside a template we call begin_for_stmt()
instead of begin_range_for_stmt(). It pushes iff flag_new_for_scope >
0.
Then it calls cp_convert_range_for() that in turn does
finish_for_init_stmt(), that pushes the FOR_BODY.
When the loop finishes finish_for_stmt() (quoted) goes to the "else",
pops the FOR_BODY and iff flag_new_for_scope > 0 pops the for_scope.
So, with -fno-for-scope, one push and one pop. Without it, two pushes
and two pops.

If the template case, it calls the begin_range_for_stmt() that always
pushes the for_scope, then finish_range_for_decl() pushes the
RANGE_FOR_BODY, and the finish_for_stmt() pops twice.

The template instantiation case is parallel to the non template one:
begin_for_stmt()/cp_convert_range_for()/finish_for_stmt().

I feel that my English is a bit thick today, so sorry if I'm hard to
understand...

Frankly, I though that the code was simpler when
begin_range_for_stmt() obeyed the -fno-for-scope, it was like more
symmetric. But again, this option hardly matters any more. Also, if
you like, I can add a testcase with this option.

Regards.
Rodrigo.
Rodrigo Rivas Sept. 11, 2010, 12:45 p.m. UTC | #7
>> I think this will do the wrong thing (push but no pop) with -fno-for-scope
>> outside a template, since we don't create a RANGE_FOR_STMT in that case.
>
> I've double checked it, and I think that the code is correct.

Oh... not so correct, in fact. The pushes/pops are balanced, but the
problem is that with -fno-for-scope outside a template, a range-for
will *not* push (nor pop) because we create a FOR_STMT that obeys that
flag. If it is inside a template the RANGE_FOR_STMT creates the
for-scope, but the template instantiation does not. That's certainly
not a good thing.

The are just three solutions, I think:
One: record into the FOR_STMT tree whether it is created scoped or
not. A new bool parameter to the begin_for_stmt() is needed. Then in
the finish_for_stmt() we change the "if (flag_new_for_scope > 0)" for
"if (FOR_STMT_SCOPED_P (stmt))" or similar.
Two: make range-fors obey the -fno-for-scope. Then we just need to add
the "if (flag_new_for_scope > 0)" condition to begin_range_for_stmt()
and all works automatically.
Three: delete the -fno-for-scope alltogheter :-). Nice, but not a real option.

Given that nobody in their minds will use "-fno-for-scope -std=c++0x"
this decision is hardly relevant, so I vote for the simpler
implementation: option Two.

Best regards.
Rodigo.
Jason Merrill Sept. 11, 2010, 1:35 p.m. UTC | #8
On 09/11/2010 08:45 AM, Rodrigo Rivas wrote:
> Given that nobody in their minds will use "-fno-for-scope -std=c++0x"
> this decision is hardly relevant, so I vote for the simpler
> implementation: option Two.

OK, makes sense.

Jason
Jason Merrill Sept. 11, 2010, 1:45 p.m. UTC | #9
On 09/11/2010 09:35 AM, Jason Merrill wrote:
> On 09/11/2010 08:45 AM, Rodrigo Rivas wrote:
>> Given that nobody in their minds will use "-fno-for-scope -std=c++0x"
>> this decision is hardly relevant, so I vote for the simpler
>> implementation: option Two.
>
> OK, makes sense.

In case you hadn't noticed, I applied your earlier patch last night 
(with a few whitespace fixes and the variable name change), so this 
change should be relative to that.

Jason
diff mbox

Patch

Index: gcc/cp/cxx-pretty-print.c
===================================================================
--- gcc/cp/cxx-pretty-print.c	(revision 163923)
+++ gcc/cp/cxx-pretty-print.c	(working copy)
@@ -1921,6 +1921,23 @@  pp_cxx_statement (cxx_pretty_printer *pp, tree t)
       pp_needs_newline (pp) = true;
       break;
 
+    case RANGE_FOR_STMT:
+      pp_cxx_ws_string (pp, "for");
+      pp_space (pp);
+      pp_cxx_left_paren (pp);
+      pp_cxx_statement (pp, RANGE_FOR_DECL (t));
+      pp_space (pp);
+      pp_needs_newline (pp) = false;
+      pp_colon (pp);
+      pp_space (pp);
+      pp_cxx_statement (pp, RANGE_FOR_EXPR (t));
+      pp_cxx_right_paren (pp);
+      pp_newline_and_indent (pp, 3);
+      pp_cxx_statement (pp, FOR_BODY (t));
+      pp_indentation (pp) -= 3;
+      pp_needs_newline (pp) = true;
+      break;
+
       /* jump-statement:
 	    goto identifier;
 	    continue ;
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 163923)
+++ gcc/cp/pt.c	(working copy)
@@ -11742,7 +11742,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t com
 
     case FOR_STMT:
       stmt = begin_for_stmt ();
-			  RECUR (FOR_INIT_STMT (t));
+      RECUR (FOR_INIT_STMT (t));
       finish_for_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
       finish_for_cond (tmp, stmt);
@@ -11752,6 +11752,20 @@  tsubst_expr (tree t, tree args, tsubst_flags_t com
       finish_for_stmt (stmt);
       break;
 
+    case RANGE_FOR_STMT:
+      {
+        tree decl, expr;
+        stmt = begin_for_stmt ();
+        decl = RANGE_FOR_DECL (t);
+        decl = tsubst (decl, args, complain, in_decl);
+        maybe_push_decl (decl);
+        expr = RECUR (RANGE_FOR_EXPR (t));
+        stmt = cp_convert_range_for (stmt, decl, expr);
+        RECUR (RANGE_FOR_BODY (t));
+        finish_for_stmt (stmt);
+      }
+      break;
+
     case WHILE_STMT:
       stmt = begin_while_stmt ();
       tmp = RECUR (WHILE_COND (t));
@@ -12536,7 +12550,7 @@  tsubst_copy_and_build (tree t,
 	       into a non-dependent call.  */
 	    && type_dependent_expression_p_push (t)
 	    && !any_type_dependent_arguments_p (call_args))
-	  function = perform_koenig_lookup (function, call_args);
+	  function = perform_koenig_lookup (function, call_args, false);
 
 	if (TREE_CODE (function) == IDENTIFIER_NODE)
 	  {
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 163923)
+++ gcc/cp/semantics.c	(working copy)
@@ -876,15 +876,27 @@  finish_for_expr (tree expr, tree for_stmt)
 
 /* Finish the body of a for-statement, which may be given by
    FOR_STMT.  The increment-EXPR for the loop must be
-   provided.  */
+   provided.
+   It can also finish RANGE_FOR_STMT. */
 
 void
 finish_for_stmt (tree for_stmt)
 {
-  FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
+  bool scoped;
 
+  if (TREE_CODE (for_stmt) == RANGE_FOR_STMT)
+    {
+      RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt));
+      scoped = true;
+    }
+  else
+    {
+      FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
+      scoped = flag_new_for_scope > 0;
+    }
+
   /* Pop the scope for the body of the loop.  */
-  if (flag_new_for_scope > 0)
+  if (scoped)
     {
       tree scope = TREE_CHAIN (for_stmt);
       TREE_CHAIN (for_stmt) = NULL;
@@ -894,6 +906,34 @@  finish_for_stmt (tree for_stmt)
   finish_stmt ();
 }
 
+/* Begin a range-for-statement.  Returns a new RANGE_FOR_STMT. 
+   To finish it call finish_for_stmt(). */
+
+tree
+begin_range_for_stmt (void)
+{
+  tree r;
+  r = build_stmt (input_location, RANGE_FOR_STMT, 
+		  NULL_TREE, NULL_TREE, NULL_TREE);
+  /* We can ignore flag_new_for_scope here. */
+  TREE_CHAIN (r) = do_pushlevel (sk_for);
+
+  return r;
+}
+
+/* Finish the head of a range-based for statement, which may
+   be given by RANGE_FOR_STMT. DECL must be the declaration
+   and EXPR must be the loop expression. */
+
+void
+finish_range_for_decl (tree range_for_stmt, tree decl, tree expr)
+{
+  RANGE_FOR_DECL (range_for_stmt) = decl;
+  RANGE_FOR_EXPR (range_for_stmt) = expr;
+  add_stmt (range_for_stmt);
+  RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block);
+}
+
 /* Finish a break-statement.  */
 
 tree
@@ -1839,11 +1879,12 @@  empty_expr_stmt_p (tree expr_stmt)
 
 /* Perform Koenig lookup.  FN is the postfix-expression representing
    the function (or functions) to call; ARGS are the arguments to the
-   call.  Returns the functions to be considered by overload
-   resolution.  */
+   call; if INCLUDE_STD then the `std' namespace is automatically
+   considered an associated namespace (used in range-based for loops).
+   Returns the functions to be considered by overload resolution.  */
 
 tree
-perform_koenig_lookup (tree fn, VEC(tree,gc) *args)
+perform_koenig_lookup (tree fn, VEC(tree,gc) *args, bool include_std)
 {
   tree identifier = NULL_TREE;
   tree functions = NULL_TREE;
@@ -1879,7 +1920,7 @@  tree
   if (!any_type_dependent_arguments_p (args)
       && !any_dependent_template_arguments_p (tmpl_args))
     {
-      fn = lookup_arg_dependent (identifier, functions, args);
+      fn = lookup_arg_dependent (identifier, functions, args, include_std);
       if (!fn)
 	/* The unqualified name could not be resolved.  */
 	fn = unqualified_fn_lookup_error (identifier);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 163923)
+++ gcc/cp/parser.c	(working copy)
@@ -1829,6 +1829,10 @@  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
+  (cp_parser *);
 static tree cp_parser_jump_statement
   (cp_parser *);
 static void cp_parser_declaration_statement
@@ -5171,7 +5175,8 @@  cp_parser_postfix_expression (cp_parser *parser, b
 			koenig_p = true;
 			if (!any_type_dependent_arguments_p (args))
 			  postfix_expression
-			    = perform_koenig_lookup (postfix_expression, args);
+			    = perform_koenig_lookup (postfix_expression, args,
+						     /*include_std=*/false);
 		      }
 		    else
 		      postfix_expression
@@ -5195,7 +5200,8 @@  cp_parser_postfix_expression (cp_parser *parser, b
 			koenig_p = true;
 			if (!any_type_dependent_arguments_p (args))
 			  postfix_expression
-			    = perform_koenig_lookup (postfix_expression, args);
+			    = perform_koenig_lookup (postfix_expression, args,
+						     /*include_std=*/false);
 		      }
 		  }
 	      }
@@ -8580,6 +8586,258 @@  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. */
+static tree
+cp_parser_c_for (cp_parser *parser)
+{
+  /* Normal for loop */
+  tree stmt;
+  tree condition = NULL_TREE;
+  tree expression = NULL_TREE;
+
+  /* Begin the for-statement.  */
+  stmt = begin_for_stmt ();
+
+  /* Parse the initialization.  */
+  cp_parser_for_init_statement (parser);
+  finish_for_init_stmt (stmt);
+
+  /* If there's a condition, process it.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+    condition = cp_parser_condition (parser);
+  finish_for_cond (condition, stmt);
+  /* Look for the `;'.  */
+  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+  /* If there's an expression, process it.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+    expression = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+  finish_for_expr (expression, stmt);
+
+  return stmt;
+}
+
+/* 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().
+
+  Returns TRUE iff a range-based for is parsed. */
+
+static tree
+cp_parser_range_for (cp_parser *parser)
+{
+  tree stmt, range_decl, range_expr;
+  cp_decl_specifier_seq type_specifiers;
+  cp_declarator *declarator;
+  const char *saved_message;
+  tree attributes, pushed_scope;
+
+  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))
+    {
+      cp_parser_abort_tentative_parse (parser);
+      return NULL_TREE;
+    }
+  /* 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;
+      range_expr = cp_parser_braced_list (parser, &expr_non_constant_p);
+    }
+  else
+    range_expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+
+  /* If in template, STMT is converted to a normal for-statements
+     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);
+  else
+    /* Convert the range-based for loop into a normal for-statement. */
+    stmt = cp_convert_range_for (stmt, range_decl, range_expr);
+
+  return stmt;
+}
+
+/* Converts a range-based for-statement into a normal
+   for-statement, as per the definition. 
+
+      for (RANGE_DECL : RANGE_EXPR)
+	BLOCK
+
+   should be equivalent to:
+
+      {
+	auto &&__range = RANGE_EXPR;
+	for (auto __begin = BEGIN_EXPR, end = END_EXPR;
+	      __begin != __end;
+	      ++__begin)
+	  {
+	      RANGE_DECL = *__begin;
+	      BLOCK
+	  }
+      }
+
+   If RANGE_EXPR is an array:
+       BEGIN_EXPR = __range
+       END_EXPR = __range + ARRAY_SIZE(__range)
+   Else:
+	BEGIN_EXPR = begin(__range)
+	END_EXPR = end(__range);
+
+   When calling begin()/end() we must use argument dependent
+   lookup, but always considering 'std' as an associated namespace.
+*/
+
+tree
+cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
+{
+  tree range_type, range_temp;
+  tree begin, end;
+  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 ("__range"), range_type);
+  TREE_USED (range_temp) = 1;
+  DECL_ARTIFICIAL (range_temp) = 1;
+  pushdecl (range_temp);
+  finish_expr_stmt (cp_build_modify_expr (range_temp, INIT_EXPR, range_expr, 
+					  tf_warning_or_error));
+  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 */
+  begin = build_decl (input_location, VAR_DECL, 
+		      get_identifier ("__begin"), iter_type);
+  TREE_USED (begin) = 1;
+  DECL_ARTIFICIAL (begin) = 1;
+  pushdecl (begin);
+  finish_expr_stmt (cp_build_modify_expr (begin, INIT_EXPR, begin_expr, 
+					  tf_warning_or_error));
+  end = build_decl (input_location, VAR_DECL, 
+		    get_identifier ("__end"), iter_type);
+  TREE_USED (end) = 1;
+  DECL_ARTIFICIAL (end) = 1;
+  pushdecl (end);
+
+  finish_expr_stmt (cp_build_modify_expr (end, INIT_EXPR, end_expr, 
+					  tf_warning_or_error));
+
+  finish_for_init_stmt (statement);
+
+/* The new for condition */
+  condition = build_x_binary_op (NE_EXPR,
+				 begin, ERROR_MARK,
+				 end, ERROR_MARK,
+				 NULL, tf_warning_or_error);
+  finish_for_cond (condition, statement);
+
+  /* The new increment expression */
+  expression = finish_unary_op_expr (PREINCREMENT_EXPR, begin);
+  finish_for_expr (expression, statement);
+
+  /* The declaration is initialized with *__begin inside the loop body */
+  cp_finish_decl (range_decl,
+		  build_x_indirect_ref (begin, RO_NULL, tf_warning_or_error),
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
+
+  return statement;
+}
+
+
 /* Parse an iteration-statement.
 
    iteration-statement:
@@ -8588,7 +8846,7 @@  cp_parser_condition (cp_parser* parser)
      for ( for-init-statement condition [opt] ; expression [opt] )
        statement
 
-   Returns the new WHILE_STMT, DO_STMT, or FOR_STMT.  */
+   Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT.  */
 
 static tree
 cp_parser_iteration_statement (cp_parser* parser)
@@ -8661,28 +8919,16 @@  cp_parser_iteration_statement (cp_parser* parser)
 
     case RID_FOR:
       {
-	tree condition = NULL_TREE;
-	tree expression = NULL_TREE;
-
-	/* Begin the for-statement.  */
-	statement = begin_for_stmt ();
 	/* Look for the `('.  */
 	cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
-	/* Parse the initialization.  */
-	cp_parser_for_init_statement (parser);
-	finish_for_init_stmt (statement);
 
-	/* If there's a condition, process it.  */
-	if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
-	  condition = cp_parser_condition (parser);
-	finish_for_cond (condition, statement);
-	/* Look for the `;'.  */
-	cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+	if (cxx_dialect == cxx0x)
+	  statement = cp_parser_range_for (parser);
+	else
+	  statement = NULL_TREE;
+	if (statement == NULL_TREE)
+	  statement = cp_parser_c_for (parser);
 
-	/* If there's an expression, process it.  */
-	if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
-	  expression = cp_parser_expression (parser, /*cast_p=*/false, NULL);
-	finish_for_expr (expression, statement);
 	/* Look for the `)'.  */
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
Index: gcc/cp/cp-tree.def
===================================================================
--- gcc/cp/cp-tree.def	(revision 163923)
+++ gcc/cp/cp-tree.def	(working copy)
@@ -293,6 +293,10 @@  DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 3)
    FOR_INIT_STMT, FOR_COND, FOR_EXPR, and FOR_BODY, respectively.  */
 DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 4)
 
+/* Used to represent a range-based `for' statement. The operands are
+   RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, respectively. */
+DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 3)
+
 /* Used to represent a 'while' statement. The operands are WHILE_COND
    and WHILE_BODY, respectively.  */
 DEFTREECODE (WHILE_STMT, "while_stmt", tcc_statement, 2)
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 163923)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -3799,6 +3801,12 @@  more_aggr_init_expr_args_p (const aggr_init_expr_a
 #define FOR_EXPR(NODE)		TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
 #define FOR_BODY(NODE)		TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
 
+/* RANGE_FOR_STMT accessors. These give access to the declarator,
+   expression and body of the statement, respectively.  */
+#define RANGE_FOR_DECL(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 0)
+#define RANGE_FOR_EXPR(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 1)
+#define RANGE_FOR_BODY(NODE)	TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 2)
+
 #define SWITCH_STMT_COND(NODE)	TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
 #define SWITCH_STMT_BODY(NODE)	TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
 #define SWITCH_STMT_TYPE(NODE)	TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2)
@@ -4009,6 +4017,7 @@  extern int function_depth;
    sizeof can be nested.  */
 
 extern int cp_unevaluated_operand;
+extern tree cp_convert_range_for (tree, tree, tree);
 
 /* in pt.c  */
 
@@ -5189,6 +5198,9 @@  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 void finish_range_for_decl		(tree, tree, tree);
+extern void finish_range_for_stmt		(tree);
 extern tree finish_break_stmt			(void);
 extern tree finish_continue_stmt		(void);
 extern tree begin_switch_stmt			(void);
@@ -5229,7 +5241,7 @@  extern tree finish_stmt_expr_expr		(tree, tree);
 extern tree finish_stmt_expr			(tree, bool);
 extern tree stmt_expr_value_expr		(tree);
 bool empty_expr_stmt_p				(tree);
-extern tree perform_koenig_lookup		(tree, VEC(tree,gc) *);
+extern tree perform_koenig_lookup		(tree, VEC(tree,gc) *, bool);
 extern tree finish_call_expr			(tree, VEC(tree,gc) **, bool,
 						 bool, tsubst_flags_t);
 extern tree finish_increment_expr		(tree, enum tree_code);
Index: gcc/cp/dump.c
===================================================================
--- gcc/cp/dump.c	(revision 163923)
+++ gcc/cp/dump.c	(working copy)
@@ -453,6 +453,13 @@  cp_dump_tree (void* dump_info, tree t)
       dump_child ("body", FOR_BODY (t));
       break;
 
+    case RANGE_FOR_STMT:
+      dump_stmt (di, t);
+      dump_child ("decl", RANGE_FOR_DECL (t));
+      dump_child ("expr", RANGE_FOR_EXPR (t));
+      dump_child ("body", RANGE_FOR_BODY (t));
+      break;
+
     case SWITCH_STMT:
       dump_stmt (di, t);
       dump_child ("cond", SWITCH_STMT_COND (t));
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 163923)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -4389,7 +4389,7 @@  lookup_function_nonclass (tree name, VEC(tree,gc)
     lookup_arg_dependent (name,
 			  lookup_name_real (name, 0, 1, block_p, 0,
 					    LOOKUP_COMPLAIN),
-			  args);
+			  args, false);
 }
 
 tree
@@ -5063,7 +5063,8 @@  arg_assoc (struct arg_lookup *k, tree n)
    are the functions found in normal lookup.  */
 
 tree
-lookup_arg_dependent (tree name, tree fns, VEC(tree,gc) *args)
+lookup_arg_dependent (tree name, tree fns, VEC(tree,gc) *args,
+		      bool include_std)
 {
   struct arg_lookup k;
 
@@ -5086,6 +5087,8 @@  tree
      picking up later definitions) in the second stage. */
   k.namespaces = make_tree_vector ();
 
+  if (include_std)
+      arg_assoc_namespace (&k, std_node);
   arg_assoc_args_vec (&k, args);
 
   fns = k.functions;
Index: gcc/cp/lex.c
===================================================================
--- gcc/cp/lex.c	(revision 163923)
+++ gcc/cp/lex.c	(working copy)
@@ -226,8 +226,9 @@  cxx_init (void)
    CTOR_INITIALIZER,	TRY_BLOCK,	HANDLER,
    EH_SPEC_BLOCK,	USING_STMT,	TAG_DEFN,
    IF_STMT,		CLEANUP_STMT,	FOR_STMT,
-   WHILE_STMT,		DO_STMT,	BREAK_STMT,
-   CONTINUE_STMT,	SWITCH_STMT,	EXPR_STMT
+   RANGE_FOR_STMT,	WHILE_STMT,	DO_STMT,
+   BREAK_STMT,		CONTINUE_STMT,	SWITCH_STMT,
+   EXPR_STMT
   };
 
   memset (&statement_code_p, 0, sizeof (statement_code_p));
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h	(revision 163923)
+++ gcc/cp/name-lookup.h	(working copy)
@@ -342,7 +342,7 @@  extern void do_toplevel_using_decl (tree, tree, tr
 extern void do_local_using_decl (tree, tree, tree);
 extern tree do_class_using_decl (tree, tree);
 extern void do_using_directive (tree);
-extern tree lookup_arg_dependent (tree, tree, VEC(tree,gc) *);
+extern tree lookup_arg_dependent (tree, tree, VEC(tree,gc) *, bool);
 extern bool is_associated_namespace (tree, tree);
 extern void parse_using_directive (tree, tree);
 extern tree innermost_non_namespace_value (tree);
Index: gcc/testsuite/g++.dg/cpp0x/range-for1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for1.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for1.C	(revision 0)
@@ -0,0 +1,17 @@ 
+// Test for range-based for loop
+// Test the loop with an array
+
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+extern "C" void abort();
+
+int main()
+{
+    int a[] = {1,2,3,4};
+    int sum = 0;
+    for (int x : a)
+        sum += x;
+    if (sum != 10)
+        abort();
+}
Index: gcc/testsuite/g++.dg/cpp0x/range-for2.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for2.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for2.C	(revision 0)
@@ -0,0 +1,41 @@ 
+// Test for range-based for loop
+// Test the loop with a custom iterator
+// with begin/end in an associated namespace
+
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+struct iterator
+{
+    int x;
+    iterator(int v) :x(v) {}
+    iterator &operator ++() { ++x; return *this; }
+    int operator *() { return x; }
+    bool operator != (const iterator &o) { return x != o.x; }
+};
+
+namespace foo
+{
+    struct container
+    {
+        int min, max;
+        container(int a, int b) :min(a), max(b) {}
+    };
+
+    iterator begin(container &c)
+    {
+        return iterator(c.min);
+    }
+
+    iterator end(container &c)
+    {
+        return iterator(c.max + 1);
+    }
+}
+
+int main()
+{
+    foo::container c(1,4);
+    for (iterator it : c)
+        ;
+}
Index: gcc/testsuite/g++.dg/cpp0x/range-for3.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for3.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for3.C	(revision 0)
@@ -0,0 +1,42 @@ 
+// Test for range-based for loop
+// Test the loop with a custom iterator
+// with begin/end in std
+
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+struct iterator
+{
+    int x;
+    iterator(int v) :x(v) {}
+    iterator &operator ++() { ++x; return *this; }
+    int operator *() { return x; }
+    bool operator != (const iterator &o) { return x != o.x; }
+};
+
+struct container
+{
+    int min, max;
+    container(int a, int b) :min(a), max(b) {}
+};
+
+namespace std
+{
+    iterator begin(container &c)
+    {
+        return iterator(c.min);
+    }
+
+    iterator end(container &c)
+    {
+        return iterator(c.max + 1);
+    }
+}
+
+int main()
+{
+    container c(1,4);
+    for (iterator it : c)
+    {
+    }
+}
Index: gcc/testsuite/g++.dg/cpp0x/range-for4.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for4.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for4.C	(revision 0)
@@ -0,0 +1,119 @@ 
+// Test for range-based for loop with templates
+
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <cstdio>
+
+/* Preliminary declarations */
+namespace pre
+{
+  struct iterator
+  {
+    int x;
+    iterator (int v) :x(v) {}
+    iterator &operator ++() { ++x; return *this; }
+    int operator *() { return x; }
+    bool operator != (const iterator &o) { return x != o.x; }
+  };
+
+  struct container
+  {
+    int min, max;
+    container(int a, int b) :min(a), max(b) {}
+  };
+
+  iterator begin(const container &c)
+  {
+    return iterator(c.min);
+  }
+
+  iterator end(const container &c)
+  {
+    return iterator(c.max);
+  }
+
+} //namespace pre
+
+using pre::container;
+extern "C" void abort(void);
+
+container run_me_just_once()
+{
+    static bool run = false;
+    if (run)
+        abort();
+    run = true;
+    return container(1,2);
+}
+
+/* Template with dependent expression. */
+/* Template with dependent expression. */
+template<typename T> int test1(const T &r)
+{
+  int t = 0;
+  for (int i : r)
+    t += i;
+  return t;
+}
+
+/* Template with non-dependent expression and dependent declaration. */
+template<typename T> int test2(const container &r)
+{
+  int t = 0;
+  for (T i : r)
+    t += i;
+  return t;
+}
+
+/* Template with non-dependent expression (array) and dependent declaration. */
+template<typename T> int test2(const int (&r)[4])
+{
+  int t = 0;
+  for (T i : r)
+    t += i;
+  return t;
+}
+
+/* Template with non-dependent expression and auto declaration. */
+template<typename T> int test3(const container &r)
+{
+  int t = 0;
+  for (auto i : r)
+    t += i;
+  return t;
+}
+
+/* Template with non-dependent expression (array) and auto declaration. */
+template<typename T> int test3(const int (&r)[4])
+{
+  int t = 0;
+  for (auto i : r)
+    t += i;
+  return t;
+}
+
+int main ()
+{
+  container c(1,5);
+  int a[4] = {5,6,7,8};
+
+  for (auto x : run_me_just_once())
+      ;
+
+  if (test1 (c) != 10)
+    abort();
+  if (test1 (a) != 26)
+    abort();
+
+  if (test2<int> (c) != 10)
+    abort();
+  if (test2<int> (a) != 26)
+    abort();
+
+  if (test3<int> (c) != 10)
+    abort();
+  if (test3<int> (a) != 26)
+    abort();
+  return 0;
+}
Index: gcc/testsuite/g++.dg/cpp0x/range-for5.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for5.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for5.C	(revision 0)
@@ -0,0 +1,54 @@ 
+// Test for errors in range-based for loops
+
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+struct container
+{
+};
+
+int *begin(const container &c)
+{
+  return 0;
+}
+
+int end(const container &c) //Ops! wrong type
+{
+  return 0;
+}
+
+
+struct Implicit
+{
+  Implicit(int x)
+  {}
+};
+struct Explicit
+{
+  explicit Explicit(int x)
+  {}
+};
+
+void test1()
+{
+  container c;
+  for (int x : c) // { dg-error "inconsistent|conversion" }
+    ;
+
+  int a[2] = {1,2};
+  for (Implicit x : a)
+    ;
+  for (Explicit x : a) // { dg-error "conversion" }
+    ;
+  for (const Implicit &x : a)
+    ;
+  for (Implicit &&x : a)
+    ;
+
+  //Check the correct scopes
+  int i;
+  for (int i : a)
+  {
+    int i;
+  }
+}
Index: gcc/testsuite/g++.dg/cpp0x/range-for6.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for6.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for6.C	(revision 0)
@@ -0,0 +1,29 @@ 
+// Test for range-based for loop
+// Test the loop with an initializer_list
+
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <initializer_list>
+
+extern "C" void abort();
+
+template<typename T> T foo()
+{
+    T sum = 0;
+    for (T x : {T(1),T(2),T(3),T(4)})
+        sum += x;
+    if (sum != T(10))
+        abort();
+}
+
+int main()
+{
+    int sum = 0;
+    for (int x : {1,2,3,4})
+        sum += x;
+    if (sum != 10)
+        abort();
+
+    foo<int>();
+}