On Sat, Jan 11, 2025 at 01:55:42PM -0500, David Malcolm wrote: > + if ((takes_void_p (fntype_a) && takes_int_p (fntype_b)) > + || (takes_int_p (fntype_a) && takes_void_p (fntype_b))) > + { > + inform (UNKNOWN_LOCATION, > + "the meaning of %<()%> in function declarations changed" > + " in C23 from %<(int)%> to %<(void)%>");
That is not true. The C17 and earlier meaning of rettype identifier (); or rettype (*identifier) (); etc. is (in C17 6.7.6.3): "The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied." And per C17 6.11.6 it was: "The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature." E.g. the 6.7.6.3 example attempts to clarify that: "The declaration int f(void), *fip(), (*pfi)(); declares a function f with no parameters returning an int, a function fip with no parameter specification returning a pointer to an int, and a pointer pfi to a function with no parameter specification returning an int. It is especially useful to compare the last two. The binding of *fip() is *(fip()) , so that the declaration suggests, and the same construction in an expression requires, the calling of a function fip, and then using indirection through the pointer result to yield an int. In the declarator (*pfi)() , the extra parentheses are necessary to indicate that indirection through a pointer to a function yields a function designator, which is then used to call the function; it returns an int." As C23 doesn't have any syntax to specify a function with no parameter specification returning sometype, I'm afraid you can't use something short in %<%> for the old meaning, you should say maybe "the meaning of %<()%> in function declarations which are not a definition" "changed in C23 from function with no parameter specification to %<(void)%>" or so. And, the takes_int_p doesn't make any sense. Sure, in the example you've given, because void (*int_stat)(); int_stat used to be a function pointer to a function with unspecified parameter specification returning void, you could call through that int_stat (0); if it actually pointed to a function with int argument, but also int_stat (0.0); if it actually pointed to a function with double argument, or int_stat ("foo", 1, 1LL); if it pointed to a function with const char *, int, long long arguments, etc. Note, in the K&R style, if there is a function definition void foo () { } then for the declaration it is still a function with no parameter specification (how other functions see it), while in the actual definition it has no parameters. The functions declared with unspecified parameter specification actually can't be defined with an ellipsis, and do be compatible can have only types after default argument promotions (so not float, {,{un,}signed} {char,short}). Many years ago, most of the functions were just declared in C like char *strstr (); (or if they had int return type just used implicit declarations), and then it is up to users to know the function has 2 arguments which need to be pointers to char. If you call such a function, the type of each passed argument goes through default argument promotion and that is how it expects the function to be called. Jakub