> 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):
"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 >>>> >>>> >>> >> >