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

Reply via email to