Error: @nogc function 'test.func2' cannot call non- at nogc delegate 'msg'

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Dec 10 11:44:20 UTC 2017


On Sunday, December 10, 2017 12:54:00 Shachar Shemesh via Digitalmars-d 
wrote:
> void func1(scope lazy string msg) @nogc {
> }
>
> void func2(scope lazy string msg) @nogc {
>      func1(msg);
> }
>
> What? Why is msg GC allocating, especially since I scoped the lazy? Why
> is msg even evaluated?
>
> Something seems off here.

Well, I'm not exactly sure how lazy is implemented underneath the hood
(other than the fact that it generates a delegate and potentially a
closure), but based on the error message, it sounds like the delegate that's
being generated isn't @nogc, so it can't be called within the function,
which would be a completely different issue from allocating a closure.

Curiously, pure doesn't seem to have the same problem, and I would have
guessed that it would given that @nogc does.

But if it matters that the delegate be pure or @nogc because the function is
marked that way, then that's a bit of a problem, because presumably, there
can only be one delegate (since the function isn't templated), and the same
function could be called with an expression that allocated and with an
expression that didn't allocate. So, if the delegate is restricted like
that, then that would restrict the caller, which doesn't follow how non-lazy
arguments work, and an argument could be made that whether calling the
delegate allocates memory or not or is pure or not doesn't matter even if
the function being called is @nogc or pure on the basis that it's
conceptually just a delayed evaluation of the argument in the caller's
scope. But for that to work, the generated delegate can't be checked for
@nogc or pure or nothrow or any of that inside the function with the lazy
parameter. Given that pure works but @nogc doesn't, it makes it seem like
the compiler was made smart enough to ignore purity for lazy parameters but
not smart enough to ignore the lack of @nogc.

As for scope, I don't know if it really applies to lazy parameters or not at
this point. Without -dip1000, all it applies to is delegates, but lazy
parameters are turned into delegates, so you would _think_ that scope would
apply, but I don't know. scope has always been underimplemented, though
Walter's work on -dip1000 is fixing that. Regardless, the error message
makes it sound like scope and closures have nothing to do with the problem
(though it could potentially be a problem once the @nogc problem with the
delegate is fixed).

In any case, I think that it's pretty clear that this merits being reported
in bugzilla. The fact that pure works while @nogc doesn't strongly indicates
that something is off with @nogc - especially if scope is involved. Worst
case, a fix will have to be lumped in with -dip1000, depending on what scope
is supposed to be doing now and exactly how lazy is working underneath the
hood, but I definitely think that your code should work.

- Jonathan M Davis



More information about the Digitalmars-d mailing list