* [PATCH] c++: aggregate CTAD and brace elision [PR101344]
@ 2021-08-16 19:06 Patrick Palka
2021-08-16 19:18 ` Marek Polacek
2021-08-16 20:05 ` Jason Merrill
0 siblings, 2 replies; 4+ messages in thread
From: Patrick Palka @ 2021-08-16 19:06 UTC (permalink / raw)
To: gcc-patches
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;
+
+ return new_init;
}
/* Undo the brace-elision allowed by [dcl.init.aggr] in a
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5ac89901e22..65b06d978b6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28836,12 +28836,7 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE)
{
tree ftype = elt ? elt : TREE_TYPE (idx);
if (BRACE_ENCLOSED_INITIALIZER_P (val)
- && CONSTRUCTOR_NELTS (val)
- /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound
- type gets a single initializer. */
- && CP_AGGREGATE_TYPE_P (ftype)
- && !(TREE_CODE (ftype) == ARRAY_TYPE
- && uses_template_parms (TYPE_DOMAIN (ftype))))
+ && CONSTRUCTOR_BRACES_ELIDED_P (val))
{
tree subelt = NULL_TREE;
if (TREE_CODE (ftype) == ARRAY_TYPE)
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C
new file mode 100644
index 00000000000..c4806de56af
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C
@@ -0,0 +1,29 @@
+// PR c++/101344
+// { dg-do compile { target c++20 } }
+
+template<class T=void>
+struct A { int m; int t[2]; };
+
+A a1{1, {2, 3}}; // previously rejected
+A a2{1, 2, 3};
+
+struct B { int x, y; };
+
+template<class T=void>
+struct C { int m; struct { int x, y; } t; };
+
+A b1{1, {2, 3}}; // previously rejected
+A b2{1, 2, 3};
+
+template<class T>
+struct D { T t[2]; };
+
+D d1{1, 2};
+D d2{{1, 2}}; // previously rejected
+
+template<class T>
+struct E { T t[2][2]; };
+
+E e1{1, 2, 3, 4};
+E e2{{{1, 2}, {3, 4}}}; // previously rejected
+E e3{{1, 2, 3, 4}}; // { dg-error "deduction|no match" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C
new file mode 100644
index 00000000000..ebe73c1d817
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C
@@ -0,0 +1,15 @@
+// PR c++/101820
+// { dg-do compile { target c++20 } }
+
+struct Inner { int i = 0; };
+
+template <typename T = void>
+struct Outer { Inner s{}; };
+
+Outer o1{ .s = {} }; // works
+Outer o2{ .s = Inner{ .i = 1} }; // works
+Outer o3{ .s = { .i = 1} }; // does not
+
+Outer o4{ .s{} }; // works
+Outer o5{ .s{Inner{ .i = 1} } }; // works
+Outer o6{ .s{ .i = 1} }; // does not
--
2.33.0.rc1
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] c++: aggregate CTAD and brace elision [PR101344]
2021-08-16 19:06 [PATCH] c++: aggregate CTAD and brace elision [PR101344] Patrick Palka
@ 2021-08-16 19:18 ` Marek Polacek
2021-08-16 19:26 ` Patrick Palka
2021-08-16 20:05 ` Jason Merrill
1 sibling, 1 reply; 4+ messages in thread
From: Marek Polacek @ 2021-08-16 19:18 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
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 &&?
Marek
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] c++: aggregate CTAD and brace elision [PR101344]
2021-08-16 19:18 ` Marek Polacek
@ 2021-08-16 19:26 ` Patrick Palka
0 siblings, 0 replies; 4+ messages in thread
From: Patrick Palka @ 2021-08-16 19:26 UTC (permalink / raw)
To: Marek Polacek; +Cc: Patrick Palka, gcc-patches
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
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] c++: aggregate CTAD and brace elision [PR101344]
2021-08-16 19:06 [PATCH] c++: aggregate CTAD and brace elision [PR101344] Patrick Palka
2021-08-16 19:18 ` Marek Polacek
@ 2021-08-16 20:05 ` Jason Merrill
1 sibling, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2021-08-16 20:05 UTC (permalink / raw)
To: Patrick Palka, gcc-patches
On 8/16/21 3:06 PM, Patrick Palka 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?
OK.
> 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;
> +
> + return new_init;
> }
>
> /* Undo the brace-elision allowed by [dcl.init.aggr] in a
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 5ac89901e22..65b06d978b6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -28836,12 +28836,7 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE)
> {
> tree ftype = elt ? elt : TREE_TYPE (idx);
> if (BRACE_ENCLOSED_INITIALIZER_P (val)
> - && CONSTRUCTOR_NELTS (val)
> - /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound
> - type gets a single initializer. */
> - && CP_AGGREGATE_TYPE_P (ftype)
> - && !(TREE_CODE (ftype) == ARRAY_TYPE
> - && uses_template_parms (TYPE_DOMAIN (ftype))))
> + && CONSTRUCTOR_BRACES_ELIDED_P (val))
> {
> tree subelt = NULL_TREE;
> if (TREE_CODE (ftype) == ARRAY_TYPE)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C
> new file mode 100644
> index 00000000000..c4806de56af
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C
> @@ -0,0 +1,29 @@
> +// PR c++/101344
> +// { dg-do compile { target c++20 } }
> +
> +template<class T=void>
> +struct A { int m; int t[2]; };
> +
> +A a1{1, {2, 3}}; // previously rejected
> +A a2{1, 2, 3};
> +
> +struct B { int x, y; };
> +
> +template<class T=void>
> +struct C { int m; struct { int x, y; } t; };
> +
> +A b1{1, {2, 3}}; // previously rejected
> +A b2{1, 2, 3};
> +
> +template<class T>
> +struct D { T t[2]; };
> +
> +D d1{1, 2};
> +D d2{{1, 2}}; // previously rejected
> +
> +template<class T>
> +struct E { T t[2][2]; };
> +
> +E e1{1, 2, 3, 4};
> +E e2{{{1, 2}, {3, 4}}}; // previously rejected
> +E e3{{1, 2, 3, 4}}; // { dg-error "deduction|no match" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C
> new file mode 100644
> index 00000000000..ebe73c1d817
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C
> @@ -0,0 +1,15 @@
> +// PR c++/101820
> +// { dg-do compile { target c++20 } }
> +
> +struct Inner { int i = 0; };
> +
> +template <typename T = void>
> +struct Outer { Inner s{}; };
> +
> +Outer o1{ .s = {} }; // works
> +Outer o2{ .s = Inner{ .i = 1} }; // works
> +Outer o3{ .s = { .i = 1} }; // does not
> +
> +Outer o4{ .s{} }; // works
> +Outer o5{ .s{Inner{ .i = 1} } }; // works
> +Outer o6{ .s{ .i = 1} }; // does not
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-08-16 20:05 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-16 19:06 [PATCH] c++: aggregate CTAD and brace elision [PR101344] Patrick Palka
2021-08-16 19:18 ` Marek Polacek
2021-08-16 19:26 ` Patrick Palka
2021-08-16 20:05 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).