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. 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); -- 2.30.0