https://gcc.gnu.org/g:3e8ce187dc4595da3d2f41a0fb09ee9cd2e437ff
commit r16-6707-g3e8ce187dc4595da3d2f41a0fb09ee9cd2e437ff Author: Nathaniel Shead <[email protected]> Date: Sun Jan 11 10:02:45 2026 +1100 c++: Improve diagnostic for implicit conversion errors [PR115163] This patch adds a note to indicate if any viable explicit conversion functions were skipped if an implicit conversion failed to occur. Perhaps the base diagnostic in ocp_convert can be further improved for class types as well, as the current message is not very clear, but I've not looked into that for this patch. PR c++/115163 gcc/cp/ChangeLog: * call.cc (implicit_conversion_error): Add flags argument, call maybe_show_nonconverting_candidate. (build_converted_constant_expr_internal): Pass flags to implicit_conversion_error. (perform_implicit_conversion_flags): Likewise. * cvt.cc (ocp_convert): Call maybe_show_nonconverting_candidate on conversion error. gcc/testsuite/ChangeLog: * g++.dg/ext/is_convertible7.C: Add new testcases. * g++.dg/diagnostic/explicit2.C: New test. Signed-off-by: Nathaniel Shead <[email protected]> Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/call.cc | 34 +++++++++++++++++------------ gcc/cp/cvt.cc | 9 ++++++-- gcc/testsuite/g++.dg/diagnostic/explicit2.C | 14 ++++++++++++ gcc/testsuite/g++.dg/ext/is_convertible7.C | 12 ++++++++++ 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 608fb9b69d00..34d23e998490 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -4917,7 +4917,8 @@ build_user_type_conversion (tree totype, tree expr, int flags, /* Give a helpful diagnostic when implicit_conversion fails. */ static void -implicit_conversion_error (location_t loc, tree type, tree expr) +implicit_conversion_error (location_t loc, tree type, tree expr, + int flags) { tsubst_flags_t complain = tf_warning_or_error; @@ -4932,18 +4933,23 @@ implicit_conversion_error (location_t loc, tree type, tree expr) && !CP_AGGREGATE_TYPE_P (type)) error_at (loc, "designated initializers cannot be used with a " "non-aggregate type %qT", type); - else if (is_stub_object (expr)) - /* The expression is generated by a trait check, we don't have - a useful location to highlight the label. */ - error_at (loc, "could not convert %qH to %qI", - TREE_TYPE (expr), type); - else + else { - range_label_for_type_mismatch label (TREE_TYPE (expr), type); - gcc_rich_location rich_loc (loc, &label, - highlight_colors::percent_h); - error_at (&rich_loc, "could not convert %qE from %qH to %qI", - expr, TREE_TYPE (expr), type); + auto_diagnostic_group d; + if (is_stub_object (expr)) + /* The expression is generated by a trait check, we don't have + a useful location to highlight the label. */ + error_at (loc, "could not convert %qH to %qI", + TREE_TYPE (expr), type); + else + { + range_label_for_type_mismatch label (TREE_TYPE (expr), type); + gcc_rich_location rich_loc (loc, &label, + highlight_colors::percent_h); + error_at (&rich_loc, "could not convert %qE from %qH to %qI", + expr, TREE_TYPE (expr), type); + } + maybe_show_nonconverting_candidate (type, TREE_TYPE (expr), expr, flags); } } @@ -5065,7 +5071,7 @@ build_converted_constant_expr_internal (tree type, tree expr, else { if (complain & tf_error) - implicit_conversion_error (loc, type, expr); + implicit_conversion_error (loc, type, expr, flags); expr = error_mark_node; } @@ -14107,7 +14113,7 @@ perform_implicit_conversion_flags (tree type, tree expr, if (!conv) { if (complain & tf_error) - implicit_conversion_error (loc, type, expr); + implicit_conversion_error (loc, type, expr, flags); expr = error_mark_node; } else if (processing_template_decl && conv->kind != ck_identity) diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index 3dfa0529b9be..771f72106cd2 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -994,8 +994,13 @@ ocp_convert (tree type, tree expr, int convtype, int flags, if (invalid_nonstatic_memfn_p (loc, expr, complain)) /* We displayed the error message. */; else - error_at (loc, "conversion from %qH to non-scalar type %qI requested", - TREE_TYPE (expr), type); + { + auto_diagnostic_group d; + error_at (loc, "conversion from %qH to non-scalar type %qI requested", + TREE_TYPE (expr), type); + maybe_show_nonconverting_candidate (type, TREE_TYPE (expr), expr, + flags); + } } return error_mark_node; } diff --git a/gcc/testsuite/g++.dg/diagnostic/explicit2.C b/gcc/testsuite/g++.dg/diagnostic/explicit2.C new file mode 100644 index 000000000000..46fea3cc20be --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/explicit2.C @@ -0,0 +1,14 @@ +// PR c++/115163 +// { dg-do compile { target c++11 } } + +struct A { + explicit A(int); // { dg-message "explicit conversion function was not considered" } +}; +struct B { + explicit operator int() const; // { dg-message "explicit conversion function was not considered" } +}; + +int main() { + A a = 42; // { dg-error "conversion from .int. to non-scalar type .A." } + int x = B{}; // { dg-error "cannot convert .B. to .int. in initialization" } +} diff --git a/gcc/testsuite/g++.dg/ext/is_convertible7.C b/gcc/testsuite/g++.dg/ext/is_convertible7.C index b38fc042de98..2bdc07bad06a 100644 --- a/gcc/testsuite/g++.dg/ext/is_convertible7.C +++ b/gcc/testsuite/g++.dg/ext/is_convertible7.C @@ -27,3 +27,15 @@ struct B { }; static_assert(is_nothrow_convertible<int, B>::value, ""); // { dg-error "assert" } // { dg-message "'int' is not nothrow convertible from 'B', because" "" { target *-*-* } .-1 } + +struct C { + explicit C(int); // { dg-message "not considered" } +}; +static_assert(is_convertible<int, C>::value, ""); // { dg-error "assert" } +// { dg-message "could not convert 'int' to 'C'" "" { target *-*-* } .-1 } + +struct D { + explicit operator int() const; // { dg-message "not considered" } +}; +static_assert(is_convertible<D, int>::value, ""); // { dg-error "assert" } +// { dg-message "could not convert 'D' to 'int'" "" { target *-*-* } .-1 }
