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

Alejandro Colomar
2022-11-13T16:29:03Z

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

SYNOPSIS:

unary-operator: . identifier

DESCRIPTION:

- It is not an lvalue.

- This means sizeof() and _Lengthof() cannot be applied to them.
- 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.

- 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