On 3/22/19 2:14 PM, Marek Polacek wrote:
On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote:
+ 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."
Yes. Since the first element of the outer init-list is also an
init-list, we initialize the first element of D from the inner
init-list. The first element of D is the B base, so we're initializing
a B from {D{42}}.
Ah, and D is derived from B, so the B base is copy-initialized from the
(B base subobject of) the D temporary. So that's why it's different for
a base class.
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.
I don't think it's undesirable; the temporary initializes the base, not
the complete object. It seems that the assert in digest_init_r is wrong
for C++17.
It seems a bit questionable that adding a layer of braces silently
causes slicing; I'll raise this with the committee.