diff --git a/std/parallelism.d b/std/parallelism.d index fadb4c1759d..7525d9b1491 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -884,11 +884,26 @@ identical to the non-@safe case, but safety introduces some restrictions: */ @trusted auto task(F, Args...)(F fun, Args args) -if (is(typeof(fun(args))) && isSafeTask!F) +if (__traits(compiles, () @safe => fun(args)) && isSafeTask!F) { return new Task!(run, F, Args)(fun, args); } +@safe unittest +{ + static struct Oops { + int convert() { + *cast(int*) 0xcafebabe = 0xdeadbeef; + return 0; + } + alias convert this; + } + static void foo(int) @safe {} + + static assert(!__traits(compiles, task(&foo, Oops.init))); + static assert(!__traits(compiles, scopedTask(&foo, Oops.init))); +} + /** These functions allow the creation of `Task` objects on the stack rather than the GC heap. The lifetime of a `Task` created by `scopedTask` @@ -928,7 +943,7 @@ if (is(typeof(delegateOrFp(args))) && !isSafeTask!F) /// Ditto @trusted auto scopedTask(F, Args...)(F fun, Args args) -if (is(typeof(fun(args))) && isSafeTask!F) +if (__traits(compiles, () @safe => fun(args)) && isSafeTask!F) { auto ret = Task!(run, F, Args)(fun, args); ret.isScoped = true;