Thread overview
[Issue 19371] Taking address of ref return in @safe code: compile-time checks fail
Nov 07, 2018
Stanislav Blinov
Nov 10, 2018
Nick Treleaven
Nov 10, 2018
Stanislav Blinov
Nov 13, 2018
Nick Treleaven
Nov 13, 2018
Nick Treleaven
Nov 14, 2018
Stanislav Blinov
Nov 28, 2018
Nick Treleaven
Nov 28, 2018
Stanislav Blinov
November 07, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |safe

--
November 10, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

Nick Treleaven <nick@geany.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |nick@geany.org

--- Comment #1 from Nick Treleaven <nick@geany.org> ---
Using __traits(compiles) works for the first two asserts:

    static assert(!__traits(compiles, &get()));
    static assert(!__traits(compiles, () @safe { return &get(); }));

is(typeof()) is not as strict, it is looking for a type rather than compiling.

>     static assert(!__traits(compiles, { auto p = &get(); }));

Here, the function literal is inferred as @system, and can even be assigned to a variable in @safe code (but not called):

    auto f = { auto p = &get(); }; //ok
    f(); // Error: `@safe` function cannot call `@system` function pointer `f`

You can fix it by forcing @safe for the literal, or calling the literal:

    static assert(!__traits(compiles, () @safe { auto p = &get(); }));
    static assert(!__traits(compiles, { auto p = &get(); }()));

--
November 10, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

--- Comment #2 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
Thanks for the pointers about __traits(compiles), I somehow lost the
distinction of braces. However, the point about is(typeof()) still stands
though:

    pragma(msg, typeof(() @safe { return &get(); }));

will print _error_.

In other words:

```
void main() @safe {
    int x;
    ref int get() { return x; }
    // since this doesn't compile:
    int* getExplicit() @safe { return &get(); }
    // ...then it has no type, therefore this should pass:
    static assert(!is(typeof(() @safe { return &get(); })));
}
```

--
November 13, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

--- Comment #3 from Nick Treleaven <nick@geany.org> ---
(In reply to Stanislav Blinov from comment #2)
>     pragma(msg, typeof(() @safe { return &get(); }));
> 
> will print _error_.

What compiler are you using? With run.dlang.io the above (currently) prints:

int* delegate() pure nothrow @nogc @safe

It's the same even if I remove the @safe attribute, safety inference (or safe consistency checking) is not happening inside typeof alone.

BTW if I do this:

    auto f = { return &get(); };
    pragma(msg, typeof(f));

I get `int* delegate() pure nothrow @nogc @system`. The compiler does safety
inference for `f` before typeof(f) is analysed.

The same happens if I replace the literal with `{ return cast(int*)7; }`, it's
reported as @safe inside pragma(msg, typeof(...)), but @system when assigning
it to a variable `f` and doing pragma(msg, typeof(f)).

>     // since this doesn't compile:
>     int* getExplicit() @safe { return &get(); }
>     // ...then it has no type, therefore this should pass:
>     static assert(!is(typeof(() @safe { return &get(); })));

It depends if `typeof` is supposed to do @safe checking, or if it is just a tool to extract a type from an expression (that appears to have a valid type), even if that expression might not actually compile with full compiler checks. I think it's the latter, which is why __traits(compiles) was invented.

--
November 13, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

--- Comment #4 from Nick Treleaven <nick@geany.org> ---
See: https://forum.dlang.org/post/k6o04g$259s$1@digitalmars.com

--
November 14, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

--- Comment #5 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
Add -dip1000 to the command line. With it, I don't understand how these two lines are not contradicting:

    pragma(msg, typeof(() @safe { return &get(); }));         // _error_
    static assert(!is(typeof(() @safe { return &get(); })));  // fails

--
November 28, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

--- Comment #6 from Nick Treleaven <nick@geany.org> ---
(In reply to Stanislav Blinov from comment #5)

Adding -dip1000, the pragma line does error, but the static assert passes.

--
November 28, 2018
https://issues.dlang.org/show_bug.cgi?id=19371

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

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

--- Comment #7 from Stanislav Blinov <stanislav.blinov@gmail.com> ---
Hmm, I must've done something wrong initially.

--