Skip to content

Commit 262645b

Browse files
0xEABBolpat
andauthored
Make toDelegate safe for function pointers (#10599)
Co-authored-by: Quirin F. Schroll <[email protected]> Co-authored-by: Elias Batek <[email protected]>
1 parent 4c4c37a commit 262645b

File tree

1 file changed

+53
-8
lines changed

1 file changed

+53
-8
lines changed

std/functional.d

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,13 @@ if (isCallable!(F))
18141814
{
18151815
return fp;
18161816
}
1817+
else static if (is(F Func == Func*) && is(Func == function))
1818+
{
1819+
return function(ref F fp) @trusted
1820+
{
1821+
return buildDelegate(fp);
1822+
}(fp);
1823+
}
18171824
else static if (is(typeof(&F.opCall) == delegate)
18181825
|| (is(typeof(&F.opCall) V : V*) && is(V == function)))
18191826
{
@@ -1825,6 +1832,27 @@ if (isCallable!(F))
18251832
}
18261833
else
18271834
{
1835+
static assert(false, "Unsupported type of callable, please open an issue.");
1836+
}
1837+
}
1838+
1839+
///
1840+
@safe unittest
1841+
{
1842+
static int inc(ref uint num) {
1843+
num++;
1844+
return 8675309;
1845+
}
1846+
1847+
uint myNum = 0;
1848+
auto incMyNumDel = toDelegate(&inc);
1849+
auto returnVal = incMyNumDel(myNum);
1850+
assert(myNum == 1);
1851+
}
1852+
1853+
private template buildDelegate(F)
1854+
{
1855+
auto buildDelegate(auto ref F fp) {
18281856
alias DelType = typeof(&(new DelegateFaker!(F)).doIt);
18291857

18301858
static struct DelegateFields {
@@ -1854,21 +1882,22 @@ if (isCallable!(F))
18541882
}
18551883
}
18561884

1857-
///
1858-
@system unittest
1885+
@safe unittest
18591886
{
18601887
static int inc(ref uint num) {
18611888
num++;
18621889
return 8675309;
18631890
}
18641891

1865-
uint myNum = 0;
1866-
auto incMyNumDel = toDelegate(&inc);
1867-
auto returnVal = incMyNumDel(myNum);
1868-
assert(myNum == 1);
1892+
uint myNum = 0x1337;
1893+
struct S1 { int opCall() { inc(myNum); return myNum; } }
1894+
static assert(!is(typeof(&s1.opCall) == delegate));
1895+
S1 s1;
1896+
auto getvals1 = toDelegate(s1);
1897+
assert(getvals1() == 0x1338);
18691898
}
18701899

1871-
@system unittest // not @safe due to toDelegate
1900+
@system unittest
18721901
{
18731902
static int inc(ref uint num) {
18741903
num++;
@@ -1954,7 +1983,7 @@ if (isCallable!(F))
19541983
}
19551984

19561985

1957-
@system unittest
1986+
@safe unittest
19581987
{
19591988
static struct S1 { static void opCall()() { } }
19601989
static struct S2 { static T opCall(T = int)(T x) {return x; } }
@@ -1967,6 +1996,22 @@ if (isCallable!(F))
19671996
assert(toDelegate(i2)(0xBED) == 0xBED);
19681997
}
19691998

1999+
@safe unittest
2000+
{
2001+
static void fun() @system pure nothrow @nogc
2002+
{
2003+
return;
2004+
}
2005+
2006+
auto fn = &fun;
2007+
static assert( is(typeof(fn) == void function() @system pure nothrow @nogc));
2008+
static assert(!is(typeof(fn) == void function() @safe pure nothrow @nogc));
2009+
2010+
auto dg = fn.toDelegate();
2011+
static assert( is(typeof(dg) == void delegate() @system pure nothrow @nogc));
2012+
static assert(!is(typeof(dg) == void delegate() @safe pure nothrow @nogc));
2013+
}
2014+
19702015
/**
19712016
* Passes the fields of a struct as arguments to a function.
19722017
*

0 commit comments

Comments
 (0)