Skip to content

Commit f1872cc

Browse files
committed
c++: Unwrap type traits defined in terms of builtins within diagnostics [PR117294]
Currently, concept failures of standard type traits just report 'expression X<T> evaluates to false'. However, many type traits are actually defined in terms of compiler builtins; we can do better here. For instance, 'is_constructible_v' could go on to explain why the type is not constructible, or 'is_invocable_v' could list potential candidates. Apart from concept diagnostics, this is also useful when using such traits in a 'static_assert' directly, so this patch also adjusts the diagnostics in that context. As a first step to supporting that we need to be able to map the standard type traits to the builtins that they use. Rather than adding another list that would need to be kept up-to-date whenever a builtin is added, this patch instead tries to detect any variable template defined directly in terms of a TRAIT_EXPR. This patch also adjusts 'diagnose_trait_expr' to provide more helpful diagnostics for these cases. Not all type traits have yet been updated, this patch just updates those that seem particularly valuable or straight-forward. The function also gets moved to cp/semantics.cc to be closer to 'trait_expr_value'. Various other parts of the compiler are also adjusted here to assist in making clear diagnostics, such as making more use of 'is_stub_object' to refer to a type directly rather than in terms of 'std::declval<T>()'. Additionally, since there are now more cases of nesting within a 'static_assert'ion I felt it was helpful for the experimental-nesting mode to nest here as well. PR c++/117294 PR c++/113854 gcc/cp/ChangeLog: * call.cc (implicit_conversion_error): Hide label when printing a stub object. (convert_like_internal): Likewise, and nest candidate diagnostics. * constexpr.cc (diagnose_failing_condition): Nest diagnostics, attempt to provide more helpful diagnostics for traits. * constraint.cc (satisfy_atom): Pass result before constant evaluation to diagnose_atomic_constraint. (diagnose_trait_expr): Adjust diagnostics for clarity and detail. (maybe_diagnose_standard_trait): New function. (diagnose_atomic_constraint): Attempt to provide more helpful diagnostics for more traits. * cp-tree.h (explain_not_noexcept): Declare new function. (is_trivially_xible): Add parameter. (is_nothrow_xible): Likewise. (is_xible): Likewise. (is_convertible): Likewise. (is_nothrow_convertible): Likewise. (diagnose_trait_expr): Declare new function. (maybe_diagnose_standard_trait): Declare new function. * error.cc (dump_type) <case TREE_VEC>: Handle trait types. * except.cc (explain_not_noexcept): New function. * method.cc (build_trait_object): Add complain parameter. (build_invoke): Propagate complain parameter. (assignable_expr): Add explain parameter to show diagnostics. (constructible_expr): Likewise. (destructible_expr): Likewise. (is_xible_helper): Replace trivial flag with explain flag, add diagnostics. (is_trivially_xible): New explain flag. (is_nothrow_xible): Likewise. (is_xible): Likewise. (is_convertible_helper): Add complain flag. (is_convertible): New explain flag. (is_nothrow_convertible): Likewise. * typeck.cc (cp_build_function_call_vec): Add handling for stub objects. (convert_arguments): Always return -1 on error. * typeck2.cc (cxx_readonly_error): Add handling for stub objects. libstdc++-v3/ChangeLog: * testsuite/20_util/any/misc/any_cast_neg.cc: Adjust diagnostics. * testsuite/20_util/expected/illformed_neg.cc: Likewise. * testsuite/20_util/optional/monadic/or_else_neg.cc: Likewise. * testsuite/23_containers/array/creation/3_neg.cc: Likewise. * testsuite/24_iterators/range_generators/lwg3900.cc: Likewise. * testsuite/29_atomics/atomic/requirements/types_neg.cc: Likewise. * testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc: Likewise. * testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc: Likewise. * testsuite/std/format/arguments/args_neg.cc: Likewise. * testsuite/std/format/string_neg.cc: Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-traits3.C: Adjust diagnostics. * g++.dg/cpp2a/concepts-traits4.C: New test. * g++.dg/diagnostic/static_assert5.C: New test. * g++.dg/ext/has_virtual_destructor2.C: New test. * g++.dg/ext/is_assignable2.C: New test. * g++.dg/ext/is_constructible9.C: New test. * g++.dg/ext/is_convertible7.C: New test. * g++.dg/ext/is_destructible3.C: New test. * g++.dg/ext/is_invocable6.C: New test. * g++.dg/ext/is_virtual_base_of_diagnostic2.C: New test. Signed-off-by: Nathaniel Shead <[email protected]> Reviewed-by: Patrick Palka <[email protected]> Reviewed-by: Jason Merrill <[email protected]>
1 parent 257b640 commit f1872cc

File tree

29 files changed

+860
-187
lines changed

29 files changed

+860
-187
lines changed

gcc/cp/call.cc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4927,6 +4927,11 @@ implicit_conversion_error (location_t loc, tree type, tree expr)
49274927
&& !CP_AGGREGATE_TYPE_P (type))
49284928
error_at (loc, "designated initializers cannot be used with a "
49294929
"non-aggregate type %qT", type);
4930+
else if (is_stub_object (expr))
4931+
/* The expression is generated by a trait check, we don't have
4932+
a useful location to highlight the label. */
4933+
error_at (loc, "could not convert %qH to %qI",
4934+
TREE_TYPE (expr), type);
49304935
else
49314936
{
49324937
range_label_for_type_mismatch label (TREE_TYPE (expr), type);
@@ -8698,6 +8703,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
86988703
diagnostic_t diag_kind;
86998704
int flags;
87008705
location_t loc = cp_expr_loc_or_input_loc (expr);
8706+
const bool stub_object_p = is_stub_object (expr);
87018707

87028708
if (convs->bad_p && !(complain & tf_error))
87038709
return error_mark_node;
@@ -8774,7 +8780,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
87748780
"from %qH to %qI", TREE_TYPE (expr),
87758781
totype);
87768782
if (complained)
8777-
print_z_candidate (loc, N_("candidate is:"), t->cand);
8783+
{
8784+
auto_diagnostic_nesting_level sentinel;
8785+
print_z_candidate (loc, N_("candidate is:"), t->cand);
8786+
}
87788787
expr = convert_like (t, expr, fn, argnum,
87798788
/*issue_conversion_warnings=*/false,
87808789
/*c_cast_p=*/false, /*nested_p=*/true,
@@ -8799,7 +8808,14 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
87998808
else if (t->kind == ck_identity)
88008809
break;
88018810
}
8802-
if (!complained && expr != error_mark_node)
8811+
if (!complained && stub_object_p)
8812+
{
8813+
/* An error diagnosed within a trait, don't give extra labels. */
8814+
error_at (loc, "invalid conversion from %qH to %qI",
8815+
TREE_TYPE (expr), totype);
8816+
complained = 1;
8817+
}
8818+
else if (!complained && expr != error_mark_node)
88038819
{
88048820
range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
88058821
gcc_rich_location richloc (loc, &label, highlight_colors::percent_h);

gcc/cp/constexpr.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2883,10 +2883,15 @@ diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p,
28832883
if (TREE_CODE (bad) == CLEANUP_POINT_EXPR)
28842884
bad = TREE_OPERAND (bad, 0);
28852885

2886+
auto_diagnostic_nesting_level sentinel;
2887+
28862888
/* Actually explain the failure if this is a concept check or a
28872889
requires-expression. */
28882890
if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR)
28892891
diagnose_constraints (cloc, bad, NULL_TREE);
2892+
/* Similarly if this is a standard trait. */
2893+
else if (maybe_diagnose_standard_trait (cloc, bad))
2894+
;
28902895
else if (COMPARISON_CLASS_P (bad)
28912896
&& ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0))))
28922897
{

0 commit comments

Comments
 (0)