[PATCH] Various pages: SYNOPSIS: Use VLA syntax in function parameters
Alejandro Colomar
alx.manpages@gmail.com
Sun Nov 13 19:05:46 GMT 2022
On 11/13/22 17:56, 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?
I've been thinking about keeping the number of passes as low as possible, while
allowing most useful expressions:
Maybe forcing some ordering can help:
- The type of a .initializer is complete after the opening parenthesis of the
function-declarator (if it refers to a parameter) or after the opening brace of
a braced-initializer, if it refers to a struct/union member, except when the
type is a variably-modified type, which will be complete after the closing
parenthesis or brace respectively.
I'm not sure I got the wording precisely, or if I covered all cases (like types
that cannot be completed for other reasons, even after the closing ')' or '}'.
>
>>
>>>>
>>>> - 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)]);
This should actually be valid.
>>>>
>>>> Explanation:
>>>> - sizeof(.s): Cannot get size of incomplete type.
>>>>
>>>>
>>>> Does this idea make sense to you?
>>>>
>>>>
>>>> Cheers,
>>>> Alex
>>>
>>
>
--
<http://www.alejandro-colomar.es/>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20221113/06813a92/attachment-0001.sig>
More information about the Gcc
mailing list