The use of () to denote an unknown or varargs parameter list in function declarations and function types, a language feature from K&R C, is finally disallowed in ISO C 23. Instead, () as a parameter list denotes a list of zero arguments, the same as (void), in ISO C 23. The set of warnings that were added to GCC over the years, regarding function prototypes, were designed at a time when the migration target was still unknown. Now that the migration target, ISO C 23, is known, some projects want to have the following programming style, for code that compiles OK both in C99 and C23: - (1) In function definitions, use () to denote argument lists with zero arguments. - (2) In function declarations and function types, use (void) to denote argument lists with zero arguments. See https://lists.gnu.org/archive/html/bug-gnulib/2023-02/msg00055.html and https://lists.gnu.org/archive/html/bug-gnulib/2023-02/msg00062.html for details of the rationale. As a programmer, I would like to have an easy way to get warnings when this programming style is not followed. There are two ways such a warning could be added to GCC: (A) A warning that applies when compiling for a language standard older than C23 (e.g. -std=gnu99). In which situations would this warning be emitted? ========================================================================= /* Function definitions: */ void func1 () {} /* No warning */ void func2 (void) {} /* No warning */ /* Function declarations: */ void func3 (); /* warning: an empty parameter list in function declarators will have a different meaning in ISO C23 */ void func4 (void); /* No warning */ ========================================================================= Looking through the existing warning options of GCC and clang: Warning options from https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html Option Not adequate because ... ----------------------- ------------------------ -Wall Does not warn for func3. -Wstrict-prototypes Warns for func1 as well. -Wold-style-declaration Does not warn for func3. -Wold-style-definition Does not warn for func3. Warns for func1. -Wmissing-prototypes Does not warn for func3. Warns for func1 and func2. -Wmissing-declarations Does not warn for func3. Warns for func1 and func2. -Wpedantic Does not warn for func3. Warning options from https://clang.llvm.org/docs/DiagnosticsReference.html Option Not adequate because ... ----------------------- ------------------------ -Wall Does not warn for func3. -Wdeprecated-declarations Does not warn for func3. -Wdeprecated-non-prototype Does not warn for func3. -Wmissing-prototypes Does not warn for func3. Warns for func1 and func2. -Wpedantic Warns for func1 as well. So, none of these existing warning options fits the need. A new warning option is needed. (B) A warning that applies when compiling for C23 (e.g. -std=gnu23). The situations would be the same as above. Only the diagnostic's message would refer to *older* standard versions, such as: ========================================================================= /* Function definitions: */ void func1 () {} /* No warning */ void func2 (void) {} /* No warning */ /* Function declarations: */ void func3 (); /* warning: an empty parameter list in function declarators denotes a varargs parameter list in ISO C17 and older; use (void) to disambiguate */ void func4 (void); /* No warning */ =========================================================================
Clang now has -Wdeprecated-non-prototype apparently: https://discourse.llvm.org/t/unresolved-issues-from-the-llvm-15-x-release/66071/36 This is probably not very useful as a warning: > void func3 (); /* warning: an empty parameter list in function declarators will have a different meaning in ISO C23 */ “()” is going to be fine when matched with an empty parameter list in a definition, or an empty argument list in a call. I don't think it's necessary to warn in those cases. It distracts from the real issue.
(In reply to Florian Weimer from comment #1) > “()” is going to be fine when matched with an empty parameter list in a > definition, or an empty argument list in a call. I don't think it's > necessary to warn in those cases. It distracts from the real issue. OK. So let's see what we get with this approach where 'void func3 ();' doesn't warn and only the wrong uses of func3 produce diagnostics. Here's a test case, annotated with 'error' in those places where 'clang15 -std=c2x' produces an error: ============================================================================= /* Function definitions: */ void func1 () {} void func2 (void) {} /* Function declarations: */ void func3 (); void func4 (void); void code () { void (*fp) (void); void (*fp1) (int); fp = func1; fp = func2; fp = func3; fp = func4; fp1 = func3; func1 (1); /* error */ func2 (2); /* error */ func3 (3); /* error */ func4 (4); /* error */ (void) fp; (void) fp1; } void func3 (int x, int y) {} /* error */ ============================================================================= When compiling this in -std=c17 or older mode, we would like to get a warning - in those places where we get an error in C23 mode, and - in those places where there are unsafe conversions or parameter passing going on in C23 or in C17 or older. In detail, the desired behaviour in -std=c17 or older mode is: ============================================================================= /* Function definitions: */ void func1 () {} /* No warning */ void func2 (void) {} /* No warning */ /* Function declarations: */ void func3 (); /* No warning */ void func4 (void); /* No warning */ void code () { void (*fp) (void); void (*fp1) (int); fp = func1; /* No warning */ fp = func2; /* No warning */ fp = func3; /* No warning */ fp = func4; /* No warning */ fp1 = func3; /* warning */ func1 (1); /* warning (if -std=c17) or error (if -std=c23) */ func2 (2); /* error */ func3 (3); /* warning (if -std=c17) or error (if -std=c23) */ func4 (4); /* error */ (void) fp; (void) fp1; } void func3 (int x, int y) {} /* warning (if -std=c17) or error (if -std=c23) */ ============================================================================= In the line 'fp1 = func3;' a warning should be shown because it's an unsafe function pointer conversion in C23. (Even though in C17 it is not dangerous code and even though in C23 it's not an error!) 'clang15 -std=c2x -Wincompatible-function-pointer-types' does show a "warning: incompatible function pointer types" there. > Clang now has -Wdeprecated-non-prototype apparently But '-Wdeprecated-non-prototype' does not exactly have the behaviour you want: while it warns for 'func1 (1);' and 'func3 (3);' (good!), it warns also for 'void func3 ();', that is, where you don't want to see a warning. So, no existing GCC or clang warning option has the desired behaviour. What we need (and even independently of programming style) is * a part of -Wdeprecated-non-prototype: do warn in function call positions, don't warn in function declaration/type positions, * combined with a kind of -Wfuture-incompatible-function-pointer-types, that considers the interpretation according to C23 instead of the interpretation according to the currently chosen standard.
(In reply to Bruno Haible from comment #2) > But '-Wdeprecated-non-prototype' does not exactly have the behaviour you > want: while it warns for 'func1 (1);' and 'func3 (3);' (good!), it warns > also for 'void func3 ();', that is, where you don't want to see a warning. FWIW, the reason you get a warning on the declaration of `func3` in Clang is because of the definition of `func3` that is invalid in C2x but was valid in prior standards modes. If you do not provide a problematic conflicting definition, the diagnostic is silenced: https://godbolt.org/z/aMPrvWz1j
(In reply to Aaron Ballman from comment #3) OK. So, except for this unlucky (*) choice of attribution in case of a conflict between function declaration and function definition, the '-Wdeprecated-non-prototype' warning is actually usable. What we need is thus: * -Wdeprecated-non-prototype, * combined with a kind of -Wfuture-incompatible-function-pointer-types, that considers the interpretation according to C23 instead of the interpretation according to the currently chosen standard. (*) Reported as a clang bug at https://github.com/llvm/llvm-project/issues/60592 .