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

Martin Uecker
2022-11-12T15:57:01Z

Am Samstag, den 12.11.2022, 14:54 +0000 schrieb Joseph Myers:
> On Sat, 12 Nov 2022, Alejandro Colomar via Gcc wrote:
>
> > Since it's to be used as an rvalue, not as a lvalue, I guess a
> > postfix-expression wouldn't be the right one.
>
> Several forms of postfix-expression are only rvalues.
>
> > > (with a special rule about how the identifier is interpreted, different
> > > from the normal scope rules)? If so, then ".a = 1" could either match
> > > assignment-expression directly (assigning to the postfix-expression ".a").
> >
> > No, assigning to a function parameter from within another parameter
> > declaration wouldn't make sense. They should be readonly. Side effects
> > should be forbidden, I think.
>
> Such assignments are already allowed. In a function definition, the side
> effects (including in size expressions for array parameters adjusted to
> pointers) take place before entry to the function body.
>
> And, in any case, if you did have a constraint disallowing such
> assignments, it wouldn't suffice for syntactic disambiguation (see the
> previous point I made about that; I have some rough notes towards a WG14
> paper on syntactic disambiguation, but haven't converted them into a
> coherent paper).

My idea was to only allow

array-declarator : direct-declarator [ . identifier ]

and only for parameter (not nested inside structs declared
in parameter list) as a first step because it seems this
would exclude all difficult cases.

But if we need to allow more complicated expressions, then
it starts getting more complicated.

One could could allow more generic expressions, and
specify that the .identifier refers to a
parameter in
the nearest lexically enclosing parameter list or
struct/union.

Then

void foo(struct bar { int x; char c[.x] } a, int x);

would not be allowed (which is good because then we
could later use the syntax also inside structs). If
we apply scoping rules, the following would work:

struct bar { int y; };
void foo(char p[((struct bar){ .y = .x }).y], int x);

But not:

struct bar { int y; };
void foo(char p[((struct bar){ .y = .y }).y], int y);

But there are not only syntactical problems, because
also the type of the parameter might become relevant
and then you can get circular dependencies:

void foo(char (*a)[sizeof *.b], char (*b)[sizeof *.a]);

I am not sure what would the best way to fix it. One
could specifiy that parameters referred to by
the .identifer syntax must of some integer type and
that the sub-expression .identifer is always
converted to a 'size_t'.

Maybe one should also add a constraint that all new
type length expressions, i.e. using the syntax,
can not have side effects. Or even that they follow
all the rules of integer constant expressions with
the fictitious assumption that all . identifer
sub-expressions are integer constant expressions.
The rationale being that this would facilitate
compile time reasoning about length expressions.

Martin