https://issues.dlang.org/show_bug.cgi?id=14162
--- Comment #1 from Kenji Hara <[email protected]> --- I also noticed this difference recently. But I think the safe violation error in the first case is incorrect. (In reply to Walter Bright from comment #0) > Consider the code: > --------- > @trusted auto trusted(alias fun)() { return fun(); } > > @safe void func() > { > char[3] s = "abc"; > string t = trusted!(() => cast(string)(s[])); > //test.d(6): Error: cast from char[] to string not allowed in safe code > assert(t == "abc"); > } > > @safe void test() { func(); } > ---------- > The error is correct because the lambda is evaluated in the context of @safe > func(), not in the context of @trusted trusted(). But turn func() into a > template function: Normally a nested function inherits @safe attribute from the enclosing function. But lambda function attribute should inferred from the body statement. Currently the inherited @safe is preferred, but as I'll explain later, it's not good behavior. > --------- > @trusted auto trusted(alias fun)() { return fun(); } > > @safe void func()() // only change is add () to make it a template > { > char[3] s = "abc"; > string t = trusted!(() => cast(string)(s[])); > assert(t == "abc"); > } > > @safe void test() { func(); } > ---------- > And it now incorrectly compiles without error. Inside template function, the attribute inference result is priority than the inherited @safe on the lambda. Then the lambda is marked as @system. ======== The latter case is at least intended behavior. See FuncDeclaration::semantic() in func.c: if (sc->func) { /* If the parent is @safe, then this function defaults to safe too. */ if (tf->trust == TRUSTdefault) { FuncDeclaration *fd = sc->func; /* If the parent's @safe-ty is inferred, then this function's @safe-ty needs * to be inferred first. * If this function's @safe-ty is inferred, then it needs to be infeerd first. * (local template function inside @safe function can be inferred to @system). */ if (fd->isSafeBypassingInference() && !isInstantiated()) tf->trust = TRUSTsafe; // default to @safe } The behavior is necessary to support a lambda idiom. For example: struct S { this(this) {} } import std.traits: isSafe; void foo(T)() @safe { static if (isSafe!((ref T t){ T t2 = t; })) { pragma(msg, true); } else { pragma(msg, false); } } void main() { foo!S(); } Lambda is used to check whether the T's copy operation is really safe. If the lambda inherits @safe attribute from the enclosing foo, unsafe T copy will cause safe violation error so the check won't work. And more, D allows to declare @system function inside @safe function. void foo() @safe { static void bar() @system { } } >From the fact, even if a lambda inside @safe function is deduced to @system, it won't cause safety violation. Only when the lambda is actually called in the @safe function, it should be an error. void foo() @safe { auto dg = { return systemCall() }; // should be OK auto ret = { return systemCall() }(); // system cannot call in safe function } As a conclusion, I think the former case should be fixed, and the behavior should be same with the latter. --
