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.

Reply via email to