On 10 Mar 2025, at 15:34, Martin Uecker wrote: > Am Montag, dem 10.03.2025 um 15:00 -0400 schrieb John McCall: >> That said, my preference is still to just give preference to the field name, >> which sidesteps any need for disambiguation syntax and avoids this whole >> problem where structs can be broken by just adding a global variable that >> happens to collide with a field. > > I don't think it is a good idea when the 'n' in 'buf' refers to the > previous global 'n' coming before and the 'n' in attribute > refers to a member 'n' coming later in the following example.
I agree. I think compilers ought to diagnose this with a warning, and arguably it should be invalid under the standard. (It would be very easy to do this; you just keep a set of global declarations referenced by expressions within the struct body and diagnose if any of them collide with fields when the body is complete. That is not a particularly expensive thing to track, most importantly because the number of declarations referenced by expressions in a struct body is modally zero.) Fortunately, this sort of thing is largely theoretical in actual code today. Unfortunately, it is not even slightly theoretical with bounds-safety attributes. > And neither global names nor struct members may always be under > the control of the programmer. A programmer adding an attribute to a struct field can certainly declare a new global constant immediately before the struct. > Also that simply bringing > a new identifier into scope can break code elsewhere worries me. Yes, but this is only a problem if we diagnose an ambiguity. There is no such problem with just preferring a struct field, unless you’re equally concerned about shadowing whenever you create a local variable. > Finally, the following does not even compile in C++. > > struct foo { > char buf[n]; > const static int n = 2; > }; And I am not suggesting that it should. Anything that would change the type of a declaration really has to continue to be processed immediately. But code being invalid does not create inconsistency. Non-constant array bounds are invalid in structs, but that is not inconsistent, it’s a limitation in expressivity. What’s important is that code be consistently interpreted everywhere it is valid. > While the next example is also ok in C++. > > constexpr int n = 2; > > struct foo { > char buf[n]; > }; > > With both declarations of 'n' the example has UB in C++. > So I am not convinced the proposed rules make a lot > of sense for C++ either. If C required a diagnostic in your first example, it would actually put a fair amount of pressure on the C++ committee to get rid of this spurious UB rule. > I still think one could use designator syntax, i.e. '.n', which > would be clearer and intuitive for both C and C++ programmers. This doesn’t really solve the ambiguity problem. If n is a field name, a programmer who writes __counted_by(n) almost certainly means to name the field. “The proper syntax is .n” is the cause of the bug, not its solution. John.