Bug 12811 – GC-allocated closure for calling instance function in filter
Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2014-05-27T11:22:00Z
Last change time
2015-03-27T00:51:34Z
Assigned to
nobody
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2014-05-27T11:22:43Z
I am not sure if it's correct for this code to refuse @nogc:
import std.algorithm: filter;
struct Foo {
bool bar(in int) @nogc {
return true;
}
auto spam() @nogc {
immutable static data = [1, 2];
return data.filter!(i => bar(i));
}
}
void main() {}
dmd 2.066alpha gives:
temp.d(6,10): Error: function temp.Foo.spam @nogc function allocates a closure with the GC
This gives a similar error:
import std.algorithm: filter;
struct Foo {
bool bar(in int) @nogc {
return true;
}
auto spam() @nogc {
immutable static data = [1, 2];
scope immutable f = (int i) => bar(i);
return data.filter!f;
}
}
void main() {}
Comment #1 by k.hara.pg — 2015-03-25T02:29:16Z
(In reply to bearophile_hugs from comment #0)
> import std.algorithm: filter;
> struct Foo {
> bool bar(in int) @nogc {
> return true;
> }
> auto spam() @nogc {
> immutable static data = [1, 2];
> return data.filter!(i => bar(i));
'filter' will lazily evaluate the given array outside of the 'spam' function, so the lambda 'i => bar(i)' needs to capture 'this' variable to call member function 'bar'.
It will make a closure allocation.
> This gives a similar error:
>
> import std.algorithm: filter;
> struct Foo {
> bool bar(in int) @nogc {
> return true;
> }
> auto spam() @nogc {
> immutable static data = [1, 2];
> scope immutable f = (int i) => bar(i);
> return data.filter!f;
To access the delegate variable f later, 'filter' should capture the function frame of 'spam' (and it will indirectly capture the 'this' of 'spam' function). It will need a closure allocation.
Comment #2 by bearophile_hugs — 2015-03-27T00:51:34Z
(In reply to Kenji Hara from comment #1)
> 'filter' will lazily evaluate the given array outside of the 'spam'
> function, so the lambda 'i => bar(i)' needs to capture 'this' variable to
> call member function 'bar'.
>
> It will make a closure allocation.
Thank you for the answer. We'll have to add some escape analysis to turn some closure heap allocations into stack allocations.