* [PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110)
@ 2018-08-23 14:16 David Malcolm
2018-08-23 17:22 ` [PATCH] C++: highlight bad argument in some users of print_z_candidates " David Malcolm
2018-08-29 5:08 ` [PATCH] C++: underline param in print_conversion_rejection " Jason Merrill
0 siblings, 2 replies; 6+ messages in thread
From: David Malcolm @ 2018-08-23 14:16 UTC (permalink / raw)
To: gcc-patches, Jason Merrill; +Cc: David Malcolm
Consider this bogus code (from g++.dg/diagnostic/param-type-mismatch-2.C):
struct s4 { static int member_1 (int one, const char **two, float three); };
int test_4 (int first, const char *second, float third)
{
return s4::member_1 (first, second, third);
}
Before this patch, g++ emits:
demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
5 | return s4::member_1 (first, second, third);
| ^
demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ^~~~~~~~
demo.cc:1:24: note: no known conversion for argument 2 from 'const char*' to 'const char**'
With this patch, it highlights the pertinent parameter in the
"no known conversion" note:
demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
5 | return s4::member_1 (first, second, third);
| ^
demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ^~~~~~~~
demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ~~~~~~~~~~~~~^~~
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu; adds
15 PASS results to g++.sum.
OK for trunk?
I'm working on a followup to highlight the pertinent argument
in the initial error diagnostic.
gcc/cp/ChangeLog:
PR c++/85110
* call.c (print_conversion_rejection): Add "fn" param and use it
for "no known conversion" messages to underline the pertinent
param.
(print_z_candidate): Supply "fn" to the new param above.
gcc/testsuite/ChangeLog:
PR c++/85110
* g++.dg/diagnostic/param-type-mismatch-2.C: Update expected
output to reflect underlining of pertinent parameter in decl
for "no known conversion" messages.
---
gcc/cp/call.c | 17 +++++++++------
.../g++.dg/diagnostic/param-type-mismatch-2.C | 25 +++++++++++++++++-----
2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 626830c..ef445e0 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3432,10 +3432,11 @@ equal_functions (tree fn1, tree fn2)
return fn1 == fn2;
}
-/* Print information about a candidate being rejected due to INFO. */
+/* Print information about a candidate FN being rejected due to INFO. */
static void
-print_conversion_rejection (location_t loc, struct conversion_info *info)
+print_conversion_rejection (location_t loc, struct conversion_info *info,
+ tree fn)
{
tree from = info->from;
if (!TYPE_P (from))
@@ -3466,8 +3467,12 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
inform (loc, " no known conversion from %qH to %qI",
from, info->to_type);
else
- inform (loc, " no known conversion for argument %d from %qH to %qI",
- info->n_arg + 1, from, info->to_type);
+ {
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ loc = get_fndecl_argument_location (fn, info->n_arg);
+ inform (loc, " no known conversion for argument %d from %qH to %qI",
+ info->n_arg + 1, from, info->to_type);
+ }
}
/* Print information about a candidate with WANT parameters and we found
@@ -3542,10 +3547,10 @@ print_z_candidate (location_t loc, const char *msgstr,
r->u.arity.expected);
break;
case rr_arg_conversion:
- print_conversion_rejection (cloc, &r->u.conversion);
+ print_conversion_rejection (cloc, &r->u.conversion, fn);
break;
case rr_bad_arg_conversion:
- print_conversion_rejection (cloc, &r->u.bad_conversion);
+ print_conversion_rejection (cloc, &r->u.bad_conversion, fn);
break;
case rr_explicit_conversion:
inform (cloc, " return type %qT of explicit conversion function "
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index 8cf2dab..4957f61 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -82,7 +82,10 @@ int test_4 (int first, const char *second, float third)
^~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s4_member_1 }
- // TODO: underline the pertinent param
+ /* { dg-begin-multiline-output "" }
+ struct s4 { static int member_1 (int one, const char **two, float three); };
+ ~~~~~~~~~~~~~^~~
+ { dg-end-multiline-output "" } */
}
/* non-static member, with argname. */
@@ -103,7 +106,10 @@ int test_5 (int first, const char *second, float third)
^~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s5_member_1 }
- // TODO: underline the pertinent param
+ /* { dg-begin-multiline-output "" }
+ struct s5 { int member_1 (int one, const char **two, float three); };
+ ~~~~~~~~~~~~~^~~
+ { dg-end-multiline-output "" } */
}
/* non-static member, with argname, via a ptr. */
@@ -123,7 +129,10 @@ int test_6 (int first, const char *second, float third, s6 *ptr)
^~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s6_member_1 }
- // TODO: underline the pertinent param
+ /* { dg-begin-multiline-output "" }
+ struct s6 { int member_1 (int one, const char **two, float three); };
+ ~~~~~~~~~~~~~^~~
+ { dg-end-multiline-output "" } */
}
/* Template function. */
@@ -170,7 +179,10 @@ int test_8 (int first, const char *second, float third)
^~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s8_member_1 }
- // TODO: underline the pertinent param
+ /* { dg-begin-multiline-output "" }
+ struct s8 { static int member_1 (int one, T two, float three); };
+ ~~^~~
+ { dg-end-multiline-output "" } */
}
/* Template class, non-static function. */
@@ -192,5 +204,8 @@ int test_9 (int first, const char *second, float third)
^~~~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s9_member_1 }
- // TODO: underline the pertinent param
+ /* { dg-begin-multiline-output "" }
+ struct s9 { int member_1 (int one, T two, float three); };
+ ~~^~~
+ { dg-end-multiline-output "" } */
}
--
1.8.5.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] C++: highlight bad argument in some users of print_z_candidates (more PR c++/85110)
2018-08-23 14:16 [PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110) David Malcolm
@ 2018-08-23 17:22 ` David Malcolm
2018-08-30 22:19 ` Jason Merrill
2018-08-29 5:08 ` [PATCH] C++: underline param in print_conversion_rejection " Jason Merrill
1 sibling, 1 reply; 6+ messages in thread
From: David Malcolm @ 2018-08-23 17:22 UTC (permalink / raw)
To: gcc-patches, Jason Merrill; +Cc: David Malcolm
This is a followup to:
"[PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110)"
https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01480.html
to highlight the pertinent argument in a unmatched function call
for which there is one candidate.
It updates the output from:
demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
5 | return s4::member_1 (first, second, third);
| ^
demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ^~~~~~~~
demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ~~~~~~~~~~~~~^~~
to:
demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:31: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
5 | return s4::member_1 (first, second, third);
| ^~~~~~
demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ^~~~~~~~
demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ~~~~~~~~~~~~~^~~
updating the location of the "error" to use that of the argument with
the mismatching type.
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu; adds a
further 33 PASS results to g++.sum.
OK for trunk?
gcc/cp/ChangeLog:
PR c++/85110
* call.c (struct conversion_info): Add "loc" field.
(arg_conversion_rejection): Add "loc" param, using it to
initialize the new field.
(bad_arg_conversion_rejection): Likewise.
(explicit_conversion_rejection): Initialize the new field to
UNKNOWN_LOCATION.
(template_conversion_rejection): Likewise.
(add_function_candidate): Pass on the argument location to the new
param of arg_conversion_rejection.
(add_conv_candidate): Likewise.
(build_builtin_candidate): Likewise.
(build_user_type_conversion_1): Likewise.
(get_location_for_arg_conversion): New function.
(get_location_for_unmatched_call): New function.
(build_new_method_call_1): Call get_location_for_unmatched_call
when reporting on unmatched functions, and use it for the error's
location.
gcc/testsuite/ChangeLog:
PR c++/85110
* g++.dg/diagnostic/param-type-mismatch-2.C: Update expected
results to underline the pertinent argument in the initial
error for unmatched calls in which there is a single candidate.
Add test coverage for an unmatched overloaded operator.
---
gcc/cp/call.c | 107 ++++++++++++++++++---
.../g++.dg/diagnostic/param-type-mismatch-2.C | 37 ++++++-
2 files changed, 123 insertions(+), 21 deletions(-)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ef445e0..3bc42f5 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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);
}
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index 4957f61..8fb167a 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -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 "" } */
+}
--
1.8.5.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110)
2018-08-23 14:16 [PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110) David Malcolm
2018-08-23 17:22 ` [PATCH] C++: highlight bad argument in some users of print_z_candidates " David Malcolm
@ 2018-08-29 5:08 ` Jason Merrill
1 sibling, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2018-08-29 5:08 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
OK.
On Thu, Aug 23, 2018 at 11:01 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> Consider this bogus code (from g++.dg/diagnostic/param-type-mismatch-2.C):
>
> struct s4 { static int member_1 (int one, const char **two, float three); };
>
> int test_4 (int first, const char *second, float third)
> {
> return s4::member_1 (first, second, third);
> }
>
> Before this patch, g++ emits:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
> 5 | return s4::member_1 (first, second, third);
> | ^
> demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ^~~~~~~~
> demo.cc:1:24: note: no known conversion for argument 2 from 'const char*' to 'const char**'
>
> With this patch, it highlights the pertinent parameter in the
> "no known conversion" note:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
> 5 | return s4::member_1 (first, second, third);
> | ^
> demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ^~~~~~~~
> demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ~~~~~~~~~~~~~^~~
>
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu; adds
> 15 PASS results to g++.sum.
>
> OK for trunk?
>
> I'm working on a followup to highlight the pertinent argument
> in the initial error diagnostic.
>
> gcc/cp/ChangeLog:
> PR c++/85110
> * call.c (print_conversion_rejection): Add "fn" param and use it
> for "no known conversion" messages to underline the pertinent
> param.
> (print_z_candidate): Supply "fn" to the new param above.
>
> gcc/testsuite/ChangeLog:
> PR c++/85110
> * g++.dg/diagnostic/param-type-mismatch-2.C: Update expected
> output to reflect underlining of pertinent parameter in decl
> for "no known conversion" messages.
> ---
> gcc/cp/call.c | 17 +++++++++------
> .../g++.dg/diagnostic/param-type-mismatch-2.C | 25 +++++++++++++++++-----
> 2 files changed, 31 insertions(+), 11 deletions(-)
>
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 626830c..ef445e0 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -3432,10 +3432,11 @@ equal_functions (tree fn1, tree fn2)
> return fn1 == fn2;
> }
>
> -/* Print information about a candidate being rejected due to INFO. */
> +/* Print information about a candidate FN being rejected due to INFO. */
>
> static void
> -print_conversion_rejection (location_t loc, struct conversion_info *info)
> +print_conversion_rejection (location_t loc, struct conversion_info *info,
> + tree fn)
> {
> tree from = info->from;
> if (!TYPE_P (from))
> @@ -3466,8 +3467,12 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
> inform (loc, " no known conversion from %qH to %qI",
> from, info->to_type);
> else
> - inform (loc, " no known conversion for argument %d from %qH to %qI",
> - info->n_arg + 1, from, info->to_type);
> + {
> + if (TREE_CODE (fn) == FUNCTION_DECL)
> + loc = get_fndecl_argument_location (fn, info->n_arg);
> + inform (loc, " no known conversion for argument %d from %qH to %qI",
> + info->n_arg + 1, from, info->to_type);
> + }
> }
>
> /* Print information about a candidate with WANT parameters and we found
> @@ -3542,10 +3547,10 @@ print_z_candidate (location_t loc, const char *msgstr,
> r->u.arity.expected);
> break;
> case rr_arg_conversion:
> - print_conversion_rejection (cloc, &r->u.conversion);
> + print_conversion_rejection (cloc, &r->u.conversion, fn);
> break;
> case rr_bad_arg_conversion:
> - print_conversion_rejection (cloc, &r->u.bad_conversion);
> + print_conversion_rejection (cloc, &r->u.bad_conversion, fn);
> break;
> case rr_explicit_conversion:
> inform (cloc, " return type %qT of explicit conversion function "
> diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> index 8cf2dab..4957f61 100644
> --- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> +++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> @@ -82,7 +82,10 @@ int test_4 (int first, const char *second, float third)
> ^~~~~~~~
> { dg-end-multiline-output "" } */
> // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s4_member_1 }
> - // TODO: underline the pertinent param
> + /* { dg-begin-multiline-output "" }
> + struct s4 { static int member_1 (int one, const char **two, float three); };
> + ~~~~~~~~~~~~~^~~
> + { dg-end-multiline-output "" } */
> }
>
> /* non-static member, with argname. */
> @@ -103,7 +106,10 @@ int test_5 (int first, const char *second, float third)
> ^~~~~~~~
> { dg-end-multiline-output "" } */
> // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s5_member_1 }
> - // TODO: underline the pertinent param
> + /* { dg-begin-multiline-output "" }
> + struct s5 { int member_1 (int one, const char **two, float three); };
> + ~~~~~~~~~~~~~^~~
> + { dg-end-multiline-output "" } */
> }
>
> /* non-static member, with argname, via a ptr. */
> @@ -123,7 +129,10 @@ int test_6 (int first, const char *second, float third, s6 *ptr)
> ^~~~~~~~
> { dg-end-multiline-output "" } */
> // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s6_member_1 }
> - // TODO: underline the pertinent param
> + /* { dg-begin-multiline-output "" }
> + struct s6 { int member_1 (int one, const char **two, float three); };
> + ~~~~~~~~~~~~~^~~
> + { dg-end-multiline-output "" } */
> }
>
> /* Template function. */
> @@ -170,7 +179,10 @@ int test_8 (int first, const char *second, float third)
> ^~~~~~~~
> { dg-end-multiline-output "" } */
> // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s8_member_1 }
> - // TODO: underline the pertinent param
> + /* { dg-begin-multiline-output "" }
> + struct s8 { static int member_1 (int one, T two, float three); };
> + ~~^~~
> + { dg-end-multiline-output "" } */
> }
>
> /* Template class, non-static function. */
> @@ -192,5 +204,8 @@ int test_9 (int first, const char *second, float third)
> ^~~~~~~~
> { dg-end-multiline-output "" } */
> // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s9_member_1 }
> - // TODO: underline the pertinent param
> + /* { dg-begin-multiline-output "" }
> + struct s9 { int member_1 (int one, T two, float three); };
> + ~~^~~
> + { dg-end-multiline-output "" } */
> }
> --
> 1.8.5.3
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] C++: highlight bad argument in some users of print_z_candidates (more PR c++/85110)
2018-08-23 17:22 ` [PATCH] C++: highlight bad argument in some users of print_z_candidates " David Malcolm
@ 2018-08-30 22:19 ` Jason Merrill
2018-09-05 14:22 ` [PATCH] C++: special-case single non-viable candidate " David Malcolm
0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2018-08-30 22:19 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On Thu, Aug 23, 2018 at 2:08 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> This is a followup to:
>
> "[PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110)"
> https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01480.html
>
> to highlight the pertinent argument in a unmatched function call
> for which there is one candidate.
>
> It updates the output from:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
> 5 | return s4::member_1 (first, second, third);
> | ^
> demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ^~~~~~~~
> demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ~~~~~~~~~~~~~^~~
>
> to:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:31: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
> 5 | return s4::member_1 (first, second, third);
> | ^~~~~~
Hmm, it seems pretty subtle to just change the highlighting when the
message talks about the call as a whole. I think if we're going to
focus in this way we might change the diagnostic to something like
error: no known conversion for argument 2 from 'const char*' to 'const char**'
note: in call to 'static int s4::member_1(int, const char**, float)'
or whatever the messages are from
convert_arguments/convert_for_initialization which already deal with
the single-candidate case for non-member functions.
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] C++: special-case single non-viable candidate (more PR c++/85110)
2018-08-30 22:19 ` Jason Merrill
@ 2018-09-05 14:22 ` David Malcolm
2018-09-06 0:19 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: David Malcolm @ 2018-09-05 14:22 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches List, David Malcolm
On Thu, 2018-08-30 at 18:18 -0400, Jason Merrill wrote:
> On Thu, Aug 23, 2018 at 2:08 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > This is a followup to:
> >
> > "[PATCH] C++: underline param in print_conversion_rejection (more
> > PR c++/85110)"
> > https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01480.html
> >
> > to highlight the pertinent argument in a unmatched function call
> > for which there is one candidate.
> >
> > It updates the output from:
> >
> > demo.cc: In function 'int test_4(int, const char*, float)':
> > demo.cc:5:44: error: no matching function for call to
> > 's4::member_1(int&, const char*&, float&)'
> > 5 | return s4::member_1 (first, second, third);
> > | ^
> > demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const
> > char**, float)'
> > 1 | struct s4 { static int member_1 (int one, const char **two,
> > float three); };
> > | ^~~~~~~~
> > demo.cc:1:56: note: no known conversion for argument 2 from
> > 'const char*' to 'const char**'
> > 1 | struct s4 { static int member_1 (int one, const char **two,
> > float three); };
> > | ~~~~~~~~~~~~~^~~
> >
> > to:
> >
> > demo.cc: In function 'int test_4(int, const char*, float)':
> > demo.cc:5:31: error: no matching function for call to
> > 's4::member_1(int&, const char*&, float&)'
> > 5 | return s4::member_1 (first, second, third);
> > | ^~~~~~
>
> Hmm, it seems pretty subtle to just change the highlighting when the
> message talks about the call as a whole. I think if we're going to
> focus in this way we might change the diagnostic to something like
>
> error: no known conversion for argument 2 from 'const char*' to
> 'const char**'
> note: in call to 'static int s4::member_1(int, const char**, float)'
>
> or whatever the messages are from
> convert_arguments/convert_for_initialization which already deal with
> the single-candidate case for non-member functions.
>
> Jason
Thanks.
Here's an updated version of the patch.
I broke out the "no viable candidates" case in build_new_method_call_1
into a subroutine, and added special-case handling for when there's
a single non-viable candidate where there's an argument conversion
error. I turned the error-handling from convert_for_assignment into
a subroutine, calling it from this new special-case.
This converts:
demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
5 | return s4::member_1 (first, second, third);
| ^
demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ^~~~~~~~
demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ~~~~~~~~~~~~~^~~
to:
demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:31: error: cannot convert 'const char*' to 'const char**'
5 | return s4::member_1 (first, second, third);
| ^~~~~~
| |
| const char*
demo.cc:1:56: note: initializing argument 2 of 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
| ~~~~~~~~~~~~~^~~
thus highlighting the problematic argument at the callsite (and its type).
BTW, updating the test cases shows that some of our messages are worded:
"could not convert"
and sometimes:
"cannot convert"
(see e.g. g++.old-deja/g++.jason/conversion11.C which would now
have two of them side-by-side). I'm not sure that this is a problem
(maybe save for a followup? If it is an issue, it's presumably a
pre-existing one)
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
OK for trunk?
gcc/cp/ChangeLog:
PR c++/85110
* call.c (struct conversion_info): Add "loc" field.
(arg_conversion_rejection): Add "loc" param, using it to
initialize the new field.
(bad_arg_conversion_rejection): Likewise.
(explicit_conversion_rejection): Initialize the new field to
UNKNOWN_LOCATION.
(template_conversion_rejection): Likewise.
(add_function_candidate): Pass on the argument location to the new
param of arg_conversion_rejection.
(add_conv_candidate): Likewise.
(build_builtin_candidate): Likewise.
(build_user_type_conversion_1): Likewise.
(single_z_candidate): New function.
(maybe_get_bad_conversion_for_unmatched_call): New function.
(complain_about_bad_argument): New function, based on part of
convert_for_assignment.
(build_new_method_call_1): Split out handling of the "no viable
candidates" case into...
(complain_about_no_candidates_for_method_call): ...this new
function, and use the new functions above to special-case the
handling of a single non-viable candidate due to a bad argument.
* cp-tree.h (complain_about_bad_argument): New decl.
* typeck.c (convert_for_assignment): Split out one error-handling
case into complain_about_bad_argument.
gcc/testsuite/ChangeLog:
PR c++/85110
* g++.dg/cpp0x/explicit4.C: Update expected output to reflect
special-casing of diagnostic for a single non-viable candidate due
to a bad argument.
* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
Add test coverage for an unmatched overloaded operator.
* g++.dg/expr/pmf-1.C: Likewise.
* g++.old-deja/g++.bugs/900330_02.C: Likewise.
* g++.old-deja/g++.jason/conversion11.C: Likewise.
* g++.old-deja/g++.law/arg11.C: Likewise.
* g++.old-deja/g++.law/arm9.C: Likewise.
* g++.old-deja/g++.robertl/eb131.C: Likewise.
---
gcc/cp/call.c | 192 +++++++++++++++++----
gcc/cp/cp-tree.h | 3 +
gcc/cp/typeck.c | 20 +--
gcc/testsuite/g++.dg/cpp0x/explicit4.C | 2 +-
.../g++.dg/diagnostic/param-type-mismatch-2.C | 90 +++++-----
gcc/testsuite/g++.dg/expr/pmf-1.C | 2 +-
gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C | 2 +-
.../g++.old-deja/g++.jason/conversion11.C | 4 +-
gcc/testsuite/g++.old-deja/g++.law/arg11.C | 2 +-
gcc/testsuite/g++.old-deja/g++.law/arm9.C | 2 +-
gcc/testsuite/g++.old-deja/g++.robertl/eb131.C | 4 +-
11 files changed, 220 insertions(+), 103 deletions(-)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a156702..ab14715 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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)
@@ -9156,6 +9172,129 @@ name_as_c_string (tree name, tree type, bool *free_p)
return CONST_CAST (char *, pretty_name);
}
+/* If CANDIDATES contains exactly one candidate, return it, otherwise
+ return NULL. */
+
+static z_candidate *
+single_z_candidate (z_candidate *candidates)
+{
+ if (candidates == NULL)
+ return NULL;
+
+ if (candidates->next)
+ return NULL;
+
+ return candidates;
+}
+
+/* If CANDIDATE is invalid due to a bad argument type, return the
+ pertinent conversion_info.
+
+ Otherwise, return NULL. */
+
+static const conversion_info *
+maybe_get_bad_conversion_for_unmatched_call (const z_candidate *candidate)
+{
+ /* Must be an rr_arg_conversion or rr_bad_arg_conversion. */
+ rejection_reason *r = candidate->reason;
+
+ if (r == NULL)
+ return NULL;
+
+ switch (r->code)
+ {
+ default:
+ return NULL;
+
+ case rr_arg_conversion:
+ return &r->u.conversion;
+
+ case rr_bad_arg_conversion:
+ return &r->u.bad_conversion;
+ }
+}
+
+/* Issue an error and note complaining about a bad argument type at a
+ callsite with a single candidate FNDECL.
+
+ ARG_LOC is the location of the argument (or UNKNOWN_LOCATION, in which
+ case input_location is used).
+ FROM_TYPE is the type of the actual argument; TO_TYPE is the type of
+ the formal parameter. */
+
+void
+complain_about_bad_argument (location_t arg_loc,
+ tree from_type, tree to_type,
+ tree fndecl, int parmnum)
+{
+ auto_diagnostic_group d;
+ range_label_for_type_mismatch rhs_label (from_type, to_type);
+ range_label *label = &rhs_label;
+ if (arg_loc == UNKNOWN_LOCATION)
+ {
+ arg_loc = input_location;
+ label = NULL;
+ }
+ gcc_rich_location richloc (arg_loc, label);
+ error_at (&richloc,
+ "cannot convert %qH to %qI",
+ from_type, to_type);
+ inform (get_fndecl_argument_location (fndecl, parmnum),
+ " initializing argument %P of %qD", parmnum, fndecl);
+}
+
+/* Subroutine of build_new_method_call_1, for where there are no viable
+ candidates for the call. */
+
+static void
+complain_about_no_candidates_for_method_call (tree instance,
+ z_candidate *candidates,
+ tree explicit_targs,
+ tree basetype,
+ tree optype, tree name,
+ bool skip_first_for_error,
+ vec<tree, va_gc> *user_args)
+{
+ 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));
+ else
+ {
+ /* Special-case for when there's a single candidate that's failing
+ due to a bad argument type. */
+ if (z_candidate *candidate = single_z_candidate (candidates))
+ if (const conversion_info *conv
+ = maybe_get_bad_conversion_for_unmatched_call (candidate))
+ {
+ complain_about_bad_argument (conv->loc,
+ conv->from, conv->to_type,
+ candidate->fn, conv->n_arg);
+ return;
+ }
+
+ tree arglist = build_tree_list_vec (user_args);
+ tree errname = name;
+ bool twiddle = false;
+ if (IDENTIFIER_CDTOR_P (errname))
+ {
+ twiddle = IDENTIFIER_DTOR_P (errname);
+ errname = constructor_name (basetype);
+ }
+ if (explicit_targs)
+ 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));
+ }
+ print_z_candidates (location_of (name), candidates);
+}
+
/* 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. */
@@ -9373,34 +9512,11 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
if (!any_viable_p)
{
if (complain & tf_error)
- {
- 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));
- else
- {
- tree arglist = build_tree_list_vec (user_args);
- tree errname = name;
- bool twiddle = false;
- if (IDENTIFIER_CDTOR_P (errname))
- {
- twiddle = IDENTIFIER_DTOR_P (errname);
- errname = constructor_name (basetype);
- }
- if (explicit_targs)
- 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));
- }
- print_z_candidates (location_of (name), candidates);
- }
+ complain_about_no_candidates_for_method_call (instance, candidates,
+ explicit_targs, basetype,
+ optype, name,
+ skip_first_for_error,
+ user_args);
call = error_mark_node;
}
else
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 43e452c..f612e97 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6087,6 +6087,9 @@ extern bool can_convert_arg_bad (tree, tree, tree, int,
extern int conv_flags (int, int, tree, tree, int);
extern struct conversion * good_conversion (tree, tree, tree, int, tsubst_flags_t);
extern location_t get_fndecl_argument_location (tree, int);
+extern void complain_about_bad_argument (location_t arg_loc,
+ tree from_type, tree to_type,
+ tree fndecl, int parmnum);
/* A class for recording information about access failures (e.g. private
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ab088a9..9cb2271 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8818,23 +8818,9 @@ convert_for_assignment (tree type, tree rhs,
parmnum, complain, flags);
}
else if (fndecl)
- {
- auto_diagnostic_group d;
- location_t loc = cp_expr_location (rhs);
- range_label_for_type_mismatch rhs_label (rhstype, type);
- range_label *label = &rhs_label;
- if (loc == UNKNOWN_LOCATION)
- {
- loc = input_location;
- label = NULL;
- }
- gcc_rich_location richloc (loc, label);
- error_at (&richloc,
- "cannot convert %qH to %qI",
- rhstype, type);
- inform (get_fndecl_argument_location (fndecl, parmnum),
- " initializing argument %P of %qD", parmnum, fndecl);
- }
+ complain_about_bad_argument (cp_expr_location (rhs),
+ rhstype, type,
+ fndecl, parmnum);
else
switch (errtype)
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit4.C b/gcc/testsuite/g++.dg/cpp0x/explicit4.C
index 346a6e2..065a473 100644
--- a/gcc/testsuite/g++.dg/cpp0x/explicit4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit4.C
@@ -13,5 +13,5 @@ int main()
{
B b;
(A(b)); // OK
- (A(b,1)); // { dg-error "no match" }
+ (A(b,1)); // { dg-error "cannot convert" }
}
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index 4957f61..f74f8d3 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -71,17 +71,14 @@ struct s4 { static int member_1 (int one, const char **two, float three); }; //
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&\\)'" }
+ return s4::member_1 (first, second, third); // { dg-error "31: cannot convert 'const char\\*' to 'const char\\*\\*'" }
/* { dg-begin-multiline-output "" }
return s4::member_1 (first, second, third);
- ^
+ ^~~~~~
+ |
+ const char*
{ dg-end-multiline-output "" } */
- // { dg-message "candidate: 'static int s4::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s4_member_1 }
- /* { dg-begin-multiline-output "" }
- struct s4 { static int member_1 (int one, const char **two, float three); };
- ^~~~~~~~
- { dg-end-multiline-output "" } */
- // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s4_member_1 }
+ // { dg-message "initializing argument 2 of 'static int s4::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s4_member_1 }
/* { dg-begin-multiline-output "" }
struct s4 { static int member_1 (int one, const char **two, float three); };
~~~~~~~~~~~~~^~~
@@ -95,19 +92,16 @@ struct s5 { int member_1 (int one, const char **two, float three); }; // { dg-li
int test_5 (int first, const char *second, float third)
{
s5 inst;
- return inst.member_1 (first, second, third); // { dg-error "no matching function for call to 's5::member_1\\(int&, const char\\*&, float&\\)'" }
+ return inst.member_1 (first, second, third); // { dg-error "32: cannot convert 'const char\\*' to 'const char\\*\\*'" }
/* { dg-begin-multiline-output "" }
return inst.member_1 (first, second, third);
- ^
+ ^~~~~~
+ |
+ const char*
{ dg-end-multiline-output "" } */
- // { dg-message "candidate: 'int s5::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s5_member_1 }
+ // { dg-message "initializing argument 2 of 'int s5::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s5_member_1 }
/* { dg-begin-multiline-output "" }
struct s5 { int member_1 (int one, const char **two, float three); };
- ^~~~~~~~
- { dg-end-multiline-output "" } */
- // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s5_member_1 }
- /* { dg-begin-multiline-output "" }
- struct s5 { int member_1 (int one, const char **two, float three); };
~~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -118,17 +112,14 @@ struct s6 { int member_1 (int one, const char **two, float three); }; // { dg-li
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&\\)'" }
+ return ptr->member_1 (first, second, third); // { dg-error "32: cannot convert 'const char\\*' to 'const char\\*\\*'" }
/* { dg-begin-multiline-output "" }
return ptr->member_1 (first, second, third);
- ^
+ ^~~~~~
+ |
+ const char*
{ dg-end-multiline-output "" } */
- // { dg-message "candidate: 'int s6::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s6_member_1 }
- /* { dg-begin-multiline-output "" }
- struct s6 { int member_1 (int one, const char **two, float three); };
- ^~~~~~~~
- { dg-end-multiline-output "" } */
- // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s6_member_1 }
+ // { dg-message "initializing argument 2 of 'int s6::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s6_member_1 }
/* { dg-begin-multiline-output "" }
struct s6 { int member_1 (int one, const char **two, float three); };
~~~~~~~~~~~~~^~~
@@ -168,17 +159,14 @@ struct s8 { static int member_1 (int one, T two, float three); }; // { dg-line s
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&\\)'" }
+ return s8 <const char **>::member_1 (first, second, third); // { dg-error "47: cannot convert 'const char\\*' to 'const char\\*\\*'" }
/* { 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 "" }
- struct s8 { static int member_1 (int one, T two, float three); };
- ^~~~~~~~
+ ^~~~~~
+ |
+ const char*
{ dg-end-multiline-output "" } */
- // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s8_member_1 }
+ // { dg-message "initializing argument 2 of 'static int s8<T>::member_1\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } s8_member_1 }
/* { dg-begin-multiline-output "" }
struct s8 { static int member_1 (int one, T two, float three); };
~~^~~
@@ -193,19 +181,43 @@ struct s9 { int member_1 (int one, T two, float three); }; // { dg-line s9_membe
int test_9 (int first, const char *second, float third)
{
s9 <const char **> inst;
- return inst.member_1 (first, second, third); // { dg-error "no matching function for call to 's9<const char\\*\\*>::member_1\\(int&, const char\\*&, float&\\)'" }
+ return inst.member_1 (first, second, third); // { dg-error "32: cannot convert 'const char\\*' to 'const char\\*\\*'" }
/* { dg-begin-multiline-output "" }
return inst.member_1 (first, second, third);
- ^
+ ^~~~~~
+ |
+ const char*
{ dg-end-multiline-output "" } */
- // { dg-message "candidate: 'int s9<T>::member_1\\(int, T, float\\)" "" { target *-*-* } s9_member_1 }
+ // { dg-message "initializing argument 2 of 'int s9<T>::member_1\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } s9_member_1 }
/* { dg-begin-multiline-output "" }
struct s9 { int member_1 (int one, T two, float three); };
- ^~~~~~~~
+ ~~^~~
{ dg-end-multiline-output "" } */
- // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s9_member_1 }
+}
+
+/* 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 "" }
- struct s9 { int member_1 (int one, T two, float three); };
- ~~^~~
+ 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 "" } */
}
diff --git a/gcc/testsuite/g++.dg/expr/pmf-1.C b/gcc/testsuite/g++.dg/expr/pmf-1.C
index e6b7219..35ebe52 100644
--- a/gcc/testsuite/g++.dg/expr/pmf-1.C
+++ b/gcc/testsuite/g++.dg/expr/pmf-1.C
@@ -14,6 +14,6 @@ struct A
{
void (A::*p)() = &A::f;
void (A::*q)() = &(A::f); // { dg-error "parenthesized" }
- foo(&g<int>); // { dg-error "no matching" }
+ foo(&g<int>); // { dg-error "cannot convert" }
}
};
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C
index 588251d..f1591b2 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C
@@ -24,7 +24,7 @@ struct D : public B {
void h(D* pd)
{
- pd->f(1); // { dg-error "no matching" } D::f(struct B) hides B::f(int)
+ pd->f(1); // { dg-error "cannot convert" } D::f(struct B) hides B::f(int)
}
int main () { return 0; }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C b/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C
index a7c0fbe..ccbd1f5 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C
@@ -22,6 +22,6 @@ void DoSomething(Ding A);
void foo(Something* pX)
{
DoSomething(1); // { dg-error "could not convert" }
- pX->DoSomething(1); // { dg-error "no matching" }
- (*pX).DoSomething(1); // { dg-error "no matching" }
+ pX->DoSomething(1); // { dg-error "cannot convert" }
+ (*pX).DoSomething(1); // { dg-error "cannot convert" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.law/arg11.C b/gcc/testsuite/g++.old-deja/g++.law/arg11.C
index bd88844..d68f184 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/arg11.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/arg11.C
@@ -17,6 +17,6 @@ int
foo(S *o)
{ // Neither call has a usable constructor for conversions of char[5] to Ack.
function("adsf");// { dg-error "could not convert" }
- o->method("adsf");// { dg-error "no matching" }
+ o->method("adsf");// { dg-error "cannot convert" }
return 0;
}
diff --git a/gcc/testsuite/g++.old-deja/g++.law/arm9.C b/gcc/testsuite/g++.old-deja/g++.law/arm9.C
index c603aab..ab18189 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/arm9.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/arm9.C
@@ -23,7 +23,7 @@ void B::set (f2 f) { std::cout << "called B\n|no known conversion";} // { dg-mes
int main() {
B b;
- b.set(F1); // ARM page 309: should call A.set(f1) and that what g++ does,// { dg-error "match" }
+ b.set(F1); // ARM page 309: should call A.set(f1) and that what g++ does,// { dg-error "cannot convert" }
// but 13.1 of ARM clearly states that it should call B::set()
// or generate an error because overloading works only for
// functions within the same scope (first page of chapter 13)
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C
index 6a0f1c3..c2377fb 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C
@@ -15,6 +15,6 @@ struct a {
a::a()
{
- foo( &junk ); // { dg-error "match" } junk is an unqualified-id.
- foo( &bar ); // { dg-error "match" } bar is an unqualified-id.
+ foo( &junk ); // { dg-error "cannot convert" } junk is an unqualified-id.
+ foo( &bar ); // { dg-error "cannot convert" } bar is an unqualified-id.
}
--
1.8.5.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] C++: special-case single non-viable candidate (more PR c++/85110)
2018-09-05 14:22 ` [PATCH] C++: special-case single non-viable candidate " David Malcolm
@ 2018-09-06 0:19 ` Jason Merrill
0 siblings, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2018-09-06 0:19 UTC (permalink / raw)
To: David Malcolm; +Cc: gcc-patches List
On Wed, Sep 5, 2018 at 11:08 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Thu, 2018-08-30 at 18:18 -0400, Jason Merrill wrote:
>> On Thu, Aug 23, 2018 at 2:08 PM, David Malcolm <dmalcolm@redhat.com>
>> wrote:
>> > This is a followup to:
>> >
>> > "[PATCH] C++: underline param in print_conversion_rejection (more
>> > PR c++/85110)"
>> > https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01480.html
>> >
>> > to highlight the pertinent argument in a unmatched function call
>> > for which there is one candidate.
>> >
>> > It updates the output from:
>> >
>> > demo.cc: In function 'int test_4(int, const char*, float)':
>> > demo.cc:5:44: error: no matching function for call to
>> > 's4::member_1(int&, const char*&, float&)'
>> > 5 | return s4::member_1 (first, second, third);
>> > | ^
>> > demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const
>> > char**, float)'
>> > 1 | struct s4 { static int member_1 (int one, const char **two,
>> > float three); };
>> > | ^~~~~~~~
>> > demo.cc:1:56: note: no known conversion for argument 2 from
>> > 'const char*' to 'const char**'
>> > 1 | struct s4 { static int member_1 (int one, const char **two,
>> > float three); };
>> > | ~~~~~~~~~~~~~^~~
>> >
>> > to:
>> >
>> > demo.cc: In function 'int test_4(int, const char*, float)':
>> > demo.cc:5:31: error: no matching function for call to
>> > 's4::member_1(int&, const char*&, float&)'
>> > 5 | return s4::member_1 (first, second, third);
>> > | ^~~~~~
>>
>> Hmm, it seems pretty subtle to just change the highlighting when the
>> message talks about the call as a whole. I think if we're going to
>> focus in this way we might change the diagnostic to something like
>>
>> error: no known conversion for argument 2 from 'const char*' to
>> 'const char**'
>> note: in call to 'static int s4::member_1(int, const char**, float)'
>>
>> or whatever the messages are from
>> convert_arguments/convert_for_initialization which already deal with
>> the single-candidate case for non-member functions.
>>
>> Jason
>
> Thanks.
>
> Here's an updated version of the patch.
>
> I broke out the "no viable candidates" case in build_new_method_call_1
> into a subroutine, and added special-case handling for when there's
> a single non-viable candidate where there's an argument conversion
> error. I turned the error-handling from convert_for_assignment into
> a subroutine, calling it from this new special-case.
>
> This converts:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
> 5 | return s4::member_1 (first, second, third);
> | ^
> demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ^~~~~~~~
> demo.cc:1:56: note: no known conversion for argument 2 from 'const char*' to 'const char**'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ~~~~~~~~~~~~~^~~
>
> to:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:31: error: cannot convert 'const char*' to 'const char**'
> 5 | return s4::member_1 (first, second, third);
> | ^~~~~~
> | |
> | const char*
> demo.cc:1:56: note: initializing argument 2 of 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
> | ~~~~~~~~~~~~~^~~
>
> thus highlighting the problematic argument at the callsite (and its type).
OK, thanks.
> BTW, updating the test cases shows that some of our messages are worded:
> "could not convert"
> and sometimes:
> "cannot convert"
> (see e.g. g++.old-deja/g++.jason/conversion11.C which would now
> have two of them side-by-side). I'm not sure that this is a problem
> (maybe save for a followup? If it is an issue, it's presumably a
> pre-existing one)
Indeed, a pre-existing issue. I assume that we want to unify on
present tense; does that sound right to you?
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2018-09-06 0:19 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-23 14:16 [PATCH] C++: underline param in print_conversion_rejection (more PR c++/85110) David Malcolm
2018-08-23 17:22 ` [PATCH] C++: highlight bad argument in some users of print_z_candidates " David Malcolm
2018-08-30 22:19 ` Jason Merrill
2018-09-05 14:22 ` [PATCH] C++: special-case single non-viable candidate " David Malcolm
2018-09-06 0:19 ` Jason Merrill
2018-08-29 5:08 ` [PATCH] C++: underline param in print_conversion_rejection " Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).