> On Mar 18, 2025, at 12:48 PM, Martin Uecker <uec...@tugraz.at> wrote:
>
> Am Dienstag, dem 18.03.2025 um 09:52 -0700 schrieb Yeoul Na via Gcc:
>>
>>> On Mar 18, 2025, at 12:16 AM, Martin Uecker <uec...@tugraz.at> wrote:
>>>
>>> When xp->ptr is accessed, the size expression
>>> is evaluated and the lvalue which is formed at this point in
>>> time gets the type int(*)[xp->count], similar to how the size
>>> expression of function arguments are evaluated when the
>>> function is entered. The type of this expression
>>> then does not change anymore. You could implement it
>>> by rewriting it to the following.
>>
>> Yes, that’s effectively similar to how the size of bounds annotations work
>> too.
>>
>> Though my question was, VLA types currently don't work this way.
>>
>> The size is evaluated when it’s declared as you all discussed earlier.
>
> this is the case only for automatic variables. For function arguments
> they are evaluated at function entry.
Well, I think saying this way sounds a bit misleading. This works this way
because function parameters are automatic variables of the function and their
declarations are reached at the entry of the function.
And by “only for automatic variables’, then you mean global and static
variables are not or won't be working in the same way as the automatic
variables in the future? For global and static variables, I meant “pointers" to
VLA types.
Also, what about a pointer to pointer to an array? Should it be fixed to be
evaluated at the time of use?
int foo(int len, int (*((*inout_buf)[len])) {
// use *inout_buf
// ...
int new_len = 10;
*out_buf = malloc(new_len); // should it be fixed to be evaluated at the time
of use?
return new_len;
}
>
>> So do you mean you want to fix the current behavior or make the
>
> I think the current behavior is fine, and changing it
> would also be problematic for existing code.
>
>> behavior inconsistent between if they are struct members,
>> indirect pointers vs. local variables like below?
>
> I think the nature of the problem requires that the size
> expression must be evaluated at different time points
> depending on the scenario.
>
> For automatic variables, this is when the declaration is
> reached in the control flow and for function arguments when
> the function is entered. For structure members where the size
> expression refers to other members, they need to be
> evaluated when the member is accessed.
>
>>
>> void test(struct X *xp) {
>> int len = 10;
>> int (*ptr)[len] = malloc(sizeof(int) * len); // (1) int (*ptr)[len] is
>> evaluated here and fixed.
>>
>> xp->count = 100;
>> xp->ptr = malloc(sizeof(int) * 100); // size of xp->ptr is dynamically
>> evaluated with xp->count, hence, this works fine.
>>
>> len = 5; // (2)
>> ptr = malloc(sizeof(int) * len); // size of ptr is still fixed to be (1),
>> so this traps at run time.
>> }
>
> Yes.
I think the fact that the behavior diverges in this subtle way will make things
very confusing. Not sure adding “dot” actually helps that much with the users
comprehending this code. That’s why I was quite skeptical if VLA in C can ever
be evolved to model the size with a struct member safely, given that VLA made a
wrong choice from the beginning. That said this is just my own impression and
whether we can make the usable model this way may need more study.
At least now I understand what is your vision. Thanks.
>
> For GNU C (but not ISO C) there could be size expression in
> the declaration referring to automatic variables.
>
> int foo()
> {
> int n = 1;
> struct {
> char buf[n]; // evaluated when the declaration is reached
> } x;
> };
>
> This is something which can not currently happen for ISO C where
> this can only refer to named constants and where the size is
> evaluated at compile time.
>
> int foo()
> {
> enum { N = 1 };
> struct {
> char buf[N];
> } x;
> }
>
> Still, I think this is another reason why it would be much
> better to have new syntax for this. We also need to restrict
> the size expressions in all three scenarios in different ways.
>
> int foo()
> {
> int n = 1;
> struct {
>
> int m;
> char buf1[n]; // evaluated when the declaration is reached
> char buf2[.m]; // evaluated on access to buf2, restricted syntax
> } x { .m = 10 };
> }
>
>
> Martin
Yeoul