> On Jul 28, 2025, at 17:39, Martin Uecker <ma.uec...@gmail.com> wrote:
> 
> Am Montag, dem 28.07.2025 um 20:48 +0000 schrieb Qing Zhao:
>> 
>>> On Jul 28, 2025, at 16:09, Martin Uecker <ma.uec...@gmail.com> wrote:
>>> 
>>> Am Montag, dem 28.07.2025 um 11:18 -0700 schrieb Yeoul Na:
>>>> 
>>>> 
>>>>> On Jul 28, 2025, at 10:27 AM, Qing Zhao <qing.z...@oracle.com> wrote:
>>>>> 
>>>>> 
>>>>> 
>>>>>> On Jul 26, 2025, at 12:43, Yeoul Na <yeoul...@apple.com> wrote:
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Jul 24, 2025, at 3:52 PM, Kees Cook <k...@kernel.org> wrote:
>>>>>>> 
>>>>>>> On Thu, Jul 24, 2025 at 04:26:12PM +0000, Aaron Ballman wrote:
>>>>>>>> Ah, apologies, I wasn't clear. My thinking is: we're (Clang folks)
>>>>>>>> going to want it to work in C++ mode because of shared headers. If it
>>>>>>>> works in C++ mode, then we have to figure out what it means with all
>>>>>>>> the various C++ features that are possible, not just the use cases
>>>>>>> 
>>>>>>> I am most familiar with C, so I may be missing something here, but if
>>>>>>> -fbounds-safety is intended to be C only, then why not just make it
>>>>>>> unrecognized in C++?
>>>>>> 
>>>>>> The bounds safety annotations must also be parsable in C++. While C++ 
>>>>>> can get bounds checking by using std::span instead of raw pointers, 
>>>>>> switching to std::span breaks ABI. Therefore,
>>>>>> in many situations, C++ code must continue to use raw pointers—for 
>>>>>> example, when interoperating with C code by sharing headers with C. In 
>>>>>> such cases, bounds annotations can help close
>>>>>> safety gaps in raw pointers.
>>>>> 
>>>>> -fbound-safety feature was initially proposed as an C extension, So, it’s 
>>>>> natural to make it compatible with C language, not C++. 
>>>>> If C++ also need such a feature, then an extension to C++ is needed too.
>>>>> If a consistent syntax for this feature can satisfy both C and C++,  that 
>>>>> will be ideal.
>>>>> However, if  providing such consistent syntax requires major changes to C 
>>>>> language, 
>>>>> ( a new name lookup scope, and late parsing), it might be a good idea to 
>>>>> provide different syntax for C and C++.
>>>> 
>>>> 
>>>> So the main problem here is when the "same code” will be parsed in both in 
>>>> C and C++, which is quite common in practice.
>>>> 
>>>> Therefore, we need a way to reasonably write code that works both C and 
>>>> C++. 
>>>> 
>>>> From my perspective, that means:
>>>> 
>>>> 1. The same spelling doesn’t “silently" behave differently in C and C++.
>>>> 2. At least the most common use cases (i.e., __counted_by(peer)) should be 
>>>> able to be written the same way in C and C++, without ceremony.
>>>> 
>>>> Here is our compromise proposal that meets these requirements, until we 
>>>> get blessing from the standard for a more elegant solution:
>>>> 
>>>> 1. `__counted_by(member)` keeps working as is: late parsing + name lookup 
>>>> finds the member name first
>>>> 2. `__counted_by_expr(expr)` uses a new syntax (e.g., __self), and is not 
>>>> allowed to use a name that matches the member name without the new syntax 
>>>> even if that would’ve resolved to a
>>>> global variable. Use something like  `__global_ref(id)` to disambiguate. 
>>>> This rule will prevent the confusion where `__counted_by_expr(id)` and 
>>>> `__counted_by(id)` may designate different
>>>> entities.
>>>> 
>>>> Here are the examples:
>>>> 
>>>> Ex 1)
>>>> constexpr int n = 10;
>>>> 
>>>> struct s {
>>>>  int *__counted_by(n) ptr; // resolves to member `n`; which matches the 
>>>> current behavior 
>>>>  int n;
>>>> };
>>>> 
>>>> Ex 2)
>>>> constexpr int n = 10;
>>>> struct s {
>>>>  int *__counted_by_expr(n) ptr; // error: referring to a member name 
>>>> without “__self."
>>>>  int n;
>>>> };
>>>> 
>>>> Ex 3)
>>>> constexpr int n = 10;
>>>> struct s {
>>>>  int *__counted_by_expr(__self.n) ptr; // resolves to member `n`
>>>>  int n;
>>>> };
>>>> 
>>>> 
>>>> Ex 4)
>>>> constexpr int n = 10;
>>>> struct s {
>>>>  int *__counted_by_expr(__self.n + 1) ptr; // resolves to member `n`
>>>>  int n;
>>>> };
>>>> 
>>>> 
>>>> Ex 5)
>>>> constexpr int n = 10;
>>>> struct s {
>>>>  int *__counted_by_expr(__global_ref(n) + 1) ptr; // resolves to global `n`
>>>>  int n;
>>>> };
>>>> 
>>>> 
>>>> Ex 6)
>>>> constexpr int n = 10;
>>>> struct s {
>>>>  int *__counted_by_expr(n + 1) ptr; // resolves to global `n`; okay, no 
>>>> matching member name
>>>> };
>>>> 
>>>> Or in case, people prefer forward declaration inside 
>>>> `__counted_by_expr()`, the similar rule can apply to achieve the same goal.
>>>> 
>>> 
>>> Thank you Yeoul! 
>>> 
>>> I think it is a reasonable compromise.
>> 
>> Yes, I agree. -:)
>> 
>> It adds two new keywords in both C and C++ (__self and __global_ref) to 
>> explicitly mark the scopes for the variables inside the attribute. 
>> will definitely resolve the lookup scope ambiguity issue in both C and C++. 
>> 
>> However, it will not resolve the issue when the counted_by field is declared 
>> After the pointer field. 
>> So, forward declarations is still  needed to resolve this issue, I think.
> 
> Yes, forwards declarations are this simplest solution.
> 
> 
> Another idea I mentioned before is to let __self.N have type 
> int, and then emit an error later if it has  a type that 
> would change the type / meaning of the immediate
> parent expression.

Yes, this is reasonable too.

However, one of the major issue with it is, the user has to change the type 
of  all the counted_by field to “int”. Not sure whether this is easy to do or 
not
for  a large application. 

Qing
> 
> This would allow all of the following:
> 
> struct foo { 
> char * __counted_by_expr(__self.N) buf;
> int N;
> };
> struct foo {
> char * __counted_by_expr(__self.N + 1L) buf;
> long N;
> };
> struct foo {
> char * __counted_by_expr(__self.N * 2) buf;
> int N;
> };
> struct foo {
> char * __counted_by_expr(__self.N + 2) buf;
> char N;
> };
> struct foo {
> char * __counted_by_expr(__self.N + .M) buf;
> int N; int M;
> };
> struct foo {
> char * __counted_by_expr((int)__self.N) buf;
> double N;
> };
> struct foo {
> char * __counted_by_expr(3 * sizeof(__self.buf2)) buf;
> char buf2[5];
> };
> struct foo {
> char * __counted_by_expr(((struct bar *)__self.x)->z) buf; 
> struct bar *x;
> };
> 
> 
> It would *not* allow:
> 
> struct foo {
> char * __counted_by_expr(__self.N + 1) buf;
> long N;
> };
> struct foo {
> char * __counted_by_expr(__self.x->z) buf;
> struct foo *x;
> };
> 
> 
> But in this case you would get an explicit error:
> 
> xyz:13.4: Type of `__self.N' needs to be known.  Did you forget to
> add a cast `(long)__self.N'?
> 
> 
> 
> Martin
> 
> 
> 
> 
> 
> 

Reply via email to