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.