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; } 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. 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. 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 > > > > > > > > > > > > > > > > > > > >