Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk/14?
-- >8 -- In the three-parameter version of satisfy_declaration_constraints, when 't' isn't the most general template, then 't' won't correspond with 'args' after we augment the latter via add_outermost_template_args, and so the instantiation context that we push via push_tinst_level isn't quite correct: 'args' is a complete set of template arguments, but 't' is not necessarily the most general template. This manifests as misleading diagnostic context lines when issuing a hard error (or a constraint recursion error) that occurred during satisfaction, e.g. for the below testcase without this patch we emit: In substitution of '... void A<int>::f<U>() [with U = int]' and with this patch we emit: In substitution of '... void A<T>::f<U>() [with U = char; T = int]'. This patch fixes this by always passing the most general template to push_tinst_level. PR c++/99214 gcc/cp/ChangeLog: * constraint.cc (get_normalized_constraints_from_decl): New out-parameter GEN_D. (satisfy_declaration_constraints): Use it to pass the most general version of T to push_tinst_level. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic20.C: New test. --- gcc/cp/constraint.cc | 15 +++++++++++---- gcc/testsuite/g++.dg/concepts/diagnostic20.C | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic20.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index a9caba8e2cc..f688a99c5fd 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -648,10 +648,13 @@ get_normalized_constraints_from_info (tree ci, tree in_decl, bool diag = false) return t; } -/* Returns the normalized constraints for the declaration D. */ +/* Returns the normalized constraints for the declaration D. + If GEN_D is non-NULL, sets *GEN_D to the most general version + of D that ultimately owns its constraints. */ static tree -get_normalized_constraints_from_decl (tree d, bool diag = false) +get_normalized_constraints_from_decl (tree d, bool diag = false, + tree *gen_d = nullptr) { tree tmpl; tree decl; @@ -716,6 +719,8 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) tmpl = most_general_template (tmpl); d = tmpl ? tmpl : decl; + if (gen_d) + *gen_d = d; /* If we're not diagnosing errors, use cached constraints, if any. */ if (!diag) @@ -2730,9 +2735,11 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) return boolean_true_node; tree result = boolean_true_node; - if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ())) + tree gen_t; + if (tree norm = get_normalized_constraints_from_decl (t, info.noisy (), + &gen_t)) { - if (!push_tinst_level (t, args)) + if (!push_tinst_level (gen_t, args)) return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_to_top_level (); diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic20.C b/gcc/testsuite/g++.dg/concepts/diagnostic20.C new file mode 100644 index 00000000000..b8d586e9a21 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic20.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.49.0.rc0.57.gdb91954e18