diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 6e40f7edf02ae95a90594cd71aff6da02cfe9a6e..cd9290160d7a391185298dd6cf7e836570e2cf68 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3737,14 +3737,30 @@ build_function_call (location_t loc, tree function, tree params) 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. */ @@ -3819,10 +3835,11 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, 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, @@ -4276,25 +4293,37 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype, 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, @@ -4307,7 +4336,7 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype, " for function %qE declared without parameters", function); if (warned) - inform_declaration (fundecl); + inform_declaration (fundecl, function); } if (selector && argnum > 2) @@ -4437,8 +4466,33 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype, 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; } @@ -4448,10 +4502,11 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype, 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; diff --git a/gcc/testsuite/gcc.dg/too-few-arguments.c b/gcc/testsuite/gcc.dg/too-few-arguments.c new file mode 100644 index 0000000000000000000000000000000000000000..4406e021e0c321dee920a40fffa2544e803a32ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/too-few-arguments.c @@ -0,0 +1,28 @@ +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" } */ +} diff --git a/gcc/testsuite/gcc.dg/too-many-arguments.c b/gcc/testsuite/gcc.dg/too-many-arguments.c new file mode 100644 index 0000000000000000000000000000000000000000..5bbd4a306c3b21e6229e527fb80540fb0042e66c --- /dev/null +++ b/gcc/testsuite/gcc.dg/too-many-arguments.c @@ -0,0 +1,83 @@ +/* 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 "" } */ +}