On 11/1/19 4:42 PM, Marek Polacek wrote:
On Fri, Nov 01, 2019 at 04:37:15PM -0400, Jason Merrill wrote:
On 10/22/19 10:53 AM, Marek Polacek wrote:
This patch implements C++20 P0960R3: Parenthesized initialization of aggregates
(<wg21.link/p0960>; see R0 for more background info).  Essentially, if you have
an aggregate, you can now initialize it by (x, y), similarly to {x, y}.  E.g.

    struct A {
      int x, y;
      // no A(int, int) ctor (see paren-init14.C for = delete; case)
    };
    A a(1, 2);

The difference between ()-init and {}-init is that narrowing conversions are
permitted, designators are not permitted, a temporary object bound to
a reference does not have its lifetime extended, and there is no brace elision.
Further, things like

    int a[](1, 2, 3); // will deduce the array size
    const A& r(1, 2.3, 3); // narrowing is OK
    int (&&rr)[](1, 2, 3);
    int b[3](1, 2); // b[2] will be value-initialized

now work as expected.  Note that

    char f[]("fluff");

has always worked and this patch keeps it that way.  Also note that A a((1, 2))
is not the same as A a{{1,2}}; the inner (1, 2) remains a COMPOUND_EXPR.

The approach I took was to handle (1, 2) similarly to {1, 2} -- conjure up
a CONSTRUCTOR, and introduce LOOKUP_AGGREGATE_PAREN_INIT to distinguish
between the two.  This kind of initialization is only supported in C++20;
I've made no attempt to support it in earlier standards, like we don't
support CTAD pre-C++17, for instance.

Could we use a flag on the CONSTRUCTOR to distinguish between them instead,
rather than a LOOKUP flag and a flag in the conversion?

I think I tried and it didn't play well with digest_init and narrowing.
If we have { 2.0 } then when recursing on the CONSTRUCTOR element we
don't know it came from a paren-init, so a LOOKUP flag was necessary.

Ah, good point. Perhaps process_init_constructor could add that flag based on the CONSTRUCTOR flag rather than use rvaluedness_matches_p? That ought to avoid a few of the changes. And extend_ref_init_temps could check it rather than change store_init_value.

It also looks like you're using the LOOKUP flag to mean two different things:

1) try to treat parenthesized args as an aggregate initializer (build_new_method_call_1) 2) treat this CONSTRUCTOR as coming from parenthesized args (store_init_value/digest_init)

Why is the flag needed for #1? When do we not want to try to treat the args as an aggregate initializer?

Jason

Reply via email to