[cfe-dev] Stumped by codegen for std::initializer_list

Sebastian Redl sebastian.redl at getdesigned.at
Tue Feb 7 02:02:55 PST 2012


Doug, CCing you explicitly here. Are you going to Kona? If so, can you 
ask for fast, unambiguous resolution of initializer_list-bound array 
lifetime? This is DR1290, which, on the public list, is just a title. 
See below.

On 07.02.2012 03:24, John McCall wrote:
> On Feb 4, 2012, at 7:06 AM, Sebastian Redl wrote:
>> I'm kinda stuck at codegenning std::initializer_list and would appreciate if someone more experienced could give advice.
>>
>> Basically, if you initialize a std::initializer_list object from an initializer list, like so:
>>
>> std::initializer_list<int>  il = { 1, 2, 3 };
>>
>> we are supposed to create a hidden array int[3], initialize that with the init list, and then have the std::initlist point at the array. The lifetime of this hidden array (and its contained objects) is incorrectly specified at the moment, but is probably supposed to be the same as if it was a temporary that is bound to a reference, that reference being the initializer_list object.
> Does this apply recursively?  i.e. if you have a std::initializer_list<std::initializer_list<std::string>>, should both levels of array be implicitly extended?
I have no idea. It feels like this should work.
> Also, what happens in cases of copy elision of the intializer_list object?  e.g.
>    auto list = (std::initializer_list<std::string>) { "" };
I also have no idea. I think this still should destroy the init list at 
the end of the full-expression. On the other hand,
auto list = {1, 2, 3};
should not, and the code is semantically pretty much the same, I think.

Argh! The standard is so horribly underspecified here!
> I don't see any great solutions beyond special-casing the emission of local and global variables of std::initializer_list type, unless it's to create a special AST node or something (or a flag?) to mark the special kind of construction (which shouldn't be *too* difficult, since it's a special case of initialization already).  That won't really help with the copy-elision case, though.
>
OK, so I'll just have to do my best to factor out the code duplication. 
Thank you.

Doug: so we've got a few interesting examples for initializer_list 
lifetime issues:
auto list = {1, 2, 3}; // Conceptually, creates a temporary init_list 
and copies to the stack variable. Array would be gone at end of FE. 
Cannot be what is wanted.
auto list = std::initializer_list{1, 2, 3}; // Same as above, but 
explicit in the construction of the temporary.
new auto{1, 2, 3}; // Allocates the init_list on the heap. What about 
the array, which is supposed to have the same lifetime?
std::initializer_list<std::initializer_list<std::string>>{{"one"}, 
{"two"}}; // What's the lifetime of the arrays of the inner init_lists, 
and how on earth are we supposed to implement that? (Note to self: try 
in GCC.)
struct S { std::initializer_list<int> mList; S() : mList{1, 2, 3} {} }; 
// What about here?

Let's try to resolve as many of these as possible with the analogy to 
references.

struct D { D(int); ~D(); };
const D& r1 = {1}; // Binds to temporary, extends lifetime, very special 
rule though.
const D& r2 = (const D&){1}; // What does this do?
struct CR { const D& ref; };
struct CRR { const CR& ref; };
new CR{{1}}; // D temporary gets destroyed at end of FE.
CRR crr{{{1}}}; // What does this do? How many compilers get it right?
struct IR { const D& ref; IR() : ref{1} {} }; // D temporary destroyed 
at end of initializer.

Sebastian



More information about the cfe-dev mailing list