Bug 23923 – `this` not captured by lazy expression

Status
NEW
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-05-18T11:46:44Z
Last change time
2024-12-13T19:29:02Z
Keywords
accepts-invalid, wrong-code
Assigned to
No Owner
Creator
Vladimir Panteleev
Moved to GitHub: dmd#18168 →

Comments

Comment #0 by dlang-bugzilla — 2023-05-18T11:46:44Z
////////// test.d ////////// @safe: void delegate() later; void lazyFun(lazy void expr) { later = { expr; }; } class C { void virtualFunc() {} final void run() { lazyFun({ virtualFunc(); }()); } } void main() { auto c = new C; c.run(); later(); } //////////////////////////// This program segfaults. The `this` pointer used by the `virtualFunc` call is gone by the time it is evaluated. I am not sure if this is accepts-invalid or wrong-code. On one hand, the lazy expression does capture regular locals. On the other hand, one would think that `lazy` would imply `scope`, so the implicit reference to `this` (or other locals) would not be allowed.
Comment #1 by dlang-bugzilla — 2023-05-18T12:32:48Z
(In reply to Vladimir Panteleev from comment #0) > so the implicit reference to `this` (or other locals) would not be allowed. so escaping the lazy expression in lazyFun would not be allowed.*
Comment #2 by dlang-bugzilla — 2023-05-18T13:58:40Z
(In reply to Vladimir Panteleev from comment #0) > lazyFun({ > virtualFunc(); > }()); This could simply be: lazyFun(virtualFunc());
Comment #3 by bugzilla — 2024-04-23T06:56:32Z
Lazy functions are implemented as delegates, so to investigate this, redo the lazy function as an explicit delegate. If the behavior is correct, then the fix is to figure out where lazy function checking diverges from delegate checking.
Comment #4 by dlang-bugzilla — 2024-04-23T07:06:44Z
The issue does not occur when lazy is replaced with an explicit delegate. //////////////// test.d //////////////// @safe: void delegate() later; void lazyFun(void delegate() @safe expr) { later = { expr(); }; } class C { void virtualFunc() {} final void run() { lazyFun({ virtualFunc(); }); } } void main() { auto c = new C; c.run(); later(); } ////////////////////////////////////////
Comment #5 by razvan.nitu1305 — 2024-07-15T15:02:31Z
Hmmm, there's seems to be a problem with the creation of the second delegate in the original code (the first delegate is created when virtualFunc() is passed to the lazy parameter). If the delegate is extracted directly, the context pointer is preserved correctly: //@safe: void delegate() later; void lazyFun(lazy void expr) { later = &expr; //later = { expr; }; } class C { void virtualFunc() {} final void run() { lazyFun(virtualFunc()); } } void main() { auto c = new C; c.run(); later(); } However, the code is not safe anymore.
Comment #6 by robert.schadek — 2024-12-13T19:29:02Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18168 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB