This patch improves our concept diagnostics in two ways. First, it sets a more precise location for the constraint expressions built in finish_constraint_binary_op. As a result, when a disjunction is unsatisfied we now print e.g.
.../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 466 | requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 467 | || __adl_end<_Tp> | ^~~~~~~~~~~~~~~~~ instead of .../include/bits/range_access.h:467:2: note: neither operand of the disjunction is satisfied 467 | || __adl_end<_Tp> | ^~ Second, this patch changes diagnose_atomic_constraint to pretty-print unsatisfied atomic constraint expressions with their template arguments substituted in (if doing so does not result in a trivial expression). So for example we now emit cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C<int>() && C<long int>()) && C<void>())’ evaluated to ‘false’ instead of cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C<Tx>)())’ evaluated to ‘false’ Tested on x86_64-pc-linux-gnu, and verified that all the diagnostics emitted in our concept tests are no worse with this patch. Does this look OK to commit? gcc/cp/ChangeLog: * constraint.cc (finish_constraint_binary_op): Set expr's location range to the range of its operands. (diagnose_atomic_constraint): Prefer to pretty-print the atomic constraint with template arguments substituted in. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: New test. * g++.dg/concepts/diagnostic3.C: New test. --- gcc/cp/constraint.cc | 15 +++++++---- gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +++++++++++++++++++++ gcc/testsuite/g++.dg/concepts/diagnostic3.C | 19 +++++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 58044cd0f9d..4f6bc11e7e8 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc, if (!check_constraint_operands (loc, lhs, rhs)) return error_mark_node; tree overload; - tree expr = build_x_binary_op (loc, code, - lhs, TREE_CODE (lhs), - rhs, TREE_CODE (rhs), - &overload, tf_none); + cp_expr expr = build_x_binary_op (loc, code, + lhs, TREE_CODE (lhs), + rhs, TREE_CODE (rhs), + &overload, tf_none); /* When either operand is dependent, the overload set may be non-empty. */ if (expr == error_mark_node) return error_mark_node; - SET_EXPR_LOCATION (expr, loc); + expr.set_range (lhs.get_start (), rhs.get_finish ()); return expr; } @@ -3330,6 +3330,11 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info) inform (loc, "%qE is never satisfied", expr); break; default: + tree orig_expr = expr; + expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false); + if (CONSTANT_CLASS_P (expr)) + /* We are better off printing the original expression. */ + expr = orig_expr; inform (loc, "the expression %qE evaluated to %<false%>", expr); } } diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C b/gcc/testsuite/g++.dg/concepts/diagnostic2.C new file mode 100644 index 00000000000..ce51b71fa8b --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C @@ -0,0 +1,30 @@ +// { dg-do compile { target c++2a } } +// { dg-options "-fdiagnostics-show-caret" } + +template<typename T> + inline constexpr bool foo_v = false; + +template<typename T> + concept foo = foo_v<T> || foo_v<T&>; // { dg-message "neither operand" } +/* { dg-begin-multiline-output "" } + concept foo = foo_v<T> || foo_v<T&>; + ~~~~~~~~~^~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + +template<typename T> + requires foo<T> + void bar(); +/* { dg-begin-multiline-output "" } + void bar(); + { dg-end-multiline-output "" } */ +/* { dg-prune-output "~" } */ + +void +baz() +{ + bar<int>(); // { dg-error "unsatisfied constraints" } +/* { dg-begin-multiline-output "" } + bar<int>(); + ^ + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic3.C b/gcc/testsuite/g++.dg/concepts/diagnostic3.C new file mode 100644 index 00000000000..e0649dac51a --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic3.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++2a } } + +template<typename T> + inline constexpr bool foo_v = false; + +template<typename T> + concept foo = (bool)(foo_v<T> | foo_v<T&>); // { dg-message "foo_v<int>.*foo_v<int&>" } + +template<typename T> +requires foo<T> +void +bar() +{ } + +void +baz() +{ + bar<int>(); // { dg-error "unsatisfied constraints" } +} -- 2.25.1.291.ge68e29171c