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 }

Reply via email to