April 19, 2019
https://issues.dlang.org/show_bug.cgi?id=19812

          Issue ID: 19812
           Summary: Lambda over struct member causes dangling reference to
                    out-of-scope struct
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: hsteoh@quickfur.ath.cx

Code:
------
import std.algorithm : filter, map;
import std.stdio;

struct S {
        bool flag;
        auto method() {
                return [ 1 ].filter!(e => flag);
        }
}

void main() @safe {
        auto s = S(true);
        writeln(s.method);

        auto arr = [ s ];
        writeln(arr[0].method);

        auto mappedArray = arr.map!(e => e.method);
        writeln(mappedArray.front);
        writeln(mappedArray);
}
------

Expected output:

        [1]
        [1]
        [1]
        [[1]]

Actual output:

        [1]
        [1]
        [1]
        [[]]

Changing method() to the following makes the problem go away:
------
        auto method() {
                auto _flag = flag;
                return [ 1 ].filter!(e => _flag);
        }
------

Changing flag to an integer value and printing the value reveals that in the last writeln, the value has been corrupted into a garbage value.

It appears that the lambda incorrectly closes over a temporary copy of the struct (the argument of map as a local variable) that has gone out of scope by the time the lambda is executed. Explicitly copying .flag into a local variable in method() appears to cause it to be allocated on the heap, as it ought to be.

Compiling with -dip25 -dip1000 fails to catch this problem even though main()
is marked @safe.

Expected behaviour: the compiler should either reject this code (at the very least under -dip25 -dip1000, because the lambda carries a reference to a variable past its scope), or it should do the correct thing by copying the closed-over variable into a heap allocation.

--