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