On Fri, Mar 01, 2019 at 04:14:33PM -0500, Jason Merrill wrote: > > Note, this is just a partial fix for the PR, for the second part (making > > struct S { void *a; int b; }; > > void foo (S); > > ... foo ({.b = 1}) work), I'm afraid I don't really understand what the C++ > > standard wants to say in http://eel.is/c++draft/over.ics.list#2 and what > > build_aggr_conv should do, such that the cpp2a/desig{4,6}.C testcases taken > > from the standard as well as the desig11.C in the earlier version of the > > patch (would need to be renamed to desig12.C) can pass. > > It seems to me that for designated initializers, we should make sure that > all the designators match fields, and otherwise check convertibility like > build_aggr_conv already does.
For the simple standard conforming case when if any initializer clause has designator, then all of them have to I can imagine e.g. one loop where we e.g. if (CONSTRUCTOR_IS_DESIGNATED_INIT (ctor)) { tree idx, val; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), i, idx, val) { if (idx && TREE_CODE (idx) == FIELD_DECL) { tree ftype = TREE_TYPE (idx); if (TREE_CODE (ftype) == ARRAY_TYPE && TREE_CODE (val) == CONSTRUCTOR) ok = can_convert_array (ftype, val, flags, complain); else ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags, complain); if (!ok) return NULL; // Put idx into some hash_set } } } and then in the current for (; field; field = next_initializable_field (DECL_CHAIN (field))) loop for the if (CONSTRUCTOR_IS_DESIGNATED_INIT (ctor)) case assume all has been done if field is in the hash_set (with the slightly more complicated case of ANON_AGGR_TYPE_P (ftype) where we likely need to search recursively for any initialized field) and just go the missing initializer way otherwise. But it isn't clear to me what to do in the case where the initializer has some designators and doesn't have others, because then the order is significant, the initializers without designator are supposed to follow those that do have them. struct S { int a, b, c, d, e; }; void foo (S); void bar () { foo ({.d = 5, 6, .b = 2, 3}); } or struct T { int a, b; }; void baz (T); void qux () { baz ({.b = 1, .a = 2}); } clang++ currently accepts both, but I believe it doesn't claim to supported the C++2a designated initializer, just an extension which likely allowed reordering like C99 and maybe that is why the C++2a standard says the ordering doesn't matter? I'm not really sure what to do for foo. Perhaps if we find that case just require that the order is ok already during build_aggr_conv and fail the conversion otherwise? We are outside of the standard in that case anyway. For baz we currently error with: error: designator order for field âT::aâ does not match declaration order in âTâ and I guess we should continue to do so, but only after build_aggr_conv succeeds, right? Jakub