return ret;
}
-/* Give a note about the location of the declaration of DECL. */
+/* Give a note about the location of the declaration of DECL,
+ or, failing that, a pertinent declaration for FUNCTION_EXPR. */
static void
-inform_declaration (tree decl)
+inform_declaration (tree decl, tree function_expr)
{
if (decl && (TREE_CODE (decl) != FUNCTION_DECL
|| !DECL_IS_UNDECLARED_BUILTIN (decl)))
inform (DECL_SOURCE_LOCATION (decl), "declared here");
+ else if (function_expr)
+ switch (TREE_CODE (function_expr))
+ {
+ default:
+ break;
+ case COMPONENT_REF:
+ /* Show the decl of the pertinent field (e.g. for callback
+ fields in a struct. */
+ {
+ tree field_decl = TREE_OPERAND (function_expr, 1);
+ if (location_t loc = DECL_SOURCE_LOCATION (field_decl))
+ inform (loc, "declared here");
+ }
+ break;
+ }
}
/* C implementation of callback for use when checking param types. */
function);
else if (DECL_P (function))
{
+ auto_diagnostic_group d;
error_at (loc,
"called object %qD is not a function or function pointer",
function);
- inform_declaration (function);
+ inform_declaration (function, NULL_TREE);
}
else
error_at (loc,
if (type == void_type_node)
{
+ auto_diagnostic_group d;
+ int num_expected = parmnum;
+ int num_actual = values->length ();
+ gcc_rich_location rich_loc (loc);
+ if (ploc != input_location)
+ rich_loc.add_range (ploc);
if (selector)
- error_at (loc, "too many arguments to method %qE", selector);
+ error_at (&rich_loc,
+ "too many arguments to method %qE; expected %i, have %i",
+ selector, num_expected, num_actual);
else
- error_at (loc, "too many arguments to function %qE", function);
- inform_declaration (fundecl);
+ error_at (&rich_loc,
+ "too many arguments to function %qE; expected %i, have %i",
+ function, num_expected, num_actual);
+ inform_declaration (fundecl, function);
return error_args ? -1 : (int) parmnum;
}
if (builtin_type == void_type_node)
{
+ auto_diagnostic_group d;
if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch,
"too many arguments to built-in function %qE "
"expecting %d", function, parmnum))
- inform_declaration (fundecl);
+ inform_declaration (fundecl, function);
builtin_typetail = NULL_TREE;
}
if (!typetail && parmnum == 0 && !TYPE_NO_NAMED_ARGS_STDARG_P (fntype))
{
+ auto_diagnostic_group d;
bool warned;
if (selector)
warned = warning_at (loc, OPT_Wdeprecated_non_prototype,
" for function %qE declared without parameters",
function);
if (warned)
- inform_declaration (fundecl);
+ inform_declaration (fundecl, function);
}
if (selector && argnum > 2)
if (typetail != NULL_TREE && TREE_VALUE (typetail) != void_type_node)
{
- error_at (loc, "too few arguments to function %qE", function);
- inform_declaration (fundecl);
+ /* Not enough args.
+ Determine minimum number of arguments required. */
+ int min_expected_num = 0;
+ bool at_least_p = false;
+ tree iter = typelist;
+ while (true)
+ {
+ if (!iter)
+ {
+ /* Variadic arguments; stop iterating. */
+ at_least_p = true;
+ break;
+ }
+ if (iter == void_list_node)
+ /* End of arguments; stop iterating. */
+ break;
+ ++min_expected_num;
+ iter = TREE_CHAIN (iter);
+ }
+ auto_diagnostic_group d;
+ int actual_num = vec_safe_length (values);
+ error_at (loc,
+ at_least_p
+ ? G_("too few arguments to function %qE; expected at least %i, have %i")
+ : G_("too few arguments to function %qE; expected %i, have %i"),
+ function, min_expected_num, actual_num);
+ inform_declaration (fundecl, function);
return -1;
}
for (tree t = builtin_typetail; t; t = TREE_CHAIN (t))
++nargs;
+ auto_diagnostic_group d;
if (warning_at (loc, OPT_Wbuiltin_declaration_mismatch,
"too few arguments to built-in function %qE "
"expecting %u", function, nargs - 1))
- inform_declaration (fundecl);
+ inform_declaration (fundecl, function);
}
return error_args ? -1 : (int) parmnum;
--- /dev/null
+extern void fn_a (void);
+extern void fn_b (int); /* { dg-message "declared here" } */
+extern void fn_c (int, int); /* { dg-message "declared here" } */
+extern void fn_f (const char *, ...); /* { dg-message "declared here" } */
+
+void test_known_fn (void)
+{
+ fn_a ();
+ fn_b (); /* { dg-error "too few arguments to function '\[^\n\r\]*'; expected 1, have 0" } */
+ fn_c (42);/* { dg-error "too few arguments to function '\[^\n\r\]*'; expected 2, have 1" } */
+ fn_f (); /* { dg-error "too few arguments to function '\[^\n\r\]*'; expected at least 1, have 0" } */
+}
+
+struct foo
+{
+ void (*callback_a) (void);
+ void (*callback_b) (int); /* { dg-message "declared here" } */
+ void (*callback_c) (int, int); /* { dg-message "declared here" } */
+};
+
+void test_callback (struct foo *f)
+{
+ f->callback_a ();
+
+ f->callback_b (); /* { dg-error "too few arguments to function 'f->callback_b'; expected 1, have 0" } */
+
+ f->callback_c (42); /* { dg-error "too few arguments to function 'f->callback_c'; expected 2, have 1" } */
+}
--- /dev/null
+/* Ensure that we get an error on the call to fn_a with an
+ int arg below. */
+/* { dg-additional-options "-std=c23" } */
+
+/* Verify that the first excess param is underlined. */
+/* { dg-additional-options "-fdiagnostics-show-caret" } */
+
+extern void fn_a (); /* { dg-message "declared here" } */
+extern void fn_b (void); /* { dg-message "declared here" } */
+extern void fn_c (int); /* { dg-message "declared here" } */
+
+void test_known_fn (void)
+{
+ fn_a (42); /* { dg-error "too many arguments to function 'fn_a'; expected 0, have 1" } */
+ /* { dg-begin-multiline-output "" }
+ fn_a (42);
+ ^~~~ ~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ extern void fn_a ();
+ ^~~~
+ { dg-end-multiline-output "" } */
+
+ fn_b (1776); /* { dg-error "too many arguments to function 'fn_b'; expected 0, have 1" } */
+ /* { dg-begin-multiline-output "" }
+ fn_b (1776);
+ ^~~~ ~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ extern void fn_b (void);
+ ^~~~
+ { dg-end-multiline-output "" } */
+
+ fn_c (1066, 1649); /* { dg-error "too many arguments to function 'fn_c'; expected 1, have 2" } */
+ /* { dg-begin-multiline-output "" }
+ fn_c (1066, 1649);
+ ^~~~ ~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ extern void fn_c (int);
+ ^~~~
+ { dg-end-multiline-output "" } */
+}
+
+struct foo
+{
+ void (*callback_a)(); /* { dg-message "declared here" } */
+ void (*callback_b)(void); /* { dg-message "declared here" } */
+ void (*callback_c)(int); /* { dg-message "declared here" } */
+};
+
+void test_callback (struct foo *f)
+{
+ f->callback_a (42); /* { dg-error "too many arguments to function 'f->callback_a'; expected 0, have 1" } */
+ /* { dg-begin-multiline-output "" }
+ f->callback_a (42);
+ ^ ~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void (*callback_a)();
+ ^~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ f->callback_b (1776); /* { dg-error "too many arguments to function 'f->callback_b'; expected 0, have 1" } */
+ /* { dg-begin-multiline-output "" }
+ f->callback_b (1776);
+ ^ ~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void (*callback_b)(void);
+ ^~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ f->callback_c (1066, 1649); /* { dg-error "too many arguments to function 'f->callback_c'; expected 1, have 2" } */
+ /* { dg-begin-multiline-output "" }
+ f->callback_c (1066, 1649);
+ ^ ~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void (*callback_c)(int);
+ ^~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}