Bug 14306 – Wrong codegen with -inline for generic lambdas
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-03-18T16:55:00Z
Last change time
2015-06-17T21:02:32Z
Assigned to
nobody
Creator
andrei
Comments
Comment #0 by andrei — 2015-03-18T16:55:19Z
Consider:
import std.algorithm, std.range;
struct S {
int x;
int bump() { ++x; return x; }
}
int[] fun(ref S s) {
auto a = iota(100).map!(x => s.bump).array;
return a;
}
void main() {
S s;
auto a = fun(s);
assert(s.x == 100);
}
If built without -inline, the code works. Adding -inline makes the assertion fail (s.x is 0).
Changing the lambda from x => s.bump to (int x) => s.bump makes the code work, so this is an issue with inlining generic lambdas.
Comment #1 by bugzilla — 2015-03-18T18:30:28Z
Appears to be a problem on all platforms.
Comment #2 by bugzilla — 2015-03-18T21:50:14Z
Test case without imports:
---------
template map(alias fun)
{
auto map(Range)(Range r)
{
return MapResult!(fun, Range)(r);
}
}
struct MapResult(alias fun, Range)
{
alias R = Range;
R _input;
this(R input)
{
_input = input;
}
@property bool empty()
{
return _input.empty;
}
void popFront()
{
_input.popFront();
}
@property auto ref front()
{
return fun(_input.front);
}
}
auto iota(int end)
{
static struct Result
{
int end = 100;
int i = 0;
@property bool empty() { return i == end; }
@property int front() { return i; }
void popFront() { ++i; }
}
return Result();
}
void bar(R)(R r)
{
foreach (x; r) { }
}
struct S {
int x;
int bump() { ++x; return x; }
}
void fun(ref S s) {
iota(100).map!(x => s.bump()).bar;
// iota(100).map!((int x) => s.bump()).bar;
assert(s.x == 100);
}
void main() {
S s;
fun(s);
}
Comment #3 by bugzilla — 2015-03-20T07:18:09Z
Even more reduced:
------------------
struct MapResult(alias fun)
{
void front()
{
fun(1);
}
}
void bar(R)(R r)
{
foreach (i; 0..100)
{
r.front();
}
}
struct S {
int x;
int bump() { ++x; return x; }
}
void fun(ref S s) {
MapResult!(x => s.bump())().bar; // fails
// MapResult!((int x) => s.bump())().bar; // succeeds
if (s.x != 100) assert(0);
}
void main() {
S s;
fun(s);
}
-------------
The failure stems from front() getting inlined. Not sure yet what the problem is.