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 5195a0a043f9426e03ff30a7cda5b993400a027a..5cf9dda42e2c8800e455c06a1dd9f69c9b3b6de8 100644 (file)
@@ -1,3 +1,9 @@
+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
index 86f1bb7470df0ddb3efafb61d3ab8c7910ba0b2d..84864561c2581d7578fcf595a18244854f11c29c 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 cbe0a1b5a0d7f29ea9a600e73684a04c70bbf637..b68416dca6188befdc130a5c79f11de15acc6be4 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 "" }