> On Jan 23, 2025, at 13:27, Martin Uecker <uec...@tugraz.at> wrote:
> 
> Am Donnerstag, dem 23.01.2025 um 17:39 +0000 schrieb Qing Zhao:
>> 
>>> On Jan 22, 2025, at 12:20, Martin Uecker <uec...@tugraz.at> 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 <uec...@tugraz.at> 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 

Reply via email to