From 1f20e1afebaad4604bd5e96904ca90146e3b33c6 Mon Sep 17 00:00:00 2001 From: "Quirin F. Schroll" Date: Tue, 20 Jun 2023 17:32:36 +0200 Subject: [PATCH 1/3] Make `toDelegate` safe for function pointers --- std/functional.d | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/std/functional.d b/std/functional.d index 588a9c8a547..844e70cca78 100644 --- a/std/functional.d +++ b/std/functional.d @@ -1717,6 +1717,17 @@ if (isCallable!(F)) { return fp; } + else static if (is(F Func == Func*) && is(Func == function) && is(Func Params == __parameters)) + { + alias dg = delegate(Params params) const => F.init(params); + typeof(dg) result; // inlining `dg` infers attributes incorrectly + () @trusted + { + // assigning funcptr is @system, but it’s safe here because `fp` needs no context + result.funcptr = cast(typeof(result.funcptr)) fp; + }(); + return result; + } else static if (is(typeof(&F.opCall) == delegate) || (is(typeof(&F.opCall) V : V*) && is(V == function))) { @@ -1754,7 +1765,7 @@ if (isCallable!(F)) } /// -@system unittest +@safe unittest { static int inc(ref uint num) { num++; @@ -1767,7 +1778,7 @@ if (isCallable!(F)) assert(myNum == 1); } -@system unittest // not @safe due to toDelegate +@system unittest { static int inc(ref uint num) { num++; From 7394672ce19f0a80b8a8c3f44c8d8ad310fa4929 Mon Sep 17 00:00:00 2001 From: "Quirin F. Schroll" Date: Wed, 21 Jun 2023 10:24:30 +0200 Subject: [PATCH 2/3] Fix issue 18171 --- std/functional.d | 1 - 1 file changed, 1 deletion(-) diff --git a/std/functional.d b/std/functional.d index 844e70cca78..2acde9e0299 100644 --- a/std/functional.d +++ b/std/functional.d @@ -1706,7 +1706,6 @@ private struct DelegateFaker(F) * * BUGS: * $(UL - * $(LI Does not work with `@safe` functions.) * $(LI Ignores C-style / D-style variadic arguments.) * ) */ From 6e2d38fce9d079cb00ed5b7d5c96dd995f888c74 Mon Sep 17 00:00:00 2001 From: "Quirin F. Schroll" Date: Wed, 21 Jun 2023 12:16:21 +0200 Subject: [PATCH 3/3] Respect linkage --- std/functional.d | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/std/functional.d b/std/functional.d index 2acde9e0299..ba7b4f9d9d3 100644 --- a/std/functional.d +++ b/std/functional.d @@ -1718,8 +1718,16 @@ if (isCallable!(F)) } else static if (is(F Func == Func*) && is(Func == function) && is(Func Params == __parameters)) { - alias dg = delegate(Params params) const => F.init(params); - typeof(dg) result; // inlining `dg` infers attributes incorrectly + // https://issues.dlang.org/show_bug.cgi?id=24007 - cannot specify linkage on function literal: + //alias dg = delegate(Params params) const => F.init(params); + //typeof(dg) result; + // Workaround: + struct S + { + mixin("extern(", __traits(getLinkage, fp), ") auto ref dg(Params params) const => F.init(params);"); + } + typeof(&S().dg) result; // inlining `dg` infers attributes incorrectly + () @trusted { // assigning funcptr is @system, but it’s safe here because `fp` needs no context @@ -1734,7 +1742,7 @@ if (isCallable!(F)) } else { - alias DelType = typeof(&(new DelegateFaker!(F)).doIt); + alias DelType = typeof(&(new DelegateFaker!F).doIt); static struct DelegateFields { union { @@ -1755,7 +1763,7 @@ if (isCallable!(F)) df.contextPtr = cast(void*) fp; - DelegateFaker!(F) dummy; + DelegateFaker!F dummy; auto dummyDel = &dummy.doIt; df.funcPtr = dummyDel.funcptr;