If a pure function tries to return a struct, the return value becomes garbage.
Example:
struct Foo
{
int x, y
real z;
}
pure Foo makeFoo(const int x, const int y)
{
return Foo(x, y, 3.0);
}
int main()
{
auto f = makeFoo(1, 2);
writeln(f.x, f.y, f.z);
}
Possible cause:
The compiler might be optimizing makeFoo to
pure void makeFoo(ref Foo f, const int x, const int y)
{
f = Foo(x, y, 3.0);
}
in order to prevent returning the entire struct on the stack. Since makeFoo is pure, this optimization breaks the program.
Comment #1 by clugdbug — 2009-10-28T03:01:58Z
If my patch to bug 3269 is in place, the functions will need to be "pure nothrow" in order to reproduce the bug.
The bug clearly lies in the handling of OPucallns. It's failing to deal with the 'hidden parameter'.
In e2ir.c, line 290, if you change it to ALWAYS use OPucall instead of OPucallns, the problem disappears. But that's pretty drastic. The bug lies in the back-end somewhere.
Comment #2 by clugdbug — 2009-12-30T13:11:55Z
Shouldn't be doing no-side-effect calls if there's a hidden parameter.
This happens if the value is being returned on the stack.
PATCH (e2ir.c line 287):
else if (ep)
- e = el_bin((tf->ispure && tf->isnothrow) ? OPcallns : OPcall,tyret,ec,ep);
+ e = el_bin((tf->ispure && tf->isnothrow && (retmethod != RETstack)) ? OPcallns : OPcall,tyret,ec,ep);
else
- e = el_una((tf->ispure && tf->isnothrow) ? OPucallns : OPucall,tyret,ec);
+ e = el_una((tf->ispure && tf->isnothrow && (retmethod != RETstack)) ? OPucallns : OPucall,tyret,ec);
-------
TEST CASE:
struct Foo {
int x, y;
real z;
}
pure nothrow Foo makeFoo(const int x, const int y) {
return Foo(x, y, 3.0);
}
void main()
{
auto f = makeFoo(1, 2);
assert(f.x==1);
assert(f.y==2);
assert(f.z==3);
}