May 05, 2023 [Issue 23891] New: [DIP1000] delegate sometimes ignores lifetimes | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=23891 Issue ID: 23891 Summary: [DIP1000] delegate sometimes ignores lifetimes Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: major Priority: P1 Component: dmd Assignee: nobody@puremagic.com Reporter: qs.il.paperinik@gmail.com It seems that when a delegate is invoked, lifetime checks are not done, unless the delegate is directly named. (Usually, that is the case when the delegate is an rvalue, but if an expression returns a delegate by reference, which makes it an lvalue, lifetime checks are not done. This does not apply to function pointers, function pointers work as expected, including those returned by a delegate. Here are some test cases that demonstrate the claims: ```d struct S { int value; ref int member(int x) return @safe => value; } ref int func(return ref S s) @safe => s.member(0); // THOSE FAIL (AND SHOULD) ref int h1(ref S s) @safe => return func(s); ref int h2(ref S s) @safe => return (&func)(s); ref int h3(ref S s) @safe { static f() => &func; return f()(s); // rvalue function pointer alias Func = ref int function(return ref S s) @safe; alias F = Func function() pure nothrow @nogc @safe; static assert(is(typeof(&f) == F)); } ref int h4(ref S s) @safe { auto fptr = &func; ref dg() => fptr; return dg()(s); // unnamed lvalue function pointer alias Func = ref int function(return ref S s) @safe; alias DG = ref Func delegate() pure nothrow @nogc @safe; static assert(is(typeof(&dg) == DG)); } // THOSE FAIL (AND SHOULD) ref int f1(ref S s) @safe => s.member(0); ref int f2(ref S s) @safe => (__traits(child, s, S.member))(0); ref int f3(ref S s) @safe { auto dg = &s.member; return dg(0); } ref int f4(ref S s) @safe { auto dg = &__traits(child, s, S.member); return dg(0); } ref int f5(ref S s) @safe { static f(ref S s) => &s.member; auto dg = f(s); return dg(0); // Note: dg is an lvalue delegate (cf. g4) } // THOSE PASS AND SHOULD NOT ref int g1(ref S s) @safe => (&s.member)(0); ref int g2(ref S s) @safe => (&__traits(child, s, S.member))(0); ref int g3(ref S s) @safe { auto dg = &s.member; auto f = ref () => dg; // f() is not an rvalue: static assert(__traits(compiles, f() = null)); return f()(0); } ref int g4(ref S s) @safe { static f(ref S s) => &s.member; return f(s)(0); // Note: f(s) is an rvalue delegate // f(s) is of a delegate type that has "return" on it: alias DG = ref int delegate(int x) return @safe; static assert(is(typeof(f(s)) == DG)); // f is of type "function that returns DG": alias F = DG function(ref S s) pure nothrow @nogc @safe; static assert(is(typeof(&f) == F)); } ``` -- |
Copyright © 1999-2021 by the D Language Foundation