https://gcc.gnu.org/g:62daa81308c6c187059fcad98377146e30725fa5

commit r15-6975-g62daa81308c6c187059fcad98377146e30725fa5
Author: Patrick Palka <ppa...@redhat.com>
Date:   Thu Jan 16 16:40:08 2025 -0500

    c++: explicit spec of constrained member tmpl [PR107522]
    
    When defining a explicit specialization of a constrained member template
    (of a class template) such as f and g in the below testcase, the
    DECL_TEMPLATE_PARMS of the corresponding TEMPLATE_DECL are partially
    instantiated, whereas its associated constraints are carried over
    from the original template and thus are in terms of the original
    DECL_TEMPLATE_PARMS.  So during normalization for such an explicit
    specialization we need to consider the (parameters of) the most general
    template, since that's what the constraints are in terms of and since we
    always use the full set of template arguments during satisfaction.
    
            PR c++/107522
    
    gcc/cp/ChangeLog:
    
            * constraint.cc (get_normalized_constraints_from_decl): Use the
            most general template for an explicit specialization of a
            member template.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/concepts-explicit-spec7.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/constraint.cc                               | 18 +++++++++----
 .../g++.dg/cpp2a/concepts-explicit-spec7.C         | 30 ++++++++++++++++++++++
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 52ad88f37be0..a9caba8e2cc7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -701,11 +701,19 @@ get_normalized_constraints_from_decl (tree d, bool diag = 
false)
      accepting the latter causes the template parameter level of U
      to be reduced in a way that makes it overly difficult substitute
      concrete arguments (i.e., eventually {int, int} during satisfaction.  */
-  if (tmpl)
-  {
-    if (DECL_LANG_SPECIFIC (tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
-      tmpl = most_general_template (tmpl);
-  }
+  if (tmpl && DECL_LANG_SPECIFIC (tmpl)
+      && (!DECL_TEMPLATE_SPECIALIZATION (tmpl)
+         /* DECL_TEMPLATE_SPECIALIZATION means TMPL is either a partial
+            specialization, or an explicit specialization of a member
+            template.  In the former case all is well: TMPL's constraints
+            are in terms of its parameters.  But in the latter case TMPL's
+            parameters are partially instantiated whereas its constraints
+            aren't, so we need to instead use (the parameters of) the most
+            general template.  The following test distinguishes between a
+            partial specialization and such an explicit specialization.  */
+         || (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
+             < TMPL_ARGS_DEPTH (DECL_TI_ARGS (tmpl)))))
+    tmpl = most_general_template (tmpl);
 
   d = tmpl ? tmpl : decl;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec7.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec7.C
new file mode 100644
index 000000000000..9452159faf77
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-explicit-spec7.C
@@ -0,0 +1,30 @@
+// PR c++/107522
+// { dg-do compile { target c++20 } }
+
+template<class T>
+struct A {
+  template<int N>
+  static void f() requires (N == 42);
+
+  template<class U>
+  struct B {
+    template<int N>
+    static void g() requires (T(N) == 42);
+  };
+};
+
+template<>
+template<int N>
+void A<int>::f() requires (N == 42) { }
+
+template<>
+template<>
+template<int N>
+void A<int>::B<int>::g() requires (int(N) == 42) { }
+
+int main() {
+  A<int>::f<42>();
+  A<int>::f<43>(); // { dg-error "no match" }
+  A<int>::B<int>::g<42>();
+  A<int>::B<int>::g<43>(); // { dg-error "no match" }
+}

Reply via email to