if (pedwarn (loc, 0, "converting to %qT from initializer list "
"would use explicit constructor %qD",
totype, convfn))
- inform (loc, "in C++11 and above a default constructor "
- "can be explicit");
+ {
+ inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here",
+ convfn);
+ inform (loc, "in C++11 and above a default constructor "
+ "can be explicit");
+ }
}
else
- error ("converting to %qT from initializer list would use "
- "explicit constructor %qD", totype, convfn);
+ {
+ auto_diagnostic_group d;
+ error ("converting to %qT from initializer list would use "
+ "explicit constructor %qD", totype, convfn);
+ inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here",
+ convfn);
+ }
}
/* If we're initializing from {}, it's value-initialization. */
return true;
}
+/* We know that can_convert_arg_bad already said "no" when trying to convert
+ FROM to TO with ARG and FLAGS. Try to figure out if it was because
+ an explicit conversion function was skipped when looking for a way to
+ perform the conversion. At this point we've already printed an error. */
+
+void
+maybe_show_nonconverting_candidate (tree to, tree from, tree arg, int flags)
+{
+ if (!(flags & LOOKUP_ONLYCONVERTING))
+ return;
+
+ conversion_obstack_sentinel cos;
+ conversion *c = implicit_conversion (to, from, arg, /*c_cast_p=*/false,
+ flags & ~LOOKUP_ONLYCONVERTING, tf_none);
+ if (c && !c->bad_p && c->user_conv_p)
+ /* Ay, the conversion would have worked in direct-init context. */
+ for (; c; c = next_conversion (c))
+ if (c->kind == ck_user
+ && DECL_P (c->cand->fn)
+ && DECL_NONCONVERTING_P (c->cand->fn))
+ inform (DECL_SOURCE_LOCATION (c->cand->fn), "explicit conversion "
+ "function was not considered");
+}
+
#include "gt-cp-call.h"
extern void cp_warn_deprecated_use_scopes (tree);
extern tree get_function_version_dispatcher (tree);
extern bool any_template_arguments_need_structural_equality_p (tree);
+extern void maybe_show_nonconverting_candidate (tree, tree, tree, int);
/* in class.cc */
extern tree build_vfield_ref (tree, tree);
{
range_label_for_type_mismatch label (rhstype, type);
gcc_rich_location richloc (rhs_loc, has_loc ? &label : NULL);
+ auto_diagnostic_group d;
+
switch (errtype)
{
case ICR_DEFAULT_ARGUMENT:
gcc_unreachable();
}
}
+
+ /* See if we can be more helpful. */
+ maybe_show_nonconverting_candidate (type, rhstype, rhs, flags);
+
if (TYPE_PTR_P (rhstype)
&& TYPE_PTR_P (type)
&& CLASS_TYPE_P (TREE_TYPE (rhstype))
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct A {
+ long int l;
+};
+
+struct S {
+ explicit S(int) { }
+ explicit operator bool() const { return true; } // { dg-message "explicit conversion function was not considered" }
+ explicit operator int() const { return 42; } // { dg-message "explicit conversion function was not considered" }
+ explicit operator char() const { return 42; } // { dg-message "explicit conversion function was not considered" }
+ explicit operator double() const { return 42.; } // { dg-message "explicit conversion function was not considered" }
+ explicit operator float() const { return 42.; } // { dg-message "explicit conversion function was not considered" }
+ explicit operator long() const { return 42.; } // { dg-message "explicit conversion function was not considered" }
+};
+
+double
+f (char)
+{
+ return S{2}; // { dg-error "cannot convert .S. to .double. in return" }
+}
+
+void
+g ()
+{
+ S s = {1}; // { dg-error "would use explicit constructor" }
+ bool b = S{1}; // { dg-error "cannot convert .S. to .bool. in initialization" }
+ int i;
+ i = S{2}; // { dg-error "cannot convert .S. to .int. in assignment" }
+ f (S{3}); // { dg-error "cannot convert .S. to .char." }
+ A a{ S{4} }; // { dg-error "cannot convert .S. to .long int. in initialization" }
+ float arr[1] = { S{5} }; // { dg-error "cannot convert .S. to .float. in initialization" }
+}