> On Jan 22, 2025, at 12:20, Martin Uecker <[email protected]> wrote:
>
> Am Mittwoch, dem 22.01.2025 um 18:11 +0100 schrieb Martin Uecker:
>> Am Mittwoch, dem 22.01.2025 um 16:37 +0000 schrieb Qing Zhao:
>>>
>>>> On Jan 22, 2025, at 11:22, Martin Uecker <[email protected]> wrote:
>>>>
>>>>
>>>> Hello Michael,
>>>>
>>>> Am Mittwoch, dem 22.01.2025 um 16:54 +0100 schrieb Michael Matz:
>>>>> On Wed, 22 Jan 2025, Martin Uecker wrote:
>>>>>
>>>>>>>> So you do not need to look further. But maybe I am missing something
>>>>>>>> else.
>>>>>>>
>>>>>>> Like ...
>>>>>>>
>>>>>>>>> Note further that you may have '{ .y[1][3].z }', which is still not a
>>>>>>>>> designation, but an expression under your proposal, whereas
>>>>>>>>> '{ .y[1][3].z = 1 }' would remain a designation. This shows that you
>>>>>>>>> now need arbitrary look-ahead to disambiguate the two. A Very Bad
>>>>>>>>> Idea.
>>>>>>>
>>>>>>> ... this?
>>>>>>
>>>>>> In .y[1][3].z after .y you can decide whether y is a member of the
>>>>>> struct being initialized. If it is, it is a designator and if not
>>>>>> it must be an expression.
>>>>>
>>>>> If y is not a member it must be an expression, true. But if it's a
>>>>> member
>>>>> you don't know, it may be a designation or an expression.
>>>>
>>>> In an initializer I know all the members.
>>>
>>> I am not familiar with the parser, so, I am a little confused about the
>>> following:
>>>
>>> Suppose we have:
>>>
>>> struct foo {
>>> int z;
>>> float f;
>>> }
>>>
>>> struct bar {
>>> char *array __attribute__ ((counted_by (.y[1][3].z + 4)));
>>> struct foo y[5][10];
>>> }
>>>
>>> So, in the above, when parsing the above expression inside counted_by, can
>>> the
>>> current parser be easily to be extended to parse it?
>>
>> No, I don't think this can be done easily. The issue is that you do
>> not know the declaration for y because it hasn't been parsed yet.
>>
>> If you forward reference some struct member, you have several
>> possibilities:
>>
>> - use it only in limited contexts where you do not need to know
>> the type (e.g. this works for goto labels) or for a basic
>> counted_by attribute that only takes an identifier as we have it now.
>>
>> - simply assume it has a certain type (size_t as is proposed in the
>> WG14 paper Joseph mentioned) and fail later if it does not.
>>
>>
>> Both options would rule the construct above (but there could be
>> workarounds).
>
> One of the workarounds could be to instead call a function (which could
> be inlined later) and that function takes a pointer to the member.
> Then it does not need to now anything about any member, e.g.:
>
>
> struct foo {
> int z;
> float f;
> }
>
> size_t bar_count(struct bar *);
>
> struct bar {
> char *array __attribute__ ((counted_by (bar_count(__self__))));
> struct foo y[5][10];
> }
>
> size_t bar_count(struct bar *p)
> {
> return p->y[1][3].z +4;
> }
>
>
In this workaround, we also need to introduce a new key word “__self__”,
Is this the same as the “__self__” Joseph mentioned in a previous email
(I copied Joseph’s word in below for easy reference):
"But if you want a less-limited feature that allows for expressions, you
need some syntax for referring to a structure member that's not ambiguous.
For example, some new notation such as __self__.len1 to refer to a member
of the closest enclosing structure definition when in counted_by (while
being invalid except in counted_by inside a structure definition).
(That's just one example of how you might define syntax that avoids
ambiguity.)”
So, for the following two approaches to represent expression as argument of
“counted_by” attribute:
A. Allowing function call as the argument, and the new key word “__self__” is
passed to this function to
reference members of the closest enclosing structure.
> struct bar {
> char *array __attribute__ ((counted_by (bar_count(__self__))));
> struct foo y[5][10];
> }
B. Allowing expression with __self__ as the argument:
> struct bar {
> char *array __attribute__ ((counted_by (__self__.y[1][3].z + 4)));
> struct foo y[5][10];
> }
My question:
Which is better, A or B?
Thanks a lot for your help.
Qing
>
>> Other alternatives are:
>>
>> - you have same kind of forward declaration (as we have for
>> parameters as GNU extension). In the context of C, this is the
>> cleanest solution but either requires forward declaring the
>> full struct (which can be done in C23) or new syntax for only
>> forward declaring the member.
>
> A possible C23 workaround could be:
>
> struct foo {
> int z;
> float f;
> }
>
> struct bar {
> char *array __attribute__ ((counted_by (*)));
> // star indicates missing size exppression
> struct foo y[5][10];
> }
>
> struct bar { // redeclare with known size
> char *array __attribute__ ((counted_by (.y[1][3].z + 4)));
> struct foo y[5][10];
> }
>
>
> Martin
>
>
>>
>> - or you use some delayed parsing where you store away the tokens
>> and parse it later when all structure members are done. I think
>> this is a highly problematic approach for a variety of reasons.
>>
>>
>> Martin
>>
>>
>>>
>>> thanks.
>>>
>>> Qing
>>>>
>>>> Martin
>>>>
>>>>
>>>
>>
>