aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2018-09-12 18:50:08 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2018-09-12 18:50:08 +0000
commit4911b24d71955b757fdaac29b878ae33c32f3e0b (patch)
tree4e4772fd56335a5477fd9d79405d21633523558c /gcc/cp
parent3b582f1f3b7e19f050a219117e0d1af0e9a76af4 (diff)
downloadgcc-4911b24d71955b757fdaac29b878ae33c32f3e0b.zip
gcc-4911b24d71955b757fdaac29b878ae33c32f3e0b.tar.gz
gcc-4911b24d71955b757fdaac29b878ae33c32f3e0b.tar.bz2
C++: special-case single non-viable candidate (more PR c++/85110)
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). 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. From-SVN: r264250
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog28
-rw-r--r--gcc/cp/call.c192
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/typeck.c20
4 files changed, 188 insertions, 55 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e4d635d..9201d67 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,31 @@
+2018-09-12 David Malcolm <dmalcolm@redhat.com>
+
+ 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.
+
2018-09-09 Cesar Philippidis <cesar@codesourcery.com>
Julian Brown <julian@codesourcery.com>
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 03b4c5a..69503ca 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;
}
@@ -2257,14 +2265,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));
+
}
}
@@ -2353,7 +2364,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)
@@ -2414,13 +2426,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;
}
@@ -2439,7 +2452,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]));
}
}
@@ -3930,7 +3944,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)
@@ -3950,7 +3965,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)
@@ -9165,6 +9181,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. */
@@ -9382,34 +9521,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 b78e9eb..6cd6e5f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6088,6 +6088,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 9fa4c16..e993220 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8820,23 +8820,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)
{