On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote: > On 3/21/19 4:51 PM, Marek Polacek wrote: > > This is a crash in digest_init_r -- we encounter > > > > /* "If T is a class type and the initializer list has a single > > element of type cv U, where U is T or a class derived from T, > > the object is initialized from that element." */ > > if (flag_checking > > && cxx_dialect >= cxx11 > > && BRACE_ENCLOSED_INITIALIZER_P (stripped_init) > > && CONSTRUCTOR_NELTS (stripped_init) == 1 > > && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type)) > > || VECTOR_TYPE_P (type))) > > { > > tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value; > > if (reference_related_p (type, TREE_TYPE (elt))) > > /* We should have fixed this in reshape_init. */ > > gcc_unreachable (); > > } > > > > As the comment suggests, we have code to fix this up in reshape_init_r: > > > > /* "If T is a class type and the initializer list has a single element of > > type cv U, where U is T or a class derived from T, the object is > > initialized from that element." Even if T is an aggregate. */ > > if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type)) > > && first_initializer_p > > && d->end - d->cur == 1 > > && reference_related_p (type, TREE_TYPE (init))) > > { > > d->cur++; > > return init; > > } > > > > but in this case this didn't work, because reshape_init_class always creates > > a fresh CONSTRUCTOR. > > But we hit that code before reshape_init_class, why didn't it work?
So originally, when calling reshape_init, we have {{ TARGET_EXPR<> }} of type D we recurse on it -- it's a class so we call reshape_init_class. Then we call reshape_init_r on a field D.2070 for the base (type B), the ctor is { TARGET_EXPR<> }. Here we elide the braces, so we return just the TARGET_EXPR as a field_init for D.2070, but then we're back in reshape_init_class and append the TARGET_EXPR to new_init constructor: 5969 CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, field_init); so we end up with the undesirable form. Hence my thinking we should handle this at the end of reshape_init_class. Let me know if this exaplanation isn't sufficient. > > As of C++17, aggregates can have bases > > Does it matter whether BB is a base or a member? Yes, I couldn't trigger an ICE if it's a member rather than a base. > > > + B b10 = {{B{42}}}; > > > + B b11 = {{B{{42}}}}; > > > + B b12 = {{B{{{42}}}}}; > > These look ill-formed to me: too many braces around the B value. > > Looks like the original testcase had the same problem. So I think this is > ice-on-invalid. Are you sure? clang/icc/gcc8/msvc compile it. I thought this was a case of aggregate initialization, where we have a nested braced-init-list: http://eel.is/c++draft/dcl.init.aggr#4.2 "If an initializer is itself an initializer list, the element is list-initialized, which will result in a recursive application of the rules in this subclause if the element is an aggregate." I also noticed that since r269045 we accept struct B { int c; }; struct D : B { }; D d = {{{42}}}; whereas before it was rejected with an error. I dropped these cases from my test as it's unrelated to this PR. Marek