Re: [PATCH] Various pages: SYNOPSIS: Use VLA syntax in function parameters

Alejandro Colomar
2022-11-13T16:56:31Z

[-- Attachment #1.1: Type: text/plain, Size: 5300 bytes --]

On 11/13/22 17:34, Alejandro Colomar wrote:
>
>
> On 11/13/22 17:31, Alejandro Colomar wrote:
>>
>>
>> On 11/13/22 17:28, Alejandro Colomar wrote:
>>> SYNOPSIS:
>>>
>>> unary-operator:  . identifier
>>>
>>>
>>> DESCRIPTION:
>>>
>>> -  It is not an lvalue.
>>>
>>>     -  This means sizeof() and _Lengthof() cannot be applied to them.
>>
>> Sorry, the above is a thinko.
>>
>> I wanted to say that, like sizeof() and _Lengthof(), you can't assign to it.
>>
>>>     -  This prevents ambiguity with a designator in an initializer-list
>>> within a nested braced-initializer.
>>>
>>> -  The type of a .identifier is always an incomplete type.
>
> Or rather, more easily prohibit explicitly using typeof(), sizeof(), and
> _Lengthof() to it.

Hmm, this is not enough. Pointer arithmetics are interesting, and for that, you
need to implicitly know the sizeof(*.p).

How about allowing only integral types or pointers to integral types?

>
>>>
>>>     -  This prevents circular dependencies involving sizeof() or _Lengthof().
>>>
>>> -  Shadowing rules apply.
>>>
>>>     -  This prevents ambiguity.
>>>
>>>
>>> EXAMPLES:
>>>
>>>
>>> -  Valid examples (libc):
>>>
>>>         int
>>>         strncmp(const char s1[.n],
>>>                 const char s2[.n],
>>>                 size_t n);
>>>
>>>         int
>>>         cacheflush(void addr[.nbytes],
>>>                    int nbytes,
>>>                    int cache);
>>>
>>>         long
>>>         mbind(void addr[.len],
>>>               unsigned long len,
>>>               int mode,
>>>               const unsigned long nodemask[(.maxnode + ULONG_WIDTH ‐ 1)
>>>                                            / ULONG_WIDTH],
>>>               unsigned long maxnode, unsigned int flags);
>>>
>>>         void *
>>>         bsearch(const void key[.size],
>>>                 const void base[.size * .nmemb],
>>>                 size_t nmemb,
>>>                 size_t size,
>>>                 int (*compar)(const void [.size], const void [.size]));
>>>
>>> -  Valid examples (my own):
>>>
>>>         void
>>>         ustr2str(char dst[restrict .len + 1],
>>>                  const char src[restrict .len],
>>>                  size_t len);
>>>
>>>         char *
>>>         stpecpy(char dst[.end - .dst + 1],
>>>                 char *restrict src,
>>>                 char end[1]);
>>>
>>> -  Valid examples (from this thread):
>>>
>>>     -
>>>         struct s { int a; };
>>>         void f(int a, int b[((struct s) { .a = 1 }).a]);
>>>
>>>         Explanation:
>>>         -  Because of shadowing rules, .a=1 refers to the struct member.
>>>            -  Also, if .a referred to the parameter, it would be an rvalue,
>>> so it wouldn't be valid to assign to it.
>>>         -  (...).a refers to the struct member too, since otherwise an rvalue
>>> is not expected there.
>>>
>>>     -
>>>         void foo(struct bar { int x; char c[.x] } a, int x);
>>>
>>>         Explanation:
>>>         -  Because of shadowing rules, [.x] refers to the struct member.
>>>
>>>     -
>>>         struct bar { int y; };
>>>         void foo(char p[((struct bar){ .y = .x }).y], int x);
>>>
>>>         Explanation:
>>>         -  .x unambiguously refers to the parameter.
>>>
>>> -  Undefined behavior:
>>>
>>>     -
>>>         struct bar { int y; };
>>>         void foo(char p[((struct bar){ .y = .y }).y], int y);
>>>
>>>         Explanation:
>>>         -  Because of shadowing rules, =.y refers to the struct member.
>>>         -  .y=.y means initialize the member with itself (uninitialized use).
>>>         -  (...).y refers to the struct member, since otherwise an rvalue is
>>> not expected there.
>>>
>>> -  Constraint violations:
>>>
>>>     -
>>>         void foo(char (*a)[sizeof *.b], char (*b)[sizeof *.a]);
>>>
>>>         Explanation:
>>>         -  sizeof(*.b): Cannot get size of incomplete type.
>>>         -  sizeof(*.a): Cannot get size of incomplete type.
>>>
>>>     -
>>>         void f(size_t s, int a[sizeof(1) = 1]);
>>>
>>>         Explanation:
>>>         -  Cannot assign to rvalue.
>>>
>>>     -
>>>         void f(size_t s, int a[.s = 1]);
>>>
>>>         Explanation:
>>>         -  Cannot assign to rvalue.
>>>
>>>     -
>>>         void f(size_t s, int a[sizeof(.s)]);
>>>
>>>         Explanation:
>>>         -  sizeof(.s): Cannot get size of incomplete type.
>>>
>>>
>>> Does this idea make sense to you?
>>>
>>>
>>> Cheers,
>>> Alex
>>