c++: Fix specialization of constrained member template.
authorJason Merrill <jason@redhat.com>
Mon, 11 May 2020 19:46:59 +0000 (15:46 -0400)
committerJason Merrill <jason@redhat.com>
Mon, 11 May 2020 20:19:53 +0000 (16:19 -0400)
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.

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

Resolve C++20 NB comment CA104
* pt.c (determine_specialization): Compare constraints for
specialization of member template of class instantiation.

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-spec1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/nontype18.C

index 5195a0a..5cf9dda 100644 (file)
@@ -1,5 +1,11 @@
 2020-05-11  Jason Merrill  <jason@redhat.com>
 
+       Resolve C++20 NB comment CA104
+       * pt.c (determine_specialization): Compare constraints for
+       specialization of member template of class instantiation.
+
+2020-05-11  Jason Merrill  <jason@redhat.com>
+
        PR c++/92583
        PR c++/92654
        * tree.c (cp_walk_subtrees): Stop at typedefs.
index 86f1bb7..8486456 100644 (file)
@@ -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 (file)
index 0000000..5001813
--- /dev/null
@@ -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
index cbe0a1b..b68416d 100644 (file)
@@ -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 "" }