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