On Wed, 8 May 2024, Patrick Palka wrote:
> Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look
> OK for trunk and perhaps 14?
>
> -- >8 --
>
> During maybe_aggr_guide with a nested class template and paren init,
> like with list init we need to consider the generic template type rather
> than the partially instantiated type since only the former has
> TYPE_FIELDS. And in turn we need to partially substitute PARMs in the
> paren init case as well. As a drive-by improvement it seems better to
> use outer_template_args instead of DECL_TI_ARGS during this partial
> substitution so that we lower instead of substitute the innermost
> generic template arguments, which is generally more robust.
... lower instead of substitute the innermost _template parameters_, rather
>
> And during alias_ctad_tweaks with a nested class template, even though
> the guides may be already partially instantiated we still need to
> use the full set of arguments, not just the innermost, when substituting
> its constraints.
>
> PR c++/114974
> PR c++/114901
> PR c++/114903
>
> gcc/cp/ChangeLog:
>
> * pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
> the paren init case. Hoist out partial substitution logic
> to apply to the paren init case as well.
> (alias_ctad_tweaks): Substitute constraints using the full
> set of template arguments.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/class-deduction-aggr14.C: New test.
> * g++.dg/cpp2a/class-deduction-alias20.C: New test.
> * g++.dg/cpp2a/class-deduction-alias21.C: New test.
> ---
> gcc/cp/pt.cc | 39 +++++++++++--------
> .../g++.dg/cpp2a/class-deduction-aggr14.C | 11 ++++++
> .../g++.dg/cpp2a/class-deduction-alias20.C | 22 +++++++++++
> .../g++.dg/cpp2a/class-deduction-alias21.C | 38 ++++++++++++++++++
> 4 files changed, 93 insertions(+), 17 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1816bfd1f40..f3d52acaaac 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -30192,26 +30192,11 @@ maybe_aggr_guide (tree tmpl, tree init,
> vec<tree,va_gc> *args)
> if (init == error_mark_node)
> return NULL_TREE;
> parms = collect_ctor_idx_types (init, parms);
> - /* If we're creating a deduction guide for a member class template,
> - we've used the original template pattern type for the reshape_init
> - above; this is done because we want PARMS to be a template parameter
> - type, something that can be deduced when used as a function template
> - parameter. At this point the outer class template has already been
> - partially instantiated (we deferred the deduction until the enclosing
> - scope is non-dependent). Therefore we have to partially instantiate
> - PARMS, so that its template level is properly reduced and we don't get
> - mismatches when deducing types using the guide with PARMS. */
> - if (member_template_p)
> - {
> - ++processing_template_decl;
> - parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
> - --processing_template_decl;
> - }
> }
> else if (TREE_CODE (init) == TREE_LIST)
> {
> int len = list_length (init);
> - for (tree field = TYPE_FIELDS (type);
> + for (tree field = TYPE_FIELDS (template_type);
> len;
> --len, field = DECL_CHAIN (field))
> {
> @@ -30226,6 +30211,22 @@ maybe_aggr_guide (tree tmpl, tree init,
> vec<tree,va_gc> *args)
> /* Aggregate initialization doesn't apply to an initializer expression.
> */
> return NULL_TREE;
>
> + /* If we're creating a deduction guide for a member class template,
> + we've used the original template pattern type for the reshape_init
> + above; this is done because we want PARMS to be a template parameter
> + type, something that can be deduced when used as a function template
> + parameter. At this point the outer class template has already been
> + partially instantiated (we deferred the deduction until the enclosing
> + scope is non-dependent). Therefore we have to partially instantiate
> + PARMS, so that its template level is properly reduced and we don't get
> + mismatches when deducing types using the guide with PARMS. */
> + if (member_template_p)
> + {
> + ++processing_template_decl;
> + parms = tsubst (parms, outer_template_args (tmpl), complain, init);
> + --processing_template_decl;
> + }
> +
> if (parms)
> {
> tree last = parms;
> @@ -30417,7 +30418,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
> /* Substitute the associated constraints. */
> tree ci = get_constraints (f);
> if (ci)
> - ci = tsubst_constraint_info (ci, targs, complain, in_decl);
> + {
> + if (tree outer_targs = outer_template_args (f))
> + ci = tsubst_constraint_info (ci, outer_targs, complain,
> in_decl);
> + ci = tsubst_constraint_info (ci, targs, complain, in_decl);
> + }
> if (ci == error_mark_node)
> continue;
>
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
> b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
> new file mode 100644
> index 00000000000..68786652502
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr14.C
> @@ -0,0 +1,11 @@
> +// PR c++/114974
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T1>
> +struct A {
> + template<typename T2>
> + struct B { T2 t; };
> +};
> +
> +A<int>::B x{2}; // OK
> +A<int>::B y(2); // previously rejected
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
> b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
> new file mode 100644
> index 00000000000..8cc56d91e37
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias20.C
> @@ -0,0 +1,22 @@
> +// PR c++/114901
> +// { dg-do compile { target c++20 } }
> +
> +template <class D>
> +constexpr bool C = sizeof(D);
> +
> +template <typename U>
> +struct T {
> + template<typename V, typename N>
> + struct Foo {
> + Foo(V, N);
> + };
> +
> + template<typename X, typename N>
> + requires (C<N>) // removes the require-clause will make the crash disappear
> + Foo(X, N) -> Foo<X, N>;
> +
> + template <typename Y, typename Y2, int N = sizeof(Y2)>
> + using AFoo = Foo<decltype(N), Y2>;
> +};
> +
> +T<double>::AFoo s{1, 2}; // { dg-error "deduction|no match" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C
> b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C
> new file mode 100644
> index 00000000000..c39a0f9f141
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias21.C
> @@ -0,0 +1,38 @@
> +// PR c++/114903
> +// { dg-do compile { target c++20 } }
> +
> +template <typename T>
> +struct Key {
> + Key(int);
> +};
> +
> +class Forward {};
> +
> +template <typename T>
> +constexpr bool C = __is_same(T, Forward);
> +
> +template <typename Z>
> +struct Outer {
> + template <typename U>
> + struct Foo {
> + Foo(U);
> + U u;
> + };
> +
> + template <typename V>
> + requires(C<Z>)
> + Foo(V) -> Foo<int>;
> +};
> +
> +template <typename Y>
> +struct T {
> + template <typename Y2>
> + struct T2 {
> + template <typename K>
> + using AFoo = Outer<Y2>::template Foo<K>;
> + };
> +};
> +
> +T<Forward>::T2<Forward>::AFoo a(1.0);
> +using type = decltype(a);
> +using type = Outer<Forward>::Foo<int>;
> --
> 2.45.0.31.gd4cc1ec35f
>
>