Skip to content

Commit

Permalink
Make toDelegate safe for function pointers (#10599)
Browse files Browse the repository at this point in the history
Co-authored-by: Quirin F. Schroll <[email protected]>
Co-authored-by: Elias Batek <[email protected]>
  • Loading branch information
3 people authored Dec 30, 2024
1 parent 4c4c37a commit 262645b
Showing 1 changed file with 53 additions and 8 deletions.
61 changes: 53 additions & 8 deletions std/functional.d
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,13 @@ if (isCallable!(F))
{
return fp;
}
else static if (is(F Func == Func*) && is(Func == function))
{
return function(ref F fp) @trusted
{
return buildDelegate(fp);
}(fp);
}
else static if (is(typeof(&F.opCall) == delegate)
|| (is(typeof(&F.opCall) V : V*) && is(V == function)))
{
Expand All @@ -1825,6 +1832,27 @@ if (isCallable!(F))
}
else
{
static assert(false, "Unsupported type of callable, please open an issue.");
}
}

///
@safe unittest
{
static int inc(ref uint num) {
num++;
return 8675309;
}

uint myNum = 0;
auto incMyNumDel = toDelegate(&inc);
auto returnVal = incMyNumDel(myNum);
assert(myNum == 1);
}

private template buildDelegate(F)
{
auto buildDelegate(auto ref F fp) {
alias DelType = typeof(&(new DelegateFaker!(F)).doIt);

static struct DelegateFields {
Expand Down Expand Up @@ -1854,21 +1882,22 @@ if (isCallable!(F))
}
}

///
@system unittest
@safe unittest
{
static int inc(ref uint num) {
num++;
return 8675309;
}

uint myNum = 0;
auto incMyNumDel = toDelegate(&inc);
auto returnVal = incMyNumDel(myNum);
assert(myNum == 1);
uint myNum = 0x1337;
struct S1 { int opCall() { inc(myNum); return myNum; } }
static assert(!is(typeof(&s1.opCall) == delegate));
S1 s1;
auto getvals1 = toDelegate(s1);
assert(getvals1() == 0x1338);
}

@system unittest // not @safe due to toDelegate
@system unittest
{
static int inc(ref uint num) {
num++;
Expand Down Expand Up @@ -1954,7 +1983,7 @@ if (isCallable!(F))
}


@system unittest
@safe unittest
{
static struct S1 { static void opCall()() { } }
static struct S2 { static T opCall(T = int)(T x) {return x; } }
Expand All @@ -1967,6 +1996,22 @@ if (isCallable!(F))
assert(toDelegate(i2)(0xBED) == 0xBED);
}

@safe unittest
{
static void fun() @system pure nothrow @nogc
{
return;
}

auto fn = &fun;
static assert( is(typeof(fn) == void function() @system pure nothrow @nogc));
static assert(!is(typeof(fn) == void function() @safe pure nothrow @nogc));

auto dg = fn.toDelegate();
static assert( is(typeof(dg) == void delegate() @system pure nothrow @nogc));
static assert(!is(typeof(dg) == void delegate() @safe pure nothrow @nogc));
}

/**
* Passes the fields of a struct as arguments to a function.
*
Expand Down

0 comments on commit 262645b

Please sign in to comment.