c++: Some improvements to concept diagnostics
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 print unsatisfied atomic constraint expressions with their template arguments. So e.g. we now print cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C<Tx>)()) [with Tx = {int, long int, 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. gcc/cp/ChangeLog: * constraint.cc (finish_constraint_binary_op): Set expr's location range to the range of its operands. (satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint. (diagnose_trait_expr): Take the instantiated parameter mapping MAP instead of the corresponding template arguments ARGS and adjust body accordingly. (diagnose_requires_expr): Likewise. (diagnose_atomic_constraint): Likewise. When printing an atomic constraint expression, print the instantiated parameter mapping alongside it. * cxx-pretty-print.cc (cxx_pretty_printer::expression) [NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK. (cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic2.C: New test. * g++.dg/concepts/diagnostic3.C: New test.
This commit is contained in:
parent
38e1002657
commit
44f6b7fb57
6 changed files with 116 additions and 14 deletions
|
@ -1,3 +1,19 @@
|
|||
2020-02-26 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
* constraint.cc (finish_constraint_binary_op): Set expr's location range
|
||||
to the range of its operands.
|
||||
(satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint.
|
||||
(diagnose_trait_expr): Take the instantiated parameter mapping MAP
|
||||
instead of the corresponding template arguments ARGS and adjust body
|
||||
accordingly.
|
||||
(diagnose_requires_expr): Likewise.
|
||||
(diagnose_atomic_constraint): Likewise. When printing an atomic
|
||||
constraint expression, print the instantiated parameter mapping
|
||||
alongside it.
|
||||
* cxx-pretty-print.cc (cxx_pretty_printer::expression)
|
||||
[NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK.
|
||||
(cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK.
|
||||
|
||||
2020-02-26 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/93676 - value-init crash in template.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -2547,7 +2547,7 @@ satisfy_atom (tree t, tree args, subst_info info)
|
|||
/* Compute the value of the constraint. */
|
||||
result = satisfaction_value (cxx_constant_value (result));
|
||||
if (result == boolean_false_node && info.noisy ())
|
||||
diagnose_atomic_constraint (t, args, info);
|
||||
diagnose_atomic_constraint (t, map, info);
|
||||
|
||||
return cache.save (result);
|
||||
}
|
||||
|
@ -3056,9 +3056,10 @@ get_constraint_error_location (tree t)
|
|||
/* Emit a diagnostic for a failed trait. */
|
||||
|
||||
void
|
||||
diagnose_trait_expr (tree expr, tree args)
|
||||
diagnose_trait_expr (tree expr, tree map)
|
||||
{
|
||||
location_t loc = cp_expr_location (expr);
|
||||
tree args = get_mapped_args (map);
|
||||
|
||||
/* Build a "fake" version of the instantiated trait, so we can
|
||||
get the instantiated types from result. */
|
||||
|
@ -3271,11 +3272,12 @@ diagnose_requirement (tree req, tree args, tree in_decl)
|
|||
}
|
||||
|
||||
static void
|
||||
diagnose_requires_expr (tree expr, tree args, tree in_decl)
|
||||
diagnose_requires_expr (tree expr, tree map, tree in_decl)
|
||||
{
|
||||
local_specialization_stack stack (lss_copy);
|
||||
tree parms = TREE_OPERAND (expr, 0);
|
||||
tree body = TREE_OPERAND (expr, 1);
|
||||
tree args = get_mapped_args (map);
|
||||
|
||||
cp_unevaluated u;
|
||||
subst_info info (tf_warning_or_error, NULL_TREE);
|
||||
|
@ -3292,11 +3294,11 @@ diagnose_requires_expr (tree expr, tree args, tree in_decl)
|
|||
}
|
||||
}
|
||||
|
||||
/* Diagnose a substitution failure in the atomic constraint T. Note that
|
||||
ARGS have been previously instantiated through the parameter map. */
|
||||
/* Diagnose a substitution failure in the atomic constraint T when applied
|
||||
with the instantiated parameter mapping MAP. */
|
||||
|
||||
static void
|
||||
diagnose_atomic_constraint (tree t, tree args, subst_info info)
|
||||
diagnose_atomic_constraint (tree t, tree map, subst_info info)
|
||||
{
|
||||
/* If the constraint is already ill-formed, we've previously diagnosed
|
||||
the reason. We should still say why the constraints aren't satisfied. */
|
||||
|
@ -3320,17 +3322,20 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info)
|
|||
switch (TREE_CODE (expr))
|
||||
{
|
||||
case TRAIT_EXPR:
|
||||
diagnose_trait_expr (expr, args);
|
||||
diagnose_trait_expr (expr, map);
|
||||
break;
|
||||
case REQUIRES_EXPR:
|
||||
diagnose_requires_expr (expr, args, info.in_decl);
|
||||
diagnose_requires_expr (expr, map, info.in_decl);
|
||||
break;
|
||||
case INTEGER_CST:
|
||||
/* This must be either 0 or false. */
|
||||
inform (loc, "%qE is never satisfied", expr);
|
||||
break;
|
||||
default:
|
||||
inform (loc, "the expression %qE evaluated to %<false%>", expr);
|
||||
tree a = copy_node (t);
|
||||
ATOMIC_CONSTR_MAP (a) = map;
|
||||
inform (loc, "the expression %qE evaluated to %<false%>", a);
|
||||
ggc_free (a);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1214,12 +1214,14 @@ cxx_pretty_printer::expression (tree t)
|
|||
{
|
||||
tree args = ARGUMENT_PACK_ARGS (t);
|
||||
int i, len = TREE_VEC_LENGTH (args);
|
||||
pp_cxx_left_brace (this);
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
pp_cxx_separate_with (this, ',');
|
||||
expression (TREE_VEC_ELT (args, i));
|
||||
}
|
||||
pp_cxx_right_brace (this);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1839,6 +1841,21 @@ cxx_pretty_printer::type_id (tree t)
|
|||
pp_cxx_ws_string (this, "...");
|
||||
break;
|
||||
|
||||
case TYPE_ARGUMENT_PACK:
|
||||
{
|
||||
tree args = ARGUMENT_PACK_ARGS (t);
|
||||
int len = TREE_VEC_LENGTH (args);
|
||||
pp_cxx_left_brace (this);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
pp_cxx_separate_with (this, ',');
|
||||
type_id (TREE_VEC_ELT (args, i));
|
||||
}
|
||||
pp_cxx_right_brace (this);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
c_pretty_printer::type_id (t);
|
||||
break;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2020-02-26 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
* g++.dg/concepts/diagnostic2.C: New test.
|
||||
* g++.dg/concepts/diagnostic3.C: New test.
|
||||
|
||||
2020-02-26 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/93676 - value-init crash in template.
|
||||
|
|
30
gcc/testsuite/g++.dg/concepts/diagnostic2.C
Normal file
30
gcc/testsuite/g++.dg/concepts/diagnostic2.C
Normal file
|
@ -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 "" } */
|
||||
}
|
29
gcc/testsuite/g++.dg/concepts/diagnostic3.C
Normal file
29
gcc/testsuite/g++.dg/concepts/diagnostic3.C
Normal file
|
@ -0,0 +1,29 @@
|
|||
// { 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&>);
|
||||
|
||||
template<typename... Ts>
|
||||
requires (foo<Ts> && ...)
|
||||
void
|
||||
bar() // { dg-message "with Ts = .int, char... evaluated to .false." }
|
||||
{ }
|
||||
|
||||
template<int>
|
||||
struct S { };
|
||||
|
||||
template<int... Is>
|
||||
requires (foo<S<Is>> && ...)
|
||||
void
|
||||
baz() // { dg-message "with Is = .2, 3, 4... evaluated to .false." }
|
||||
{ }
|
||||
|
||||
void
|
||||
baz()
|
||||
{
|
||||
bar<int, char>(); // { dg-error "unsatisfied constraints" }
|
||||
baz<2,3,4>(); // { dg-error "unsatisfied constraints" }
|
||||
}
|
Loading…
Add table
Reference in a new issue