Name
	n3900, alx-0077r5 - disallow function parameters of function type

Principles
	-  Uphold the character of the language.
	-  Avoid quiet changes.

	And from previous charters:

	C23:
	-  APIs should be self-documenting when possible.

Category
	Language; function parameters.

Authors
	Alejandro Colomar <alx@kernel.org>
	Alex Celeste <alexg.nvfp@gmail.com>

	Cc: Martin Uecker <uecker@tugraz.at>
	Acked-by: Bruno Haible <bruno@clisp.org>
	Acked-by: Doug McIlroy
	Acked-by: Andrew Clayton <ac@sigsegv.uk>
	Acked-by: onf <onf@disroot.org>
	Cc: Joseph Myers <josmyers@redhat.com>

History
	<https://www.alejandro-colomar.es/src/alx/alx/std/wg14/alx-0077.git/>

	r0 (2026-01-24):
	-  Initial draft.

	r1 (2026-01-25):
	-  Re-title.

	r2 (2026-01-25):
	-  Acked-by Bruno.
	-  Add Comments section.

	r3 (2026-01-26):
	-  Acked-by.
	-  Tweak the constraint in p3 instead of adding a new one.
	-  Co-authored-by Alex Celeste.
	-  ffix
	-  Add Celeste's comment about the C89/C90 rationale and K&R.

	r4 (2026-02-01; n3798):
	-  Acked-by.
	-  Update 6.7.9p6(EX3)
	-  Mention cases.

	r5 (2026-05-30; n3900):
	-  Disallow function parameters also in declarators not part of
	   a definition.  [Joseph]
	-  Update several footnotes.  [Joseph]
	-  Update the example in 6.7.9 to document the constraint
	   violation instead of changing the example.  [Joseph]
	-  Rebase on n3854.

Abstract
	A function parameter of function type is adjusted to a pointer:

		void f(void fp(void));

	is adjusted to

		void f(void (*fp)(void));

	This is unnecessary and confusing; let's disallow it.

Discussion
	I've never seen any code written declaring a function parameter
	of function type.  Unlike array parameters, this adjustment
	seems to be seldom used, if at all.

	We can turn this into a constraint violation, which will
	require that the few users of this quirk of C to tweak their
	declarations to declare a pointer type (which is what these
	parameters have always been).

	I've tried finding such uses with a search engine, but didn't
	find anything; it could be that there are no uses, or it could
	be that it's hard to write a regex that would find this.  FWIW,
	the standard has one example, just to document this weird
	allowance, and uses the usual pointer to function syntax
	elsewhere.

	Apart from resulting in more explicit code, this simplifies the
	wording, which would get more complex with other proposals that
	will modify compatibility rules regarding adjustment (it would
	require specifying some exceptions).

	Chris did find one case, although it seemed very clearly to be
	a typo, since the function declaration and the function
	definition had different syntax (one had a pointer, and the
	other not).  Most likely, a typo that got uncaught, as there are
	no diagnostics for this.

	I've also heard that Jens's book uses function types to denote
	nonnull-ness of a function pointer.  This is something that
	should be handled by a language feature that is consistent with
	arbitrary pointer types, such as _Optional, _Nullable, [static],
	or [[gnu::nonnull]].

Comments
	On 2026-01-25T19:48:04+0100, Bruno Haible wrote:
	> I saw such a function parameter of function type once in 25 years of
	> C programming, and I found it confusing.
	>
	> This is an incompatible change to the language. But the impact on
	> existing code is so small that it's worth it.

	---

	On 2026-01-25T18:19:02-0500, Douglas McIlroy wrote:
	> All six proposals look eminently reasonable.  They simplify
	> the language and remove surprises.  I suspect these proposals
	> will invalidate very few existing programs.  In any event, the
	> required corrections will improve the legibility and
	> maintainability of such programs.
	>
	> Doug McIlroy

	---

	On 2026-01-26T02:27:02+0000, Alex Celeste wrote:
	> I was surprised not to find any comment in the C90 Rationale
	> about this.
	>
	> KnR1 says that 'since a reference to an array in any context
	> (in particular as an actual parameter) is taken to mean a
	> pointer to the first element of the array, declarations of
	> formal parameters declared ‘‘array of...’’ are adjusted to
	> read ‘‘pointer to ...’’.' There's no mention of functions in
	> this part, even though the KnR1 language does explicitly
	> describe using "bare" function identifiers to decay to
	> function pointers.
	>
	> This honestly feels like something that was added for
	> stylistic consistency.  Function pointers were already
	> well-developed before this became a language feature.
	> Combined with the fact that you _can't_ use a function type in
	> a definition of a thing with that type, and using it in an
	> external declaration creates something incompatible with an
	> object of function pointer type, and I think this was an
	> attempt at consistency that ended up creating an inconsistency
	> instead.
	> The [...] example does look unintentional to me for that
	> reason.

Proposed wording
	Proposed wording
	Based on N3854.
	
    6.5.3.3  Function calls
	@@ Semantics, footnote 77 (referenced in p4)
	...
	 A parameter declared to have array
	-or function
	 type
	 is adjusted to have a pointer type as described in 6.7.7.4.
	
    6.5.4.5  The sizeof, _Countof, and alignof operators
	@@ Semantics, footnote 86 (referenced in p4)
	 When applied to a parameter declared to have array
	-or function
	 type,
	 the sizeof operator yields
	 the size of the adjusted (pointer) type (see 6.9.2).
	
    6.7.3.6  Typeof specifiers
	@@ Semantics, footnote 117 (referenced in p4)
	 When applied to a parameter declared to have array
	-or function
	 type,
	 the typeof operators yield
	 the adjusted (pointer) type (see 6.9.2).
	
    6.7.7.4  Function declarators
	@@ Constraints, p3
	 After adjustment,
	 the parameters in a parameter type list
	 in a function declarator
	 that is part of a definition of that function
	-shall not have incomplete type.
	+shall have complete object type.
	
	@@ Constraints, p4+1
	+4+1
	+	A parameter declaration
	+	shall not specify a function type.
	
	@@ Semantics, p8
	-A declaration of a parameter
	-as "function returning type"
	-shall be adjusted
	-to "pointer to function returning type",
	-as in 6.3.3.1.
	
	@@ p15
	...
	 In the determination
	 of type compatibility and of a composite type,
	 each parameter declared with
	-function or array type
	+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.
	
    6.7.9  Type definitions
	@@ Syntax, p6 (EXAMPLE 3)
	...
	 then a function f is declared with type
	 "function returning signed int
	 with one unnamed parameter with type
	 pointer to function returning signed int
	 with one unnamed parameter with type signed int"
	+(which violates a constraint)
	 ,
	 and an identifier t with type long int.
	
    6.9.2  Function definitions
	@@ Semantics, p15
	 EXAMPLE 2 To pass one function to another, one can say
		int f(void);
		/* ... */
	-	g(f);
	+	g(f);  /* or g(&f); */
	 Then the definition of g can read
		void g(int (*funcp)(void))
		{
			/* ... */
			(*funcp)();  /* or funcp(); */
		}
	-or, equivalently,
	-	void g(int func(void))
	-	{
	-		/* ... */
	-		func();  /* or (*func)(); */
	-	}
	
	## I added 'g(&f)' for consistency with comments that show
	## alternate valid syntax; it seems an accidental omission that
	## could be fixed editorially.