Message ID | 20240508174911.1278083-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: nested aggregate/alias CTAD fixes | expand |
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 > >
On 5/8/24 13:49, Patrick Palka wrote: > Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look > OK for trunk and perhaps 14? OK for both. > -- >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. > > 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>;
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>;