On Mon, 16 Aug 2021, Marek Polacek wrote: > On Mon, Aug 16, 2021 at 03:06:08PM -0400, Patrick Palka via Gcc-patches wrote: > > During aggregate CTAD, collect_ctor_idx_types always recurses into a > > sub-CONSTRUCTOR, regardless of whether the corresponding pair of braces > > was elided in the original initializer. This causes us to reject some > > completely-braced forms of aggregate CTAD as in the first testcase > > below, because collect_ctor_idx_types effectively assumes that the given > > initializer is always minimally-braced (hence the aggregate deduction > > candidate is given a function type that's incompatible with the written > > initializer). > > > > This patch fixes this by making reshape_init flag CONSTRUCTORs that > > were built to undo brace elision in the original CONSTRUCTOR, so that > > collect_ctor_idx_types can determine whether to recurse into a > > sub-CONSTRUCTOR by simply inspecting this flag. > > > > This happens to also fix PR101820, which is about aggregate CTAD using > > designated initializers, for a similar reason as above. > > > > A tricky case is the "intermediately-braced" initialization of 'e3' > > in the first testcase below. It seems to me we're correct to continue > > to reject this according to [over.match.class.deduct]/1 because here > > the initializer element {1, 2, 3, 4} corresponds to the subobject E::t, > > hence the type T_1 of the first funciton parameter of the aggregate > > deduction candidate is T(&&)[2][2] which the argument {1, 2, 3, 4} isn't > > compatible with (as opposed to say T(&&)[4]). > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > trunk/11? > > > > PR c++/101344 > > PR c++/101820 > > > > gcc/cp/ChangeLog: > > > > * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define. > > * decl.c (reshape_init_r): Set it. > > * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR > > iff CONSTRUCTOR_BRACES_ELIDED_P. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp2a/class-deduction-aggr11.C: New test. > > * g++.dg/cpp2a/class-deduction-aggr12.C: New test. > > --- > > gcc/cp/cp-tree.h | 6 ++++ > > gcc/cp/decl.c | 18 +++++++++--- > > gcc/cp/pt.c | 7 +---- > > .../g++.dg/cpp2a/class-deduction-aggr11.C | 29 +++++++++++++++++++ > > .../g++.dg/cpp2a/class-deduction-aggr12.C | 15 ++++++++++ > > 5 files changed, 65 insertions(+), 10 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C > > > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > > index bd3f12a393e..8cbf6cc30b0 100644 > > --- a/gcc/cp/cp-tree.h > > +++ b/gcc/cp/cp-tree.h > > @@ -4502,6 +4502,12 @@ more_aggr_init_expr_args_p (const > > aggr_init_expr_arg_iterator *iter) > > #define CONSTRUCTOR_IS_PAREN_INIT(NODE) \ > > (CONSTRUCTOR_CHECK(NODE)->base.private_flag) > > > > +/* True if reshape_init built this CONSTRUCTOR to undo the brace elision > > + of another CONSTRUCTOR. This flag is used during C++20 aggregate > > + CTAD. */ > > +#define CONSTRUCTOR_BRACES_ELIDED_P(NODE) \ > > + (CONSTRUCTOR_CHECK (NODE)->base.protected_flag) > > + > > /* True if NODE represents a conversion for direct-initialization in a > > template. Set by perform_implicit_conversion_flags. */ > > #define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \ > > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > > index b3671ee8956..9e257b32e18 100644 > > --- a/gcc/cp/decl.c > > +++ b/gcc/cp/decl.c > > @@ -6650,7 +6650,8 @@ reshape_init_r (tree type, reshape_iter *d, tree > > first_initializer_p, > > /* A non-aggregate type is always initialized with a single > > initializer. */ > > if (!CP_AGGREGATE_TYPE_P (type) > > - /* As is an array with dependent bound. */ > > + /* As is an array with dependent bound, which we can see > > + during C++20 aggregate CTAD. */ > > || (cxx_dialect >= cxx20 > > && TREE_CODE (type) == ARRAY_TYPE > > && uses_template_parms (TYPE_DOMAIN (type)))) > > @@ -6767,6 +6768,7 @@ reshape_init_r (tree type, reshape_iter *d, tree > > first_initializer_p, > > initializer already, and there is not a CONSTRUCTOR, it means that > > there > > is a missing set of braces (that is, we are processing the case for > > which reshape_init exists). */ > > + bool braces_elided_p = false; > > if (!first_initializer_p) > > { > > if (TREE_CODE (stripped_init) == CONSTRUCTOR) > > @@ -6802,17 +6804,25 @@ reshape_init_r (tree type, reshape_iter *d, tree > > first_initializer_p, > > warning (OPT_Wmissing_braces, > > "missing braces around initializer for %qT", > > type); > > + braces_elided_p = true; > > } > > > > /* Dispatch to specialized routines. */ > > + tree new_init; > > if (CLASS_TYPE_P (type)) > > - return reshape_init_class (type, d, first_initializer_p, complain); > > + new_init = reshape_init_class (type, d, first_initializer_p, complain); > > else if (TREE_CODE (type) == ARRAY_TYPE) > > - return reshape_init_array (type, d, first_initializer_p, complain); > > + new_init = reshape_init_array (type, d, first_initializer_p, complain); > > else if (VECTOR_TYPE_P (type)) > > - return reshape_init_vector (type, d, complain); > > + new_init = reshape_init_vector (type, d, complain); > > else > > gcc_unreachable(); > > + > > + if (braces_elided_p) > > + if (TREE_CODE (new_init) == CONSTRUCTOR) > > + CONSTRUCTOR_BRACES_ELIDED_P (new_init) = 1; > > Any reason for the two ifs and not an &&?
Whoops, that's a refactoring artifact from an earlier version of the patch. Fixed now. > > Marek > >