January 13, 2021
https://issues.dlang.org/show_bug.cgi?id=21546

          Issue ID: 21546
           Summary: ref returning delegate circumvents immutable (@safe
                    won't help)
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: critical
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: qs.il.paperinik@gmail.com

A delegate with return type ref immutable(T) can be used to reassign an
immutable(T) as follows:

alias DGm = ref           int  delegate() @safe;
alias DGi = ref immutable(int) delegate() @safe;

@safe void f()
{
    immutable int i = 0;
    DGi dgi = ref() => i;
    DGm[] dgms = [ dgi ]; // why?
    dgms[0]() = 1;
    assert(i == 1); // fails, because optimization
}

@safe void g()
{
    DGm[] dgms;
    foreach (immutable int i; [0])
    {
        assert(i == 0); // just to be sure
        DGi dgi = ref() => i;
        dgms ~= dgi; // why?
        dgms[0]() = 1;
        assert(i == 1); // passes, meaning immutable i was changed
    }
}

The lines marked with // why? should be rejected by the type system.

--