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