Bug 23891 – [DIP1000] unnamed delegates ignore lifetimes

Status
NEW
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-05-05T15:47:05Z
Last change time
2024-12-13T19:28:33Z
Keywords
accepts-invalid, safe
Assigned to
No Owner
Creator
Bolpat
Moved to GitHub: dmd#20269 →

Comments

Comment #0 by qs.il.paperinik — 2023-05-05T15:47:05Z
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)); } ```
Comment #1 by robert.schadek — 2024-12-13T19:28:33Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20269 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB