Message ID | 20210109222305.3670720-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Fix ICE with CTAD in concept [PR98611] | expand |
On 1/9/21 5:23 PM, Patrick Palka wrote: > This patch teaches find_template_parameters to visit the template > represented by a CTAD placeholder, which is normally not visited by > for_each_template_parm. This template may be a template template > parameter (as in the first testcase), or it may implicitly use the > template parameters of an enclosing class template (as in the second > testcase), and in either case we need to record the template parameters > used therein for later satisfaction. > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk and perhaps the 10 branch? Also tested on range-v3 and cmcstl2. > > gcc/cp/ChangeLog: > > PR c++/98611 > * pt.c (any_template_parm_r) <case TEMPLATE_TYPE_PARM>: Visit > the template of a CTAD placeholder. Did you consider doing this in cp_walk_subtrees instead of here? > gcc/testsuite/ChangeLog: > > PR c++/98611 > * g++.dg/cpp2a/concepts-ctad1.C: New test. > * g++.dg/cpp2a/concepts-ctad2.C: New test. > --- > gcc/cp/pt.c | 4 ++++ > gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C | 16 ++++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C | 14 ++++++++++++++ > 3 files changed, 34 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 51540ca35a5..d3bb6231926 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -10694,6 +10694,10 @@ any_template_parm_r (tree t, void *data) > if (is_auto (t)) > if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t)) > WALK_SUBTREE (constr); > + /* A use of a CTAD placeholder is also a use of the template it > + represents. */ > + if (template_placeholder_p (t)) > + WALK_SUBTREE (CLASS_PLACEHOLDER_TEMPLATE (t)); > break; > > case TEMPLATE_ID_EXPR: > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C > new file mode 100644 > index 00000000000..ec2e4b014d7 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C > @@ -0,0 +1,16 @@ > +// PR c++/98611 > +// { dg-do compile { target c++20 } } > + > +template <class T, class U> > +concept IsSame = __is_same(T, U); > + > +template <class T, template <class...> class _Class> > +concept IsInstantiationOf = requires(T object) { > + { _Class{object} } -> IsSame<T>; > +}; > + > +template <class T> struct Degrees {}; > +static_assert(IsInstantiationOf<Degrees<int>, Degrees>); > + > +template <class T> struct NotDegrees {}; > +static_assert(!IsInstantiationOf<Degrees<int>, NotDegrees>); > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C > new file mode 100644 > index 00000000000..de960487713 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C > @@ -0,0 +1,14 @@ > +// PR c++/98611 > +// { dg-do compile { target c++20 } } > + > +template <class> > +struct S > +{ > + template <class T> struct Tmpl { Tmpl(T); }; > + > + template <class T> > + requires requires (T object) { Tmpl{object}; } > + static int f(T); > +}; > + > +int a = S<int>::f(0); >
On Mon, 11 Jan 2021, Jason Merrill wrote: > On 1/9/21 5:23 PM, Patrick Palka wrote: > > This patch teaches find_template_parameters to visit the template > > represented by a CTAD placeholder, which is normally not visited by > > for_each_template_parm. This template may be a template template > > parameter (as in the first testcase), or it may implicitly use the > > template parameters of an enclosing class template (as in the second > > testcase), and in either case we need to record the template parameters > > used therein for later satisfaction. > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > trunk and perhaps the 10 branch? Also tested on range-v3 and cmcstl2. > > > > gcc/cp/ChangeLog: > > > > PR c++/98611 > > * pt.c (any_template_parm_r) <case TEMPLATE_TYPE_PARM>: Visit > > the template of a CTAD placeholder. > > Did you consider doing this in cp_walk_subtrees instead of here? Briefly, but I couldn't convince myself which of the three visitors (cp_walk_subtrees, for_each_template_parm_r or any_template_parm_r) is the most appropriate place to do it in, so I defaulted to the most specific routine of the three. The following passes bootstrap and regtesting on x86_64-pc-linux-gnu. Shall we go with this? -- >8 -- gcc/cp/ChangeLog: PR c++/98611 * tree.c (cp_walk_subtrees) <case TEMPLATE_TYPE_PARM>: Visit the template of a CTAD placeholder. gcc/testsuite/ChangeLog: PR c++/98611 * g++.dg/cpp2a/concepts-ctad1.C: New test. * g++.dg/cpp2a/concepts-ctad2.C: New test. --- gcc/cp/tree.c | 5 ++++- gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C | 16 ++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C | 13 +++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c536eb581a7..d339036e88e 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5173,12 +5173,15 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, result = NULL_TREE; switch (code) { + case TEMPLATE_TYPE_PARM: + if (template_placeholder_p (*tp)) + WALK_SUBTREE (CLASS_PLACEHOLDER_TEMPLATE (*tp)); + /* Fall through. */ case DEFERRED_PARSE: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: case UNBOUND_CLASS_TEMPLATE: case TEMPLATE_PARM_INDEX: - case TEMPLATE_TYPE_PARM: case TYPEOF_TYPE: case UNDERLYING_TYPE: /* None of these have subtrees other than those already walked diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C new file mode 100644 index 00000000000..ec2e4b014d7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C @@ -0,0 +1,16 @@ +// PR c++/98611 +// { dg-do compile { target c++20 } } + +template <class T, class U> +concept IsSame = __is_same(T, U); + +template <class T, template <class...> class _Class> +concept IsInstantiationOf = requires(T object) { + { _Class{object} } -> IsSame<T>; +}; + +template <class T> struct Degrees {}; +static_assert(IsInstantiationOf<Degrees<int>, Degrees>); + +template <class T> struct NotDegrees {}; +static_assert(!IsInstantiationOf<Degrees<int>, NotDegrees>); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C new file mode 100644 index 00000000000..0d7f9790777 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C @@ -0,0 +1,13 @@ +// PR c++/98611 +// { dg-do compile { target c++20 } } + +template <class> +struct S { + template <class T> struct Tmpl { Tmpl(T); }; + + template <class T> + requires requires (T object) { Tmpl{object}; } + static int f(T); +}; + +int a = S<int>::f(0);
On 1/11/21 8:08 PM, Patrick Palka wrote: > On Mon, 11 Jan 2021, Jason Merrill wrote: > >> On 1/9/21 5:23 PM, Patrick Palka wrote: >>> This patch teaches find_template_parameters to visit the template >>> represented by a CTAD placeholder, which is normally not visited by >>> for_each_template_parm. This template may be a template template >>> parameter (as in the first testcase), or it may implicitly use the >>> template parameters of an enclosing class template (as in the second >>> testcase), and in either case we need to record the template parameters >>> used therein for later satisfaction. >>> >>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for >>> trunk and perhaps the 10 branch? Also tested on range-v3 and cmcstl2. >>> >>> gcc/cp/ChangeLog: >>> >>> PR c++/98611 >>> * pt.c (any_template_parm_r) <case TEMPLATE_TYPE_PARM>: Visit >>> the template of a CTAD placeholder. >> >> Did you consider doing this in cp_walk_subtrees instead of here? > > Briefly, but I couldn't convince myself which of the three visitors > (cp_walk_subtrees, for_each_template_parm_r or any_template_parm_r) is > the most appropriate place to do it in, so I defaulted to the most > specific routine of the three. > > The following passes bootstrap and regtesting on x86_64-pc-linux-gnu. > Shall we go with this? I think so; a class template placeholder is written explicitly in whatever we're walking over, so looking at it here makes sense to me. The patch is OK. > -- >8 -- > > gcc/cp/ChangeLog: > > PR c++/98611 > * tree.c (cp_walk_subtrees) <case TEMPLATE_TYPE_PARM>: Visit > the template of a CTAD placeholder. > > gcc/testsuite/ChangeLog: > > PR c++/98611 > * g++.dg/cpp2a/concepts-ctad1.C: New test. > * g++.dg/cpp2a/concepts-ctad2.C: New test. > --- > gcc/cp/tree.c | 5 ++++- > gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C | 16 ++++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C | 13 +++++++++++++ > 3 files changed, 33 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C > > diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c > index c536eb581a7..d339036e88e 100644 > --- a/gcc/cp/tree.c > +++ b/gcc/cp/tree.c > @@ -5173,12 +5173,15 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, > result = NULL_TREE; > switch (code) > { > + case TEMPLATE_TYPE_PARM: > + if (template_placeholder_p (*tp)) > + WALK_SUBTREE (CLASS_PLACEHOLDER_TEMPLATE (*tp)); > + /* Fall through. */ > case DEFERRED_PARSE: > case TEMPLATE_TEMPLATE_PARM: > case BOUND_TEMPLATE_TEMPLATE_PARM: > case UNBOUND_CLASS_TEMPLATE: > case TEMPLATE_PARM_INDEX: > - case TEMPLATE_TYPE_PARM: > case TYPEOF_TYPE: > case UNDERLYING_TYPE: > /* None of these have subtrees other than those already walked > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C > new file mode 100644 > index 00000000000..ec2e4b014d7 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C > @@ -0,0 +1,16 @@ > +// PR c++/98611 > +// { dg-do compile { target c++20 } } > + > +template <class T, class U> > +concept IsSame = __is_same(T, U); > + > +template <class T, template <class...> class _Class> > +concept IsInstantiationOf = requires(T object) { > + { _Class{object} } -> IsSame<T>; > +}; > + > +template <class T> struct Degrees {}; > +static_assert(IsInstantiationOf<Degrees<int>, Degrees>); > + > +template <class T> struct NotDegrees {}; > +static_assert(!IsInstantiationOf<Degrees<int>, NotDegrees>); > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C > new file mode 100644 > index 00000000000..0d7f9790777 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C > @@ -0,0 +1,13 @@ > +// PR c++/98611 > +// { dg-do compile { target c++20 } } > + > +template <class> > +struct S { > + template <class T> struct Tmpl { Tmpl(T); }; > + > + template <class T> > + requires requires (T object) { Tmpl{object}; } > + static int f(T); > +}; > + > +int a = S<int>::f(0); >
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 51540ca35a5..d3bb6231926 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10694,6 +10694,10 @@ any_template_parm_r (tree t, void *data) if (is_auto (t)) if (tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (t)) WALK_SUBTREE (constr); + /* A use of a CTAD placeholder is also a use of the template it + represents. */ + if (template_placeholder_p (t)) + WALK_SUBTREE (CLASS_PLACEHOLDER_TEMPLATE (t)); break; case TEMPLATE_ID_EXPR: diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C new file mode 100644 index 00000000000..ec2e4b014d7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad1.C @@ -0,0 +1,16 @@ +// PR c++/98611 +// { dg-do compile { target c++20 } } + +template <class T, class U> +concept IsSame = __is_same(T, U); + +template <class T, template <class...> class _Class> +concept IsInstantiationOf = requires(T object) { + { _Class{object} } -> IsSame<T>; +}; + +template <class T> struct Degrees {}; +static_assert(IsInstantiationOf<Degrees<int>, Degrees>); + +template <class T> struct NotDegrees {}; +static_assert(!IsInstantiationOf<Degrees<int>, NotDegrees>); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C new file mode 100644 index 00000000000..de960487713 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad2.C @@ -0,0 +1,14 @@ +// PR c++/98611 +// { dg-do compile { target c++20 } } + +template <class> +struct S +{ + template <class T> struct Tmpl { Tmpl(T); }; + + template <class T> + requires requires (T object) { Tmpl{object}; } + static int f(T); +}; + +int a = S<int>::f(0);