Bug 22498 – auto ref function with auto ref parameter causes noncopyable payload be cleaned twice

Status
NEW
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2021-11-09T19:28:09Z
Last change time
2024-12-13T19:19:16Z
Assigned to
No Owner
Creator
Tomáš Chaloupka
Moved to GitHub: dmd#20006 →

Comments

Comment #0 by chalucha — 2021-11-09T19:28:09Z
With a code like ``` import core.lifetime : forward; import core.stdc.stdio; import std.algorithm : move; struct Value(T) { private T storage; this()(auto ref T val) { storage = forward!val; } ref inout(T) get() inout { return storage; } } Value!T value(T)(auto ref T val) { return Value!T(forward!val); } auto ref unwrap(EX)(auto ref EX res) { printf("unwrap()\n"); return res.get(); } struct Foo { int n; @disable this(this); ~this() { printf("~this(%d)\n", n); } } auto gen() { Foo f; f.n = 42; return value(f.move()); } void main() { Foo f; f = gen().unwrap.move; } ``` `unwrap` accepts copy of non copyable `Value!Foo` that results in this output: ``` ~this(0) ~this(0) ~this(0) unwrap() ~this(42) <- this is a copy (that shouldn't exist) being destroyed ~this(0) ~this(42) ``` But it should't compile as output from `gen()` is rvalue. `__traits(isRef, res)` yields false in `unwrap` as expected, same with `isCopyable!(Value!Foo)`. Or is NRVO working even when return value is passed as a value to the `unwrap`? But then why wouldn't unwrap.move() cause the payload to be reset? And is it ok to ref being returned from `unwrap` when it's from local value parameter?
Comment #1 by chalucha — 2021-11-09T19:37:52Z
I've found possible workaround. ``` auto ref unwrap(EX)(auto ref EX res) { static if (__traits(isRef, res)) { printf("unwrap(ref)\n"); return res.get(); } else { printf("unwrap(val)\n"); auto ret = res.get().move(); // < NRVO return ret; } } ``` Then with `Foo f = gen(42).unwrap;` It otputs: ``` ~this(0) ~this(0) ~this(0) unwrap(val) ~this(0) ~this(42) ``` But I'm still puzzled about what's wrong with the original one.
Comment #2 by mail — 2021-11-12T14:17:25Z
As have I commented on the newsgroup https://forum.dlang.org/post/[email protected] " It doesn't copy. It just destructs the same object twice... Ouch. Change the destructor to ~this() { printf("~this(%d)\n", n); n = 12; } and you'll see. "
Comment #3 by robert.schadek — 2024-12-13T19:19:16Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20006 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB