c: Implement -Wdeprecated-non-prototype

This warning covers the C23 incompibilities resulting from using
() as parameter lists in function declarations.

The warning name comes from Clang.  The implementation is not
perfect because GCC treats these two declarations as equivalent:

  void f ();
  void f (not_a_type);

This is a bit confusing because they are clearly visually distinct.
However, as of GCC 14, the second form is an error by default, so
treating both the same as far as  -Wdeprecated-non-prototype does
not seem so bad from a user experience view.

gcc/c-family/

	PR c/95445
	* c-opts.cc (c_common_post_options): Initialize
	warn_deprecated_non_prototype.
	* c.opt (Wdeprecated-non-prototype): New option.
	* c.opt.urls: Regenerate.

gcc/c/

	PR c/95445
	* c-decl.cc (start_function): Warn about parameters
	after parameter-less declaration.
	* c-typeck.cc (build_function_call_vec): Pass fntype
	to convert_arguments.
	(convert_arguments): Change argument to fntype and
	compute typelist.  Warn about parameter list mismatches
	on first parameter.

gcc/

	PR c/95445
	* doc/invoke.texi: Document -Wdeprecated-non-prototype.

gcc/testsuite/

	PR c/95445
	* gcc.dg/Wdeprecated-non-prototype-1.c: New test.
	* gcc.dg/Wdeprecated-non-prototype-2.c: New test.
	* gcc.dg/Wdeprecated-non-prototype-3.c: New test.
	* gcc.dg/Wdeprecated-non-prototype-4.c: New test.
This commit is contained in:
Florian Weimer 2024-11-17 19:42:33 +01:00
parent 3e89a4d513
commit 701d8e7e60
10 changed files with 147 additions and 5 deletions

View File

@ -1006,6 +1006,9 @@ c_common_post_options (const char **pfilename)
= ((pedantic && !flag_isoc23 && warn_c11_c23_compat != 0) = ((pedantic && !flag_isoc23 && warn_c11_c23_compat != 0)
|| warn_c11_c23_compat > 0); || warn_c11_c23_compat > 0);
if (warn_deprecated_non_prototype == -1)
warn_deprecated_non_prototype = warn_c11_c23_compat > 0;
/* -Wshift-negative-value is enabled by -Wextra in C99 and C++11 to C++17 /* -Wshift-negative-value is enabled by -Wextra in C99 and C++11 to C++17
modes. */ modes. */
if (warn_shift_negative_value == -1) if (warn_shift_negative_value == -1)

View File

@ -668,6 +668,10 @@ Wdeprecated-literal-operator
C++ ObjC++ Var(warn_deprecated_literal_operator) Warning C++ ObjC++ Var(warn_deprecated_literal_operator) Warning
Warn about deprecated space between "" and suffix in a user-defined literal operator. Warn about deprecated space between "" and suffix in a user-defined literal operator.
Wdeprecated-non-prototype
C ObjC Var(warn_deprecated_non_prototype) Init(-1) Warning
Warn about calls with arguments to functions declared without parameters.
Wdesignated-init Wdesignated-init
C ObjC Var(warn_designated_init) Init(1) Warning C ObjC Var(warn_designated_init) Init(1) Warning
Warn about positional initialization of structs requiring designated initializers. Warn about positional initialization of structs requiring designated initializers.

View File

@ -307,6 +307,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdeprecated-enum-float-conv
Wdeprecated-literal-operator Wdeprecated-literal-operator
UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdeprecated-literal-operator) UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wdeprecated-literal-operator)
Wdeprecated-non-prototype
UrlSuffix(gcc/Warning-Options.html#index-Wdeprecated-non-prototype)
Wdesignated-init Wdesignated-init
UrlSuffix(gcc/Warning-Options.html#index-Wdesignated-init) UrlSuffix(gcc/Warning-Options.html#index-Wdesignated-init)

View File

@ -10750,6 +10750,24 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
} }
} }
/* Optionally warn about C23 compatibility. */
if (warn_deprecated_non_prototype
&& old_decl != NULL_TREE
&& TREE_CODE (oldtype) == FUNCTION_TYPE
&& !TYPE_ARG_TYPES (oldtype)
&& !TYPE_NO_NAMED_ARGS_STDARG_P (oldtype)
&& (TYPE_ARG_TYPES (newtype)
&& TREE_VALUE (TYPE_ARG_TYPES (newtype)) != void_type_node))
{
bool warned = warning_at (loc, OPT_Wdeprecated_non_prototype,
"ISO C23 does not allow defining"
" parameters for function %qE declared"
" without parameters",
decl1);
if (warned)
inform (DECL_SOURCE_LOCATION (old_decl), "declared here");
}
/* Optionally warn of old-fashioned def with no previous prototype. */ /* Optionally warn of old-fashioned def with no previous prototype. */
if (warn_strict_prototypes if (warn_strict_prototypes
&& old_decl != error_mark_node && old_decl != error_mark_node

View File

@ -3813,7 +3813,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
/* Convert the parameters to the types declared in the /* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */ function prototype, or apply default promotions. */
nargs = convert_arguments (loc, arg_loc, TYPE_ARG_TYPES (fntype), params, nargs = convert_arguments (loc, arg_loc, fntype, params,
origtypes, function, fundecl); origtypes, function, fundecl);
if (nargs < 0) if (nargs < 0)
return error_mark_node; return error_mark_node;
@ -4108,9 +4108,9 @@ convert_argument (location_t ploc, tree function, tree fundecl,
} }
/* Convert the argument expressions in the vector VALUES /* Convert the argument expressions in the vector VALUES
to the types in the list TYPELIST. to the types in the list TYPE_ARG_TYPES (FNTYPE).
If TYPELIST is exhausted, or when an element has NULL as its type, If the list is exhausted, or when an element has NULL as its type,
perform the default conversions. perform the default conversions.
ORIGTYPES is the original types of the expressions in VALUES. This ORIGTYPES is the original types of the expressions in VALUES. This
@ -4129,10 +4129,11 @@ convert_argument (location_t ploc, tree function, tree fundecl,
failure. */ failure. */
static int static int
convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype,
vec<tree, va_gc> *values, vec<tree, va_gc> *origtypes, vec<tree, va_gc> *values, vec<tree, va_gc> *origtypes,
tree function, tree fundecl) tree function, tree fundecl)
{ {
tree typelist = TYPE_ARG_TYPES (fntype);
unsigned int parmnum; unsigned int parmnum;
bool error_args = false; bool error_args = false;
const bool type_generic = fundecl const bool type_generic = fundecl
@ -4265,6 +4266,23 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
builtin_typetail = NULL_TREE; builtin_typetail = NULL_TREE;
} }
if (!typetail && parmnum == 0 && !TYPE_NO_NAMED_ARGS_STDARG_P (fntype))
{
bool warned;
if (selector)
warned = warning_at (loc, OPT_Wdeprecated_non_prototype,
"ISO C23 does not allow arguments"
" for method %qE declared without parameters",
function);
else
warned = warning_at (loc, OPT_Wdeprecated_non_prototype,
"ISO C23 does not allow arguments"
" for function %qE declared without parameters",
function);
if (warned)
inform_declaration (fundecl);
}
if (selector && argnum > 2) if (selector && argnum > 2)
{ {
rname = selector; rname = selector;

View File

@ -520,7 +520,7 @@ Objective-C and Objective-C++ Dialects}.
} }
@item C and Objective-C-only Warning Options @item C and Objective-C-only Warning Options
@gccoptlist{-Wbad-function-cast -Wmissing-declarations @gccoptlist{-Wbad-function-cast -Wdeprecated-non-prototype -Wmissing-declarations
-Wmissing-parameter-name -Wmissing-parameter-type -Wmissing-parameter-name -Wmissing-parameter-type
-Wdeclaration-missing-parameter-type -Wmissing-prototypes -Wdeclaration-missing-parameter-type -Wmissing-prototypes
-Wmissing-variable-declarations -Wnested-externs -Wold-style-declaration -Wmissing-variable-declarations -Wnested-externs -Wold-style-declaration
@ -10050,6 +10050,16 @@ is not considered an old-style definition in C23 mode, because it is
equivalent to @samp{(void)} in that case, but is considered an equivalent to @samp{(void)} in that case, but is considered an
old-style definition for older standards. old-style definition for older standards.
@opindex Wdeprecated-non-prototype
@opindex Wno-deprecated-non-prototype
@item -Wdeprecated-non-prototype @r{(C and Objective-C only)}
Warn if a function declarated with an empty parameter list @samp{()} is
called with one or more arguments, or if a function definition with one
or more parameters is encountered after such a declaration. Both cases
are errors in C23 and later dialects of C.
This warning is also enabled by @option{-Wc11-c23-compat}.
@opindex Wmissing-parameter-name @opindex Wmissing-parameter-name
@opindex Wno-missing-parameter-name @opindex Wno-missing-parameter-name
@item -Wmissing-parameter-name @r{(C and Objective-C only)} @item -Wmissing-parameter-name @r{(C and Objective-C only)}

View File

@ -0,0 +1,24 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu17 -Wdeprecated-non-prototype" } */
void f1 ();
void f2 (); /* { dg-note "declared here" } */
void f3 (...);
void
g ()
{
f1 ();
f2 (1); /* { dg-warning "does not allow arguments for function" } */
f3 (1);
}
void
f1 ()
{
}
void
f2 (int i) /* { dg-warning "does not allow defining parameters for function" } */
{
}

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu17 -Wc11-c23-compat" } */
void f1 ();
void f2 (); /* { dg-note "declared here" } */
void
g ()
{
f1 ();
f2 (1); /* { dg-warning "does not allow arguments for function" } */
}
void
f1 ()
{
}
void
f2 (int i) /* { dg-warning "does not allow defining parameters for function" } */
{
}

View File

@ -0,0 +1,18 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu17 -Wdeprecated-non-prototype -Wno-declaration-missing-parameter-type" } */
void f1 (not_a_type); /* { dg-note "declared here" } */
void f2 (not_a_type); /* { dg-note "declared here" } */
void
g ()
{
/* This is not ideal, but the GCC type system does not capture the number of
arguments in a non-prototype function declaration. */
f1 (1); /* { dg-warning "does not allow arguments for function" } */
}
void
f2 (int not_a_type) /* { dg-warning "does not allow defining parameters" } */
{
}

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu17 -Wc11-c23-compat -Wno-deprecated-non-prototype" } */
void f1 ();
void f2 ();
void
g ()
{
f1 ();
f2 (1);
}
void
f1 ()
{
}
void
f2 (int i)
{
}