N 2841: No function declarators without prototypes

Submitter: Philipp Klaus Krause
Submission Date: 2021-10-10

Summary:

No function declarators without prototypes. Follow-up to N2773 based on feedback from the August / September meeting (WG14 prefers to resuse the old syntax for function declarators without prototypes for C++-style function prototypes, instead of making it a constraint violation).

This removes the obsolescent support for function declarators without prototypes. The old syntax for function declarators without prototypes is instead given the C++ semantics.

Justification:

Function declarators without prototypes have been an obsolescent feature since the very first ISO C standard. 33 years of advance warning should be enough.

The previous N2773 proposal makes an empty parameter list a constraint violation. In C++, an empty parameter list indicates that the function has no parameters. However, following C++ would mean changing the meaning of existing syntax. While the auto proposal does something similar (as plain auto had a different meaning with implicit int in C90 and C94), there was some waiting time in between, when the now reused syntax was a constraint violation in C99 to C17. Also, unlike auto, which introduced a new feature, current C already has a way to indicate that a function has no parameters.

In this proposal, a function declarator without a parameter list declares a prototype for a function that takes no parameters (like it does in C++).

Do we want to remove function declarators without prototypes, reusing their syntax for for function declarators for functions with no parameters?

Proposed change: In N2596:

§6.1.1: replace the paragraph
"For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope. Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function, file, block, and function prototype. (A function prototype is a declaration of a function that declares the types of its parameters.)"
by
"For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope. Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function, file, block, and function prototype. (A function prototype is a declaration of a function.)".

§6.2.7: remove
"— If only one type is a function type with a parameter type list (a function prototype), the composite type is a function prototype with the parameter type list."

§6.5.2.2: replace the paragraph
"If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter."
by
"The number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter."

§6.5.2.2: replace the paragraphs
"If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.
If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments. "
by
"The arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The integer promotions are performed on each trailing argument, and trailing arguments that have type float are promoted to double. These are called the default argument promotions.".

§6.5.2.2: replace the paragraph
"No other conversions are performed implicitly; in particular, the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator."
by
"No other conversions are performed implicitly.".

§6.7.6.3: replace the paragraph
"For a function declarator without a parameter type list: if it is part of a definition of that function the function has no parameters and the effect is as if it were declared with a parameter type list consisting of the keyword void ; otherwise it specifies that no information about the number or types of the parameters is supplied.157) A function declarator provides a prototype for the function if it includes a parameter type list.158) Otherwise, a function declaration is said to have no prototype."
by
"For a function declarator without a parameter type list: the effect is as if it were declared with a parameter type list consisting of the keyword void. A function declarator provides a prototype for the function.158)"
and remove footnote 157.

§6.7.6.3: replace the paragraph
"For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type has none and is not part of a function definition, the parameter list shall not have an ellipsis terminator. In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type."
by
"For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.".

Remove §6.11.6.

§7.1.2: replace
"Each library function is declared, with a type that includes a prototype,".
by
"Each library function is declared".

Annex I: remove
"— A function is called but no prototype has been supplied (6.5.2.2).".

Annex J: remove
"— For a call to a function without a function prototype in scope, the number of arguments does not equal the number of parameters (6.5.2.2)."
and
"— For a call to a function without a function prototype in scope where the function is defined with a function prototype, either the prototype ends with an ellipsis or the types of the arguments after default argument promotion are not compatible with the types of the parameters (6.5.2.2).".