In the three-parameter version of satisfy_declaration_constraints, when 't' isn't the most general template, then 't' doesn't correspond with the augmented template arguments 'args', and so the instantiation context that we push via push_tinst_level isn't quite correct. This manifests as misleading diagnostic context lines during satisfaction failure as in the testcase below for which without this patch we emit In substitution of '... static void A<int>::f<U>() [with U = int]' and with this patch we emit In substitution of '... static void A<T>::f<U>() [with U = char; T = int]'.
This patch fixes this by passing the most general template to push_tinst_level. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? gcc/cp/ChangeLog: PR c++/99214 * constraint.cc (get_normalized_constraints_from_decl): Fix formatting. (satisfy_declaration_constraints): Be lazy about augmenting 'args'. Pass the most general template to push_tinst_level. gcc/testsuite/ChangeLog: PR c++/99214 * g++.dg/concepts/diagnostic16.C: New test. --- gcc/cp/constraint.cc | 16 ++++++++-------- gcc/testsuite/g++.dg/concepts/diagnostic16.C | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic16.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 31e0fb5079a..88963e687a7 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -910,11 +910,9 @@ 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)) + tmpl = most_general_template (tmpl); /* If we're not diagnosing errors, use cached constraints, if any. */ if (!diag) @@ -3157,12 +3155,14 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) gcc_assert (TREE_CODE (t) == TEMPLATE_DECL); - args = add_outermost_template_args (t, args); - tree result = boolean_true_node; if (tree norm = normalize_template_requirements (t, info.noisy ())) { - if (!push_tinst_level (t, args)) + args = add_outermost_template_args (t, args); + tree gen_tmpl = t; + if (DECL_LANG_SPECIFIC (t) && !DECL_TEMPLATE_SPECIALIZATION (t)) + gen_tmpl = most_general_template (t); + if (!push_tinst_level (gen_tmpl, args)) return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_access_scope (pattern); diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic16.C b/gcc/testsuite/g++.dg/concepts/diagnostic16.C new file mode 100644 index 00000000000..b8d586e9a21 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic16.C @@ -0,0 +1,15 @@ +// PR c++/99214 +// { dg-do compile { target c++20 } } + +template <class T> +struct A { + template <class U> static void f() requires ([] { return U::fail; }()); // { dg-error "fail" } + template <class U> static void f(); +}; + +int main() { + A<int>::f<char>(); +} + +// This matches the context line "In substitution of '... [with U = char; T = int]'" +// { dg-message "U = char; T = int" "" { target *-*-* } 0 } -- 2.30.1.602.g966e671106