From c569c33e875b60f1f53a16d8f801775a8f40f483 Mon Sep 17 00:00:00 2001 From: "Quirin F. Schroll" Date: Sun, 29 Dec 2024 06:52:34 +0100 Subject: [PATCH] Make `toDelegate` safe for function pointers Co-authored-by: Elias Batek <0xEAB@users.noreply.github.com> --- std/functional.d | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/std/functional.d b/std/functional.d index ed807b23a30..1e3074dfeee 100644 --- a/std/functional.d +++ b/std/functional.d @@ -1814,6 +1814,13 @@ if (isCallable!(F)) { return fp; } + else static if (is(F Func == Func*) && is(Func == function) && is(Func Params == __parameters)) + { + return () @trusted + { + return buildDelegate(fp); + }(); + } else static if (is(typeof(&F.opCall) == delegate) || (is(typeof(&F.opCall) V : V*) && is(V == function))) { @@ -1821,6 +1828,28 @@ if (isCallable!(F)) } else { + return buildDelegate(fp); + } +} + +/// +@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) +if (isCallable!(F)) +{ + auto buildDelegate(auto ref F fp) { alias DelType = typeof(&(new DelegateFaker!(F)).doIt); static struct DelegateFields { @@ -1850,21 +1879,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++;