Bug 24024 – cannot pass class this to ref class

Status
RESOLVED
Resolution
WONTFIX
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-07-01T01:04:42Z
Last change time
2024-01-12T21:52:59Z
Keywords
pull
Assigned to
No Owner
Creator
Walter Bright
See also
https://issues.dlang.org/show_bug.cgi?id=13116, https://issues.dlang.org/show_bug.cgi?id=24034, https://issues.dlang.org/show_bug.cgi?id=24035, https://issues.dlang.org/show_bug.cgi?id=24157

Comments

Comment #0 by bugzilla — 2023-07-01T01:04:42Z
class C { void mem() { foo(this); // fails } } void foo(ref C); void test() { C c; foo(c); // passes } ----------- test.d(5): Error: function `test.foo(ref C)` is not callable using argument types `(C)` test.d(5): cannot pass rvalue argument `this` of type `test.C` to parameter `ref C`
Comment #1 by kinke — 2023-07-04T09:44:00Z
This is the behavior I would expect - a class-ref `this` is special and not to be mutated. What if `foo()` sets it to null?
Comment #2 by bugzilla — 2023-07-05T06:44:19Z
Looking into the code, the reason the match fails is because `this` for a class is considered only an rvalue, not an lvalue.
Comment #3 by bugzilla — 2023-07-05T07:10:03Z
https://issues.dlang.org/show_bug.cgi?id=13116 made class `this` not an lvalue.
Comment #4 by default_357-line — 2023-07-05T09:23:31Z
I mean, in the extreme, if this was allowed, shouldn't this happen? class C { void mem() { foo(this); } } void foo(ref C c) { c = null; } C c = new C; c.mem; assert(c is null); And what about if `c` is genuinely an rvalue, such as `C createC(); createC.mem;`?
Comment #5 by bugzilla — 2023-07-05T17:14:48Z
(In reply to FeepingCreature from comment #4) > I mean, in the extreme, if this was allowed, shouldn't this happen? It isn't any different from: class C { static void mem(C c1) { foo(c1); } } void foo(ref C c2) { c2 = null; } C c3 = new C; C.mem(c3); // c1 is a copy of c3 assert(c3 is null); // c1 is set to null, not c3 > And what about if `c` is genuinely an rvalue, such as `C createC(); > createC.mem;`? Rvalues cannot be passed by ref. 13116 created a special case, and like special cases, it works inconsistently with the rest of the semantics.
Comment #6 by default_357-line — 2023-07-05T19:47:38Z
I guess I'm just allergic to ref-passing variables that you cannot see declared anywhere. In your example, C c1 is explicitly declared; in the original example, it's implicitly declared by the method call. IMO, implicitly declared variables should always be rvalues, but I guess that's a lost cause.
Comment #7 by bugzilla — 2023-07-05T20:28:25Z
Consider UFCS and the ability to do a.foo() and foo(a). When `this` behaves differently than a parameter, it generates a corner case with surprise behavior. Early on I spent much care to make the address of a nested function (i.e. a delegate) indistinguishable from the address of a member function. This symmetry and consistency turned out to be a big win. Avoiding special cases as much as possible should pay off for us.
Comment #8 by dlang-bot — 2023-07-06T03:29:16Z
@WalterBright created dlang/dmd pull request #15389 "fix Issue 24024 - cannot pass class this to ref class" fixing this issue: - fix Issue 24024 - cannot pass class this to ref class https://github.com/dlang/dmd/pull/15389
Comment #9 by dlang-bot — 2023-07-06T07:37:06Z
dlang/dmd pull request #15389 "fix Issue 24024 - cannot pass class this to ref class" was merged into master: - 7d9679081f79e94793a13829e3adb54809e2da4e by Walter Bright: fix Issue 24024 - cannot pass class this to ref class https://github.com/dlang/dmd/pull/15389
Comment #10 by nick — 2023-08-02T18:31:05Z
Given that the fix for this caused issue #24034 (which violates @safe and is marked as a regression) and issue #24035 (which could be marked a regression too AIUI), perhaps it should be reverted.
Comment #11 by dlang-bot — 2023-11-01T19:13:39Z
dlang/dmd pull request #15637 "[stable] Revert "fix Issue 24024 - cannot pass class this to ref class"" was merged into stable: - 1fed77b1e597280e91823a47310867e8df91f748 by Martin Kinkelin: Revert "fix Issue 24024 - cannot pass class this to ref class (#15389)" This reverts commit 2ee383b7908a0e2a72eb14ad3e9ca94c64d58a81. Conflicts: compiler/src/dmd/expression.d https://github.com/dlang/dmd/pull/15637
Comment #12 by dlang-bot — 2023-11-01T22:39:25Z
dlang/dmd pull request #15771 "merge stable" was merged into master: - 8a8d03d88a7a17082aca132f1be776f945cdda85 by Martin Kinkelin: [stable] Revert "fix Issue 24024 - cannot pass class this to ref class" (#15637) * Revert "fix Issue 24024 - cannot pass class this to ref class (#15389)" This reverts commit 2ee383b7908a0e2a72eb14ad3e9ca94c64d58a81. Conflicts: compiler/src/dmd/expression.d * Revert "Update C++ headers (#15396)" This reverts commit 3a1e24922d462e5c477fd5753ff46819722310f0. * Add test case for Issue 24157 - [REG2.105] class `this` as lvalue leads to memory corruption https://github.com/dlang/dmd/pull/15771
Comment #13 by ibuclaw — 2023-11-08T06:01:27Z
Reverted.
Comment #14 by petar.p.kirov — 2024-01-12T21:52:59Z
Given the issues the (now reverted) dmd PR (https://github.com/dlang/dmd/pull/15389) caused, I'd err on the side of caution and mark this as won't fix. Just for reference, C# (I tested .NET 8) also rejects treating `this` as an lvalue: ```csharp C c = new C(); c.mem(); class C { public void mem() { foo(ref this); this = new C(); } static void foo(ref C c) { c = null; } } ``` Compilation error (line 8, col 11): Cannot use 'this' as a ref or out value because it is read-only Compilation error (line 9, col 3): Cannot assign to 'this' because it is read-only