> On Jan 23, 2025, at 13:27, Martin Uecker <[email protected]> wrote:
>
> Am Donnerstag, dem 23.01.2025 um 17:39 +0000 schrieb Qing Zhao:
>>
>>> 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):
>
> I think it could be same, although Joseph uses it with a member access.
>
> One could also use designator syntax (without __self__) and pass a reference
> to the member only (which also seems appropriate for counted_by).
>
> struct foo {
> int z;
> float f;
> }
>
> size_t bar_count(struct foo (*yp)[5][10]);
>
> struct bar {
> char *array __attribute__ ((counted_by (bar_count(&.y))));
> struct foo y[5][10];
> }
>
> size_t bar_count(struct foo (*yp)[5][10])
> {
> return (*yp)[1][3].z +4;
> }
>
So, in the above, “bar_count” is still a function call, right?
Instead passing “__self__” to the function “bar_count”, the above
passed a reference to the member (as &.y) to the function “bar_count”.
>
> I still prefer the version without __self__ and will respond to Michael
> why I think so, but I am also fine *with* __self__. I just think the
> delayed parsing version used in the Apple prototype should be avoided,
> because it is very confusing (and because it needs delayed parsing).
>
>
>>
>>
>> "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?
>
> B does not work, because you can not parse the expression using the
> existing parser because the type of y is unknown.
Okay. I see.
>
> I also do not really like A because I think we should not allow function
> calls, so I tend to favour the version with the cast at the moment.
A little confused here-:) So, your current favor is the following: (i.e, you
mentioned in the beginning of this email):
> size_t bar_count(struct foo (*yp)[5][10]);
>
> struct bar {
> char *array __attribute__ ((counted_by (bar_count(&.y))));
> struct foo y[5][10];
> }
>
> size_t bar_count(struct foo (*yp)[5][10])
> {
> return (*yp)[1][3].z +4;
> }
Or something else?
Qing
>
> Martin
>
>>
>>
>> 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