Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hidden @nogc violation around closure creation #19012

Open
dlangBugzillaToGithub opened this issue Jul 5, 2015 · 3 comments
Open

Hidden @nogc violation around closure creation #19012

dlangBugzillaToGithub opened this issue Jul 5, 2015 · 3 comments

Comments

@dlangBugzillaToGithub
Copy link

Kenji Hara (@9rnsr) reported this on 2015-07-05T05:15:12Z

Transferred from https://issues.dlang.org/show_bug.cgi?id=14771

CC List

  • ag0aep6g
  • Stanislav Blinov

Description

The variable x in makeS() function is actually placed in closure object on heap, but it's not checked by the @nogc.

struct S(alias f)
{
    auto foo()() { return f(0); }
    void dummy() {}
}

auto makeS() @nogc
{
    int x = 10;
    S!(a => x) s;

    // instantiating foo inside makeS will raise the @nogc violation error.
    //assert(s.foo() == 10);

    return s;
}

void main() @nogc
{
    auto s = makeS();

    // the hidden field of s is actually non-null,
    // that points closure object on heap.
    assert(s.tupleof[$-1] !is null);

    // instantiating foo outside makeS will place the variable x in closure
    // *after* the semantic3 completion of the function.
    // --> @nogc attribute on makeS() is ignored!
    // --> @nogc on main() has no effect, so foo itself has no GC-allocation.
    assert(s.foo() == 10);
}
@dlangBugzillaToGithub
Copy link
Author

k.hara.pg commented on 2015-07-07T17:11:29Z

Issue 5730 is also related with the closure handling timing.

@dlangBugzillaToGithub
Copy link
Author

ag0aep6g commented on 2015-08-30T13:57:53Z

A variant is to make makeS a template instead of S.foo:

----
struct S(alias f)
{
    auto foo() { return f(0); }
}

auto makeS()() @nogc
{
    int x = 10;
    S!(a => x) s;
    return s;
}

void main() @nogc
{
    auto s = makeS();
}
----

Compiles, but shouldn't.

Some change in 2.068's Phobos makes it possible to accidentally do this with std.algorithm.map:

----
import std.algorithm: equal, map;
import std.range: only;

auto foo()(int[] a, immutable int b)
{
    return a.map!(x => x + b);
}

void main() @nogc
{
    int[3] test = [1,2,3];
    assert(test[].foo(3).equal(only(4,5,6)));
}
----

I've seen this twice recently:

http://forum.dlang.org/post/xpdntswucmqboejhxiit@forum.dlang.org
http://forum.dlang.org/post/mrv0td$ci6$1@digitalmars.com

@dlangBugzillaToGithub
Copy link
Author

stanislav.blinov commented on 2021-12-08T18:12:51Z

Still an issue in 2.098.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant