www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 22498] New: auto ref function with auto ref parameter causes

https://issues.dlang.org/show_bug.cgi?id=22498

          Issue ID: 22498
           Summary: auto ref function with auto ref parameter causes
                    noncopyable payload be cleaned twice
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: critical
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: chalucha gmail.com

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?

--
Nov 09 2021