Bug 20868 – DIP1000: scope delegate triggers error in unsafe code and it shouldn't

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2020-05-28T05:54:44Z
Last change time
2021-01-15T08:50:09Z
Keywords
pull
Assigned to
No Owner
Creator
Andrej Mitrovic

Comments

Comment #0 by andrej.mitrovich — 2020-05-28T05:54:44Z
----- void scoped (scope void delegate() dg) { static void delegate()[] dgs; // dgs ~= dg; // error nonScoped(dg); // not an error??? } void nonScoped (void delegate() dg) { static void delegate()[] dgs; dgs ~= dg; } void main () { int x; scoped({x = 100;}); } ----- $ dmd -dip1000 test.d > This should be a compile-time error.
Comment #1 by razvan.nitu1305 — 2021-01-11T11:48:26Z
The scope analysis is done only for @safe functions. Annotating scoped and non-scoped with @safe is going to trigger the error: 'scope variable `dg` assigned to non-scope parameter `dg` calling test.nonScoped'. So the actual error is that `dgs ~= dg` triggers an error in unsafe code.
Comment #2 by dlang-bot — 2021-01-11T12:42:10Z
@RazvanN7 created dlang/dmd pull request #12127 "Fix Issue 20868 - DIP1000: scope delegate triggers error in unsafe co…" fixing this issue: - Fix Issue 20868 - DIP1000: scope delegate triggers error in unsafe code and it shouldn't https://github.com/dlang/dmd/pull/12127
Comment #3 by bugzilla — 2021-01-12T10:37:27Z
I'm not sure exactly what the problem is. Is it the // error line, or the // not an error??? line? This should be a compile-time error. Which line?
Comment #4 by razvan.nitu1305 — 2021-01-12T10:39:54Z
Initially, it was `nonScoped(dg)` line that was reported as an error. However, the function is not annotated with `@safe` so I concluded that the actual problem is that the commented line (when uncommented) errors. We need your clarification whether scope analysis should not apply in non-@safe contexts.
Comment #5 by bugzilla — 2021-01-14T08:16:57Z
To be specific, when compiled with -dip1000: void scoped (scope void delegate() dg) { static void delegate()[] dgs; dgs ~= dg; // Error: scope variable `dg` may not be copied into allocated memory } and there is no error without -dip1000. The first thing to do is simplify: void scoped (scope void* p) { static void*[] px; px ~= p; } which exhibits the same behavior. But let's try this: void scoped (scope void* p) { static void* px; px = p; } which generates no error with or without -dip1000. Marking the function with @safe yields: Error: scope variable p is assigned to non-scope px with or without -dip1000. The examples must behave the same way. They don't, so which is right? The array examples are wrong.
Comment #6 by razvan.nitu1305 — 2021-01-14T08:21:04Z
(In reply to Walter Bright from comment #5) > To be specific, when compiled with -dip1000: > > void scoped (scope void delegate() dg) { > static void delegate()[] dgs; > dgs ~= dg; // Error: scope variable `dg` may not be copied into > allocated memory > } > > and there is no error without -dip1000. > > The first thing to do is simplify: > > void scoped (scope void* p) { > static void*[] px; > px ~= p; > } > > which exhibits the same behavior. But let's try this: > > void scoped (scope void* p) { > static void* px; > px = p; > } > > which generates no error with or without -dip1000. Marking the function with > @safe yields: > > Error: scope variable p is assigned to non-scope px > > with or without -dip1000. > > The examples must behave the same way. They don't, so which is right? The > array examples are wrong. So you agree with the PR I made? It essentially makes the error at line `dgs ~= dg;` go away in -dip1000 context.
Comment #7 by qs.il.paperinik — 2021-01-14T16:27:01Z
(In reply to Walter Bright from comment #5) > To be specific, when compiled with -dip1000: > > void scoped (scope void delegate() dg) { > static void delegate()[] dgs; > dgs ~= dg; // Error: scope variable `dg` may not be copied into > allocated memory > } I only find the error message confusing. It should be an error: One cannot assign a scope object to a global state. Local static variables are not at global scope, but are a global state. Allowing that would make `scope` absolutely useless as a guarantee and for optimizations. When the function is called with a lambda, its can be allocated on the stack, because the reference won't "survive" the call. With allowing assignment to local static variables, this is no longer the case.
Comment #8 by razvan.nitu1305 — 2021-01-14T18:27:35Z
(In reply to Bolpat from comment #7) > (In reply to Walter Bright from comment #5) > > To be specific, when compiled with -dip1000: > > > > void scoped (scope void delegate() dg) { > > static void delegate()[] dgs; > > dgs ~= dg; // Error: scope variable `dg` may not be copied into > > allocated memory > > } > > I only find the error message confusing. It should be an error: One cannot > assign a scope object to a global state. Local static variables are not at > global scope, but are a global state. > > Allowing that would make `scope` absolutely useless as a guarantee and for > optimizations. When the function is called with a lambda, its can be > allocated on the stack, because the reference won't "survive" the call. With > allowing assignment to local static variables, this is no longer the case. The DIP and spec say that scope analysis should be done only when dip1000 is enabled and in @safe context. So this would make scope useless in non-@safe could, however, if the function is @safe it would still be an error.
Comment #9 by dlang-bot — 2021-01-15T08:50:09Z
dlang/dmd pull request #12127 "Fix Issue 20868 - DIP1000: scope delegate triggers error in unsafe co…" was merged into master: - 0cd0d4ead58dcda199b65e056c5316138e425054 by RazvanN7: Fix Issue 20868 - DIP1000: scope delegate triggers error in unsafe code and it shouldn't https://github.com/dlang/dmd/pull/12127