The resolution of comment CA104 clarifies that we need to do direct
substitution of constraints in order to determine which member template
corresponds to an explicit specialization.

Tested x86_64-pc-linux-gnu, applying to trunk.

gcc/cp/ChangeLog
2020-05-11  Jason Merrill  <ja...@redhat.com>

        Resolve C++20 NB comment CA104
        * pt.c (determine_specialization): Compare constraints for
        specialization of member template of class instantiation.
---
 gcc/cp/pt.c                                 | 28 ++++++++++++++++++---
 gcc/testsuite/g++.dg/cpp2a/concepts-spec1.C | 10 ++++++++
 gcc/testsuite/g++.dg/template/nontype18.C   |  2 +-
 3 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-spec1.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 86f1bb7470d..84864561c25 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2282,8 +2282,29 @@ determine_specialization (tree template_id,
              below. */
          if (tsk == tsk_template)
            {
-             if (compparms (fn_arg_types, decl_arg_types))
-               candidates = tree_cons (NULL_TREE, fn, candidates);
+             if (!comp_template_parms (DECL_TEMPLATE_PARMS (fn),
+                                       current_template_parms))
+               continue;
+             if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)),
+                               TREE_TYPE (TREE_TYPE (fn))))
+               continue;
+             if (!compparms (fn_arg_types, decl_arg_types))
+               continue;
+
+             tree freq = get_trailing_function_requirements (fn);
+             tree dreq = get_trailing_function_requirements (decl);
+             if (!freq != !dreq)
+               continue;
+             if (freq)
+               {
+                 tree fargs = DECL_TI_ARGS (fn);
+                 tsubst_flags_t complain = tf_none;
+                 freq = tsubst_constraint (freq, fargs, complain, fn);
+                 if (!cp_tree_equal (freq, dreq))
+                   continue;
+               }
+
+             candidates = tree_cons (NULL_TREE, fn, candidates);
              continue;
            }
 
@@ -2472,7 +2493,8 @@ determine_specialization (tree template_id,
       *targs_out = copy_node (DECL_TI_ARGS (fn));
 
       /* Propagate the candidate's constraints to the declaration.  */
-      set_constraints (decl, get_constraints (fn));
+      if (tsk != tsk_template)
+       set_constraints (decl, get_constraints (fn));
 
       /* DECL is a re-declaration or partial instantiation of a template
         function.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-spec1.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-spec1.C
new file mode 100644
index 00000000000..5001813d7b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-spec1.C
@@ -0,0 +1,10 @@
+// Example from CA 104 proposal.
+// { dg-do compile { target concepts } }
+
+template <class T> concept C = sizeof(T) == 8;
+template <class T> struct A {
+  template <class U> U f(U) requires C<typename T::type>; // #1
+  template <class U> U f(U) requires C<T>; // #2
+};
+
+template <> template <class U> U A<int>::f(U) requires C<int> { } // OK, 
specializes #2
diff --git a/gcc/testsuite/g++.dg/template/nontype18.C 
b/gcc/testsuite/g++.dg/template/nontype18.C
index cbe0a1b5a0d..b68416dca61 100644
--- a/gcc/testsuite/g++.dg/template/nontype18.C
+++ b/gcc/testsuite/g++.dg/template/nontype18.C
@@ -5,4 +5,4 @@ template<int I> struct A
     template<typename T> void foo();
 };
 
-template<int I> template<typename T> void A<0>::foo() {} // { dg-error 
"template parameter" }
+template<int I> template<typename T> void A<0>::foo() {} // { dg-error "" }

base-commit: 42e9f80bf4f6a38733c221c03a512c432cdb784f
-- 
2.18.1

Reply via email to