Jump to page: 1 2
Thread overview
How do you debug @safe @nogc code? Can't figure out how to print.
Nov 16, 2018
aliak
Nov 16, 2018
Zoadian
Nov 17, 2018
aliak
Nov 16, 2018
Stanislav Blinov
Nov 17, 2018
aliak
Nov 17, 2018
Stanislav Blinov
Nov 17, 2018
aliak
Nov 17, 2018
Stanislav Blinov
Nov 17, 2018
Neia Neutuladh
Nov 17, 2018
aliak
Nov 17, 2018
Neia Neutuladh
Nov 18, 2018
aliak
Nov 22, 2018
Vijay Nayar
Nov 17, 2018
Nicholas Wilson
Nov 17, 2018
aliak
November 16, 2018
Hi, I previously had trouble trying to get print statements working while debugging in nogc. And that was hackishly solved [0], but I can't figure out how to do the same if I have @safe involved. Here's a cut down sample:

// This is the function from the thread referenced
auto assumeNoGC(T)(T t) {
    import std.traits;
    enum attrs = functionAttributes!T | FunctionAttribute.nogc;
    return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}

private struct Dispatcher {
    public template opDispatch(string name){
        auto ref opDispatch(Args...)(auto ref Args args) {
            import std.stdio;
            // Print args here for debugging purposes
            assumeNoGC({ writeln(args); })();
            return 3;
        }
    }
}

@safe @nogc void main() {
    auto i = Dispatcher().getI(3);
}

So, basically with the above, using:
    debug writeln(args);
Causes "Error: @nogc function D main cannot call non-@nogc function"

Using:
    debug assumeNoGC({ writeln(args); })();
Causes:
    Error: @safe function D main cannot call @system function
    Error: @nogc function D main cannot call non-@nogc function

Changing attrs in assumeNoGC
    enum attrs = functionAttributes!T | FunctionAttribute.nogc | FunctionAttribute.safe
Causes same as previous errors

Adding @trusted to declaration of opDispatch gets rid of @safe error but I still get "Error: @nogc function D main cannot call non-@nogc function". And going through the codebase and figuring out where to add @trusted is *very* cumbersome.

I can't figure out how to make this work. The ideal way would be just a debug_print() function that works in nogc and safe code. I.e. does not affect the attribute inference of templates.

Cheers,
- Ali

[0] https://forum.dlang.org/post/pmf4dm$jmo$1@digitalmars.com
November 16, 2018
debug {
    import std.stdio;
    writeln(args);
}
November 16, 2018
On Friday, 16 November 2018 at 12:59:22 UTC, aliak wrote:

> Adding @trusted to declaration of opDispatch gets rid of @safe error but I still get "Error: @nogc function D main cannot call non-@nogc function". And going through the codebase and figuring out where to add @trusted is *very* cumbersome.
>
> I can't figure out how to make this work. The ideal way would be just a debug_print() function that works in nogc and safe code. I.e. does not affect the attribute inference of templates.

As Zoadian points out, you can now (since 2.079: https://dlang.org/changelog/2.079.0.html#bugfix-list) shamelessly call @nogc inside debug blocks.

To get at where the problematic areas were in the code in question though, it's as follows:

> auto assumeNoGC(T)(T t) {  // point 1
>     import std.traits;
>     enum attrs = functionAttributes!T | FunctionAttribute.nogc;
>     // point 2:
>     return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
> }

At 'point 1', you just take by value. If `t` ends up being a closure, D will allocate. That's where it breaks the @nogc. Solution:

auto assumeNoGC(T)(return scope T t) { /* ... */ }

Now you take (and return) a `scope` t, in that case when `t` is a closure D won't allocate it on the GC heap.

At 'point 2' you make an un-@safe cast, that's where it breaks @safe. Given that the whole deal is just a debugging hack, you could mark the whole function @trusted:

auto assumeNoGC(T)(return scope T t) @trusted { /* ... */ }
November 17, 2018
On Friday, 16 November 2018 at 13:03:40 UTC, Zoadian wrote:
> debug {
>     import std.stdio;
>     writeln(args);
> }

As mentioned in the original post, that does not work.
November 17, 2018
On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote:
> At 'point 1', you just take by value. If `t` ends up being a closure, D will allocate. That's where it breaks the @nogc. Solution:
>
> auto assumeNoGC(T)(return scope T t) { /* ... */ }
>
> Now you take (and return) a `scope` t, in that case when `t` is a closure D won't allocate it on the GC heap.
>
> At 'point 2' you make an un-@safe cast, that's where it breaks @safe. Given that the whole deal is just a debugging hack, you could mark the whole function @trusted:
>
> auto assumeNoGC(T)(return scope T t) @trusted { /* ... */ }

Sawweet! Thanks, that made the printing possible!

"scope" is const from what I understand right? It works without scope as well. So just "return T".

Cheers,
- Ali
November 17, 2018
On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:

> Sawweet! Thanks, that made the printing possible!

You're welcome ;) Still, try a more recent compiler. This works fine:

void foo() @nogc {
    debug {
        import std.stdio;
        writefln("%d", 42);
    }
}

> "scope" is const from what I understand right? It works without scope as well. So just "return T".

No, "scope" means "does not escape scope", i.e. you can't assign that argument to some global. The only exception is through a return, in which case "return" also needed. Whether or not just "return" is sufficient, is a bit out there still (AFAIK), between DIP25, DIP1000 and current state of the language.
"scope" was implemented for delegates for ages now, exactly to allow passing lambdas around without allocating their context on the GC heap.
November 17, 2018
On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:
> On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote:
>> auto assumeNoGC(T)(return scope T t) @trusted { /* ... */ }
>
> Sawweet! Thanks, that made the printing possible!
>
> "scope" is const from what I understand right? It works without scope as well. So just "return T".

No, `in` used to mean const scope.

scope means roughly "this thing does not escape this function" e.g. assigning to global variables.
November 17, 2018
On Saturday, 17 November 2018 at 13:43:20 UTC, Stanislav Blinov wrote:
> On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:
>
>> Sawweet! Thanks, that made the printing possible!
>
> You're welcome ;) Still, try a more recent compiler. This works fine:
>
> void foo() @nogc {
>     debug {
>         import std.stdio;
>         writefln("%d", 42);
>     }
> }

Yeah that does, but not the code I posted -> https://run.dlang.io/is/vH3cFa

You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail.

Maybe a bug if it's supposed to work?

>
>> "scope" is const from what I understand right? It works without scope as well. So just "return T".
>
> No, "scope" means "does not escape scope", i.e. you can't assign that argument to some global. The only exception is through a return, in which case "return" also needed. Whether or not just "return" is sufficient, is a bit out there still (AFAIK), between DIP25, DIP1000 and current state of the language.
> "scope" was implemented for delegates for ages now, exactly to allow passing lambdas around without allocating their context on the GC heap.

Aha, cool. Thanks!

November 17, 2018
On Saturday, 17 November 2018 at 13:46:00 UTC, Nicholas Wilson wrote:
> On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:
>> On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote:
>>> auto assumeNoGC(T)(return scope T t) @trusted { /* ... */ }
>>
>> Sawweet! Thanks, that made the printing possible!
>>
>> "scope" is const from what I understand right? It works without scope as well. So just "return T".
>
> No, `in` used to mean const scope.
>
> scope means roughly "this thing does not escape this function" e.g. assigning to global variables.

Righto! Thanks!
November 17, 2018
On Saturday, 17 November 2018 at 13:55:24 UTC, aliak wrote:

> You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail.
>
> Maybe a bug if it's supposed to work?

Indeed that fails, and I would say that's a bug. If it's allowed in @nogc, it shouldn't then infer to non-@nogc when not explicitly attributed. Maybe debug blocks should outright be skipped when inferring?..
« First   ‹ Prev
1 2