On Thu, 4 Sep 2025, Richard Biener wrote: > On Thu, Sep 4, 2025 at 10:27 AM Jonathan Wakely <jwak...@redhat.com> wrote: > > > > On Thu, 4 Sept 2025 at 08:26, Richard Biener <rguent...@suse.de> wrote: > > > > > > On Wed, 3 Sep 2025, Jakub Jelinek wrote: > > > > > > > On Wed, Sep 03, 2025 at 06:41:08PM +0200, Richard Biener wrote: > > > > > > I'd be worried about C++23 deducing this, but e.g. > > > > > > struct S; > > > > > > extern S t; > > > > > > struct S > > > > > > { > > > > > > void foo (this S *p, int x); > > > > > > int s; > > > > > > }; > > > > > > void S::foo (this S *p, int x) > > > > > > { > > > > > > p->s += x; > > > > > > p = &t; > > > > > > p->s += x; > > > > > > } > > > > > > > > > > Huh, you can assign to the ‚this‘ parameter? I’ve read it can be a > > > > > non-pointer. But assigning to it makes the non-SSA match broken. > > > > > What’s the use of such assignment? > > > > > Is p = nullptr valid? Or delete p;? > > > > > > > > Clearly both g++ and clang++ compile this (but I'm then getting errors > > > > when trying to call it as t.foo (42); or ptr->foo (42)). > > > > Guess normally for deducing this the argument is this S &p instead and > > > > references can't be changed. But normal this in methods is actually > > > > a pointer and keyword such that one can't change it either. > > > > Or in some tests it is this S and so passed by value. That then can > > > > be called as t.foo (42). > > > > > > I've skimmed through the paper for the feature and found no wording > > > constraining assignment but also no example doing it ... > > > > > > We also accept > > > > > > struct B {}; > > > struct S > > > { > > > void foo (this B *p, int x); > > > int s; > > > }; > > > extern S t; > > > void S::foo (this B *p, int x) > > > { > > > } > > > > > > though I'm not sure you'd ever be able to call this? > > > > You can if S has an implicit conversion to B* > > > > struct B {}; > > struct S > > { > > void foo (this B *p, int x); > > int s; > > operator B*() { return &b; } > > B b; > > }; > > extern S t; > > void S::foo (this B *p, int x) > > { > > } > > > > int main() > > { > > S s; > > s.foo(1); > > } > > > > > > > > > int main() { B b; b.foo (1); } > > > > > > is rejected obviously, so is b.S::foo (1). I think this would > > > warrant a diagnostic at least. Maybe there's a trick to make > > > name lookup succeed though? > > > > > > That said, the invocation syntax suggests that the 'this' object > > > must be valid, the question is whether it's constrained by the > > > type of the formal argument only or by the class type > > > (TYPE_METHOD_BASETYPE if it were a method). > > > > Yes, it is. You can't call Foo::mem on an object that isn't a Foo or a > > type derived from Foo. > > > > > That said, assigning > > > to the this parameter adds a dataflow problem, easy for the SSA > > > side but impossible to resolve while in GENERIC - this makes > > > it necessary to perform EH pruning during SSA rewrite. > > > > > > That said, it's odd that the proposed "just alternative syntax" > > > produces a non-method type and also allows assigning to 'this'. > > > > It's not 'this' though! It's not a method, it's a static member > > function, so there is no implicit 'this' pointer. The parameter is > > declared as 'this S' or 'this B' but that's just a token that says > > the function uses the new syntax, it doesn't mean that the parameter > > *is* the 'this' pointer. > > Hmm, but the paper explicitly says it's _not_ a static member function > which to me suggests that the 'this' marked parameter must bind to > a valid object (of the declared type then, I guess). But all these details > seem to be absent from the paper ... > > So I hope > > struct S > { > void foo (this S *); > int i; > }; > > ((S *)0)->foo (); > char c; > ((S *)&c)->foo (); > > are both invalid, aka invoking UB.
To somewhat answer myself the fact that &S::foo is a regular function pointer that can of course the be called like (&S::foo)((S *)0); this _might_ suggest the parameter marked as 'this' doesn't necessarily bind to an object of the declared type. While the paper suggests that the simple non-template struct S { void foo (this S *); }; is merely an alternate syntax to struct { void foo (); }; it more and more looks like it isn't. But who knows ... Richard.