Thread overview
[Issue 22563] Nested structs, if not escaping, shouldn't allocate context (just like delegates)
Dec 03, 2021
kinke
Dec 03, 2021
Stanislav Blinov
Dec 03, 2021
Stanislav Blinov
Dec 03, 2021
kinke
Dec 03, 2021
Stanislav Blinov
Dec 03, 2021
Stanislav Blinov
Dec 08, 2021
Stanislav Blinov
Dec 17, 2022
Iain Buclaw
December 03, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

kinke <kinke@gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kinke@gmx.net

--- Comment #1 from kinke <kinke@gmx.net> ---
`scope S` doesn't prevent `consumeThingWithContext!Nested` from copying or moving the struct to some global state surviving the invocation.

--
December 03, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

--- Comment #2 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
It should in @safe code, which is where `scope` matters. The only way to escape it should be to break @safe. Isn't that the whole point?..

void* global;

struct Escapist(T)
{
    T value;
}

@safe
void consumeThingWithContext(S)(scope S s)
if (is(S == struct) && __traits(isNested, S))
{
    import core.lifetime;
    global = s.tupleof[$-1];       // error: scope variable `s` assigned to
non-scope `global`
    global = move(s.tupleof[$-1]); // error: scope variable `s` assigned to
non-scope `global`

    auto escape = new Escapist!S(s); // with dip1000: scope variable `s` may
not be copied into allocated memory
}

@safe /*@nogc*/
void main()
{
    int a;
    struct Nested { ~this() @nogc { a++; } }
    consumeThingWithContext(Nested());
}

--
December 03, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

--- Comment #3 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
IOW, if there is a way to escape it, there's a bug.

--
December 03, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

--- Comment #4 from kinke <kinke@gmx.net> ---
This currently compiles even with -dip1000:
```
void consumeThingWithContext(S)(scope S s)
if (is(S == struct) && __traits(isNested, S))
{
    static S global;
    global = s;
}

//@safe //@nogc
void main()
{
    int a;
    struct Nested { ~this() @safe @nogc { a++; } }
    consumeThingWithContext(Nested());
}
```

It's just not inferred to be @safe.

It segfaults at runtime, presumably because `global` is initialized statically with null context pointer and cannot be successfully destructed prior to reassignment...

--
December 03, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

--- Comment #5 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
Well... the `static S s;` simply shouldn't compile at all for exactly that reason, so that's one extra bug:

struct WTF(T)
{
    static T x;
    void foo() { x.foo(); }
}

@safe
void main()
{
    int a;
    struct Nested
    {
        @safe:

        void foo() { ++a; } // boom1

        ~this() { foo(); }  // boom2
    }
}

But the reason `consumeThingWithContext` is not inferred safe is the escape:

Error: scope variable `s` assigned to non-scope parameter `p` calling context.main.Nested.opAssign

The compiler is doing exactly the same thing for delegates too at the moment - it infers such escape as @system.

A delegate is context + one function pointer. A nested struct is effectively a superset of that, with an added advantage of type information for function pointers. There's no reason (other than implementation complexity) to support allocation elision for one and not the other.

--
December 03, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

--- Comment #6 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
Forgot to add the boom to main:

WTF!Nested.foo;

--
December 08, 2021
https://issues.dlang.org/show_bug.cgi?id=22563

Stanislav Blinov <stanislav.blinov@gmail.com> changed:

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

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=22563

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P4

--
December 13
https://issues.dlang.org/show_bug.cgi?id=22563

--- Comment #7 from dlangBugzillaToGithub <robert.schadek@posteo.de> ---
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18068

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB

--