Thread overview
[Issue 17764] [scope][DIP1000] Escape checker defeated by composition transformations
Aug 19, 2017
ZombineDev
Aug 27, 2017
Walter Bright
Jan 18, 2018
Carsten Blüggel
Mar 11, 2018
Walter Bright
Jun 09, 2019
ag0aep6g
Mar 21, 2020
Walter Bright
Jul 28, 2022
Walter Bright
Jul 28, 2022
Walter Bright
Jul 28, 2022
Walter Bright
Aug 12, 2022
Walter Bright
August 19, 2017
https://issues.dlang.org/show_bug.cgi?id=17764

ZombineDev <petar.p.kirov@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |accepts-invalid,
                   |                            |rejects-valid, safe

--- Comment #1 from ZombineDev <petar.p.kirov@gmail.com> ---
Typo: the last lines were meant to be:

$ dmd -dip1000 scope_bug2.d
$ echo $?
0

$ dmd --version
DMD64 D Compiler v2.076.0-b1-master-32bb4ed

--
August 27, 2017
https://issues.dlang.org/show_bug.cgi?id=17764

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla@digitalmars.com

--- Comment #2 from Walter Bright <bugzilla@digitalmars.com> ---
Starting with this one:

> void use0x2(scope char[]* arr)
> {
>     global = *arr; // NG - accepts invalid
> }

`scope` is not transitive. It applies to the 'head' only. `*arr` is no longer the head, and `scope` doesn't apply to it. A casual look at the rest of the cases shows similar.

If you would please filter out all the cases of more than one indirection, I can look at the rest.

--
January 18, 2018
https://issues.dlang.org/show_bug.cgi?id=17764

Carsten Blüggel <chilli@posteo.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |chilli@posteo.net

--
March 11, 2018
https://issues.dlang.org/show_bug.cgi?id=17764

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |INVALID

--- Comment #3 from Walter Bright <bugzilla@digitalmars.com> ---
The following remain:

---
@safe:
struct Context0x0 { char[]       str; }

struct Parent0x1 { Context0x0      c; }
struct Parent0x2 { Context0x0[1] csa; }
struct Parent0x3 { Context0x0[]  csl; }
struct Parent0x4 { Context0x0*    cp; }

struct Parent0x5 { Parent0x1      p1; }
struct Parent0x6 { Parent0x5      p5; }
struct Parent0x7 { Parent0x6      p6; }

struct Parent0x8 { Parent0x2[1]*  p2; }
struct Parent0x9 { Parent0x8[1]   p8; }
struct Parent0xA { Parent0x9[1]   p9; }

struct Parent0xB { Parent0x4*     p4; }
struct Parent0xC { Parent0xB*     pb; }
struct Parent0xD { Parent0xC*     pc; }

char[] global;

void use0x2(scope char[]* arr)
{
    global = *arr; // NG - accepts invalid
}

void use0x9(scope ref Parent0x4 p)
{
    global = p.cp.str; // NG - accepts invalid
}

void use0xB(scope ref Parent0xA p)
{
    global = (*p.p9[0].p8[0].p2)[0].csa[0].str; // NG - accepts invalid
}

void use0xC(scope ref Parent0xD p)
{
    global = p.pc.pb.p4.cp.str; // NG - accepts invalid
}
---

All of them are instances of transitive scope, but scope is not transitive. Not compiler bugs.

--
June 09, 2019
https://issues.dlang.org/show_bug.cgi?id=17764

ag0aep6g <ag0aep6g@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
                 CC|                            |ag0aep6g@gmail.com
         Resolution|INVALID                     |---

--- Comment #4 from ag0aep6g <ag0aep6g@gmail.com> ---
(In reply to Walter Bright from comment #3)
> All of them are instances of transitive scope, but scope is not transitive. Not compiler bugs.

Reopening.

I don't know if this report shows a problem with `scope` in particular, but it does show holes in @safe. We can't have a global that points to stack memory in @safe code.

If @safe works as designed here, you need to revisit the design, because it's insufficient.

Here's a single example based on use0x5, modified to show more blatantly that safety is violated:

----
int** global;
immutable int imm;
static this() { imm = 42; }

void main() @safe
{
    f(); /* `global` now points to the stack. Uh-oh. */
    stomp(); /* `*global` now points to `imm`. */
    **global = 13; /* Overwrites `imm`. */
    assert(imm == 42);
        /* Fails. We've (accidentally) mutated an immutable int. */
}

void f() @safe
{
    int* buf;
    static struct Context0x0 { int** str; }
    Context0x0[1] c = Context0x0(&buf);
    global = c[0].str; /* This should be rejected. */
}

void stomp() @safe
{
    immutable int*[4] x = &imm;
}
----

Some of the other variations also seem to boil down to this. Maybe all of them do.

--
March 21, 2020
https://issues.dlang.org/show_bug.cgi?id=17764

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           See Also|                            |https://issues.dlang.org/sh
                   |                            |ow_bug.cgi?id=20505

--
July 28, 2022
https://issues.dlang.org/show_bug.cgi?id=17764

--- Comment #5 from Walter Bright <bugzilla@digitalmars.com> ---
A simpler version that should fail to compile:

int** global;

struct S { int** str; }

void f() @safe
{
    int* buf;
    S[1] c = S(&buf);
    global = c[0].str; /* This should be rejected. */
}

--
July 28, 2022
https://issues.dlang.org/show_bug.cgi?id=17764

--- Comment #6 from Walter Bright <bugzilla@digitalmars.com> ---
The `c` should be inferred as `scope`.

--
July 28, 2022
https://issues.dlang.org/show_bug.cgi?id=17764

--- Comment #7 from Walter Bright <bugzilla@digitalmars.com> ---
Declaring c as:

    S c = S(&buf);

does cause it to be inferred to be `scope`, and the next line is then correctly diagnosed.

So, the trouble is the scope inference should be looking at the elements of the static array, but is not.

--
August 12, 2022
https://issues.dlang.org/show_bug.cgi?id=17764

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|---                         |WORKSFORME

--- Comment #8 from Walter Bright <bugzilla@digitalmars.com> ---
(In reply to ag0aep6g from comment #4)
>     global = c[0].str; /* This should be rejected. */

And it is now in master:

Error: scope variable `c` assigned to non-scope `global`

--