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