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

Reply via email to