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

Rodrigo Rivas rodrigorivascosta@gmail.com
Sat Sep 11 02:13:00 GMT 2010


> 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.



More information about the Gcc-patches mailing list