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

Reply via email to