@@ -436,6 +436,8 @@ struct conversion_info {
tree from;
/* The type of the parameter. */
tree to_type;
+ /* The location of the argument. */
+ location_t loc;
};
struct rejection_reason {
@@ -627,24 +629,28 @@ arity_rejection (tree first_arg, int expected, int actual)
}
static struct rejection_reason *
-arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to,
+ location_t loc)
{
struct rejection_reason *r = alloc_rejection (rr_arg_conversion);
int adjust = first_arg != NULL_TREE;
r->u.conversion.n_arg = n_arg - adjust;
r->u.conversion.from = from;
r->u.conversion.to_type = to;
+ r->u.conversion.loc = loc;
return r;
}
static struct rejection_reason *
-bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to,
+ location_t loc)
{
struct rejection_reason *r = alloc_rejection (rr_bad_arg_conversion);
int adjust = first_arg != NULL_TREE;
r->u.bad_conversion.n_arg = n_arg - adjust;
r->u.bad_conversion.from = from;
r->u.bad_conversion.to_type = to;
+ r->u.bad_conversion.loc = loc;
return r;
}
@@ -655,6 +661,7 @@ explicit_conversion_rejection (tree from, tree to)
r->u.conversion.n_arg = 0;
r->u.conversion.from = from;
r->u.conversion.to_type = to;
+ r->u.conversion.loc = UNKNOWN_LOCATION;
return r;
}
@@ -665,6 +672,7 @@ template_conversion_rejection (tree from, tree to)
r->u.conversion.n_arg = 0;
r->u.conversion.from = from;
r->u.conversion.to_type = to;
+ r->u.conversion.loc = UNKNOWN_LOCATION;
return r;
}
@@ -2254,14 +2262,17 @@ add_function_candidate (struct z_candidate **candidates,
if (! t)
{
viable = 0;
- reason = arg_conversion_rejection (first_arg, i, argtype, to_type);
+ reason = arg_conversion_rejection (first_arg, i, argtype, to_type,
+ EXPR_LOCATION (arg));
break;
}
if (t->bad_p)
{
viable = -1;
- reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type);
+ reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type,
+ EXPR_LOCATION (arg));
+
}
}
@@ -2350,7 +2361,8 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
if (t->bad_p)
{
viable = -1;
- reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type);
+ reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type,
+ EXPR_LOCATION (arg));
}
if (i == 0)
@@ -2411,13 +2423,14 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
/* We need something for printing the candidate. */
t = build_identity_conv (types[i], NULL_TREE);
reason = arg_conversion_rejection (NULL_TREE, i, argtypes[i],
- types[i]);
+ types[i], EXPR_LOCATION (args[i]));
}
else if (t->bad_p)
{
viable = 0;
reason = bad_arg_conversion_rejection (NULL_TREE, i, args[i],
- types[i]);
+ types[i],
+ EXPR_LOCATION (args[i]));
}
convs[i] = t;
}
@@ -2436,7 +2449,8 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
{
viable = 0;
reason = arg_conversion_rejection (NULL_TREE, 0, argtypes[2],
- boolean_type_node);
+ boolean_type_node,
+ EXPR_LOCATION (args[2]));
}
}
@@ -3927,7 +3941,8 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
{
cand->viable = 0;
cand->reason = arg_conversion_rejection (NULL_TREE, -2,
- rettype, totype);
+ rettype, totype,
+ EXPR_LOCATION (expr));
}
else if (DECL_NONCONVERTING_P (cand->fn)
&& ics->rank > cr_exact)
@@ -3947,7 +3962,8 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
cand->viable = -1;
cand->reason
= bad_arg_conversion_rejection (NULL_TREE, -2,
- rettype, totype);
+ rettype, totype,
+ EXPR_LOCATION (expr));
}
else if (primary_template_specialization_p (cand->fn)
&& ics->rank > cr_exact)
@@ -9157,6 +9173,61 @@ name_as_c_string (tree name, tree type, bool *free_p)
return CONST_CAST (char *, pretty_name);
}
+/* Subroutine of get_location_for_unmatched_call.
+ Return the location of the pertinent argument in INFO, if
+ available.
+ Otherwise, return DEFAULT_LOCATION. */
+
+static location_t
+get_location_for_arg_conversion (conversion_info *info,
+ location_t default_location)
+{
+ if (info->loc == UNKNOWN_LOCATION)
+ return default_location;
+ return info->loc;
+}
+
+/* Get the best location to use when reporting a function call
+ for which there are no valid candidates.
+
+ If there is just one candidate, and it is invalid due to the
+ argument type, use the location of the pertinent argument.
+
+ Otherwise, use DEFAULT_LOCATION. */
+
+static location_t
+get_location_for_unmatched_call (z_candidate *candidates,
+ location_t default_location)
+{
+ if (!candidates)
+ return default_location;
+
+ /* Must be exactly one candidate. */
+ if (candidates->next)
+ return default_location;
+
+ /* Must be an rr_arg_conversion or rr_bad_arg_conversion. */
+ z_candidate *candidate = candidates;
+ rejection_reason *r = candidate->reason;
+
+ if (r == NULL)
+ return default_location;
+
+ switch (r->code)
+ {
+ default:
+ return default_location;
+
+ case rr_arg_conversion:
+ return get_location_for_arg_conversion (&r->u.conversion,
+ default_location);
+
+ case rr_bad_arg_conversion:
+ return get_location_for_arg_conversion (&r->u.bad_conversion,
+ default_location);
+ }
+}
+
/* Build a call to "INSTANCE.FN (ARGS)". If FN_P is non-NULL, it will
be set, upon return, to the function called. ARGS may be NULL.
This may change ARGS. */
@@ -9375,13 +9446,16 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
{
if (complain & tf_error)
{
+ location_t loc = get_location_for_unmatched_call (candidates,
+ input_location);
auto_diagnostic_group d;
if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
cxx_incomplete_type_error (instance, basetype);
else if (optype)
- error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
- basetype, optype, build_tree_list_vec (user_args),
- TREE_TYPE (instance));
+ error_at (loc,
+ "no matching function for call to %<%T::operator %T(%A)%#V%>",
+ basetype, optype, build_tree_list_vec (user_args),
+ TREE_TYPE (instance));
else
{
tree arglist = build_tree_list_vec (user_args);
@@ -9396,9 +9470,10 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
errname = lookup_template_function (errname, explicit_targs);
if (skip_first_for_error)
arglist = TREE_CHAIN (arglist);
- error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
- basetype, &"~"[!twiddle], errname, arglist,
- TREE_TYPE (instance));
+ error_at (loc,
+ "no matching function for call to %<%T::%s%E(%A)%#V%>",
+ basetype, &"~"[!twiddle], errname, arglist,
+ TREE_TYPE (instance));
}
print_z_candidates (location_of (name), candidates);
}
@@ -74,7 +74,7 @@ int test_4 (int first, const char *second, float third)
return s4::member_1 (first, second, third); // { dg-error "no matching function for call to 's4::member_1\\(int&, const char\\*&, float&\\)'" }
/* { dg-begin-multiline-output "" }
return s4::member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "candidate: 'static int s4::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s4_member_1 }
/* { dg-begin-multiline-output "" }
@@ -98,7 +98,7 @@ int test_5 (int first, const char *second, float third)
return inst.member_1 (first, second, third); // { dg-error "no matching function for call to 's5::member_1\\(int&, const char\\*&, float&\\)'" }
/* { dg-begin-multiline-output "" }
return inst.member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "candidate: 'int s5::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s5_member_1 }
/* { dg-begin-multiline-output "" }
@@ -121,7 +121,7 @@ int test_6 (int first, const char *second, float third, s6 *ptr)
return ptr->member_1 (first, second, third); // { dg-error "no matching function for call to 's6::member_1\\(int&, const char\\*&, float&\\)'" }
/* { dg-begin-multiline-output "" }
return ptr->member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "candidate: 'int s6::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s6_member_1 }
/* { dg-begin-multiline-output "" }
@@ -171,7 +171,7 @@ int test_8 (int first, const char *second, float third)
return s8 <const char **>::member_1 (first, second, third); // { dg-error "no matching function for call to 's8<const char\\*\\*>::member_1\\(int&, const char\\*&, float&\\)'" }
/* { dg-begin-multiline-output "" }
return s8 <const char **>::member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "candidate: 'static int s8<T>::member_1\\(int, T, float\\)" "" { target *-*-* } s8_member_1 }
/* { dg-begin-multiline-output "" }
@@ -196,7 +196,7 @@ int test_9 (int first, const char *second, float third)
return inst.member_1 (first, second, third); // { dg-error "no matching function for call to 's9<const char\\*\\*>::member_1\\(int&, const char\\*&, float&\\)'" }
/* { dg-begin-multiline-output "" }
return inst.member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "candidate: 'int s9<T>::member_1\\(int, T, float\\)" "" { target *-*-* } s9_member_1 }
/* { dg-begin-multiline-output "" }
@@ -209,3 +209,30 @@ int test_9 (int first, const char *second, float third)
~~^~~
{ dg-end-multiline-output "" } */
}
+
+/* Overloaded operator (with one candidate). */
+
+struct s10 {};
+
+extern int operator- (const s10&, int); // { dg-line s10_operator }
+
+int test_10 ()
+{
+ s10 v10_a, v10_b;
+
+ return v10_a - v10_b; // { dg-error "no match for" }
+ /* { dg-begin-multiline-output "" }
+ return v10_a - v10_b;
+ ~~~~~~^~~~~~~
+ { dg-end-multiline-output "" } */
+ // { dg-message "candidate" "" { target *-*-* } s10_operator }
+ /* { dg-begin-multiline-output "" }
+ extern int operator- (const s10&, int);
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+ // { dg-message "no known conversion for argument 2 from" "" { target *-*-* } s10_operator }
+ /* { dg-begin-multiline-output "" }
+ extern int operator- (const s10&, int);
+ ^~~
+ { dg-end-multiline-output "" } */
+}