Name
        alx-0076r3 - incompatible array parameters

Principles
        -  Uphold the character of the language.
        -  Codify existing practice to address evident deficiencies.
        -  Avoid quiet changes.
        -  Enable secure programming.

        And from previous charters:

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

Category
        Language; array parameters.

Authors
        Alejandro Colomar <[email protected]>
        Martin Uecker <[email protected]>

        Acked-by: Doug McIlroy
        Acked-by: Andrew Clayton <[email protected]>

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

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

        r1 (2026-01-24):
        -  Add a principle.
        -  Don't break parameters of function type (but see alx-0077).
        -  Document that this also applies to [static n].
        -  Remove superfluous line in diff.
        -  Clarify that the array type is incomplete.
        -  Add 'See also'.
        -  ffix

        r2 (2026-01-25):
        -  Take the two examples from N2906 (reordered).
        -  Add Martin as co-author.

        r3 (2026-01-26):
        -  Acked-by.
        -  tfix

Abstract
        The following two function prototypes violate a constraint:

                void f(int (*p)[2]);
                void f(int (*p)[2+1]);

        The following two function prototypes should be unacceptable,
        for consistency:

                void g(int a[2]);
                void g(int a[2+1]);

Discussion
        The prototypes above are obviously wrong.  If a program is
        compiled containing the above prototypes for g(), the programmer
        is clearly very confused, and there are high chances that the
        program will eventually overflow a buffer.

        Currently, a program containing

                void g(int a[2]);
                void g(int a[2+1]);

        is a valid program, because the array parameters are adjusted to
        pointers before checking for type compatibility.

        The standard (n3685) says in 6.7.7.4p3:

                Two function types are compatible
                if and only if all of the following hold:
                        --  They specify compatible return types.
                        --  The parameter type lists
                            agree in the number of parameters
                            and in whether the function is variadic or not.
                        --  The corresponding parameters 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.

        We could easily tweak that paragraph to say that the
        compatibility is tested before adjustment.  That would need a
        teak to make pointers compatible with arrays, though.  It would
        also need a tweak so that in function calls we still use the
        adjusted type.

    [static n]
        This change also makes the following be not compatible:

                void h(int a[static 2]);
                void h(int a[static 2+1]);

        This is intentional.  A future proposal will propose that
        a function declared with a parameter [static n] is not allowed
        to access more than n elements (and the current proposal already
        kind-of implies this).  Another future proposal will make
        [static n] and [n] equivalent, except for nullability of the
        pointer.

Prior art
        Both GCC and Clang already diagnose such code:

                alx@devuan:~/tmp$ cat ap.c 
                void g(int a[2]);
                void g(int a[2+1]);
                alx@devuan:~/tmp$ gcc -Wall -S ap.c 
                ap.c:2:12: warning: argument 1 of type ‘int[3]’ with mismatched 
bound [-Warray-parameter=]
                    2 | void g(int a[2+1]);
                      |        ~~~~^~~~~~
                ap.c:1:12: note: previously declared as ‘int[2]’
                    1 | void g(int a[2]);
                      |        ~~~~^~~~
                alx@devuan:~/tmp$ clang -Weverything -S ap.c 
                ap.c:2:12: warning: argument 'a' of type 'int[3]' with
                      mismatched bound [-Warray-parameter]
                    2 | void g(int a[2+1]);
                      |            ^
                ap.c:1:12: note: previously declared as 'int[2]' here
                    1 | void g(int a[2]);
                      |            ^
                1 warning generated.

See also
        N2906 (Uecker; "Consistency of Parameters Declared as Arrays (updates 
N2779)")
        That proposal is superseded by this one, which achieves the same
        goal with significantly less complexity.

        alx-0077r0 - function parameters of function type
        <https://www.alejandro-colomar.es/src/alx/alx/std/wg14/alx-0077.git/>

Comments
        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:01:16+0000, Alex Celeste wrote:
        > Like Martin - these all seem eminently reasonable to me.

Proposed wording
        Based on N3685.

    6.5.3.3  Function calls
        @@ Constraints, p2
         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.
        +its corresponding adjusted parameter.

    6.7.7.4  Function declarators
        @@ Semantics, p15
         Two function types are compatible
         if and only if all of the following hold:
                --  They specify compatible return types.
                --  The parameter type lists
                    agree in the number of parameters
                    and in whether the function is variadic or not.
                --  The corresponding parameters have compatible types.
         In the determination
         of type compatibility
         and of a composite type,
        -each parameter declared with function or array type
        +each parameter declared with array type
         is taken as having
        -the adjusted type
        +the non-adjusted type,
        +each parameter declared with function type    ## \
        +is taken as having                            ## -} See below.
        +the adjusted type,                            ## /
        +each parameter declared with "pointer to object <i>type</i>"
        +is taken as having incomplete "array of <i>type</i>"
        +(the opposite of adjustment),
         and each parameter declared with qualified type
         is taken as having
         the unqualified version of its declared type.

        ## The three lines about function type are to not change
        ## anything regarding function types in this proposal, as this
        ## proposal intends to be mostly uncontroversial.  However, it
        ## is cruft that shouldn't be there.  There's another proposal
        ## for removing that: alx-0077.  If that other proposal is
        ## accepted before this one (or at the same time), remove these
        ## three lines here.

        @@ p21+1
        +EXAMPLE 6
        +The following are all compatible function prototype declarators:
        +       void g(int x[const 5]);
        +       void g(int x[5]);          // composite type
        +       void g(int *restrict x);
        +       void g(int x[*]);
        +       void g(int x[]);

        @@ p21+2
        +EXAMPLE 7
        +The following function prototype declarators
        +are not compatible:
        +       void g(int x[5]);
        +       void g(int x[3]);

-- 
<https://www.alejandro-colomar.es>

Attachment: signature.asc
Description: PGP signature

Reply via email to