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 <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
Nathaniel Shead
2026-01-11 10:02:45 +11:00
parent dd8df074c9
commit 3e8ce187dc
4 changed files with 53 additions and 16 deletions

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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" }
}

View File

@@ -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 }