D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3270 - pure functions returning struct
Summary: pure functions returning struct
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords: patch, wrong-code
Depends on:
Blocks:
 
Reported: 2009-08-28 13:54 UTC by qwerty
Modified: 2015-06-09 01:28 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description qwerty 2009-08-28 13:54:20 UTC
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 Don 2009-10-28 03:01:58 UTC
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 Don 2009-12-30 13:11:55 UTC
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);
}
Comment 3 Walter Bright 2009-12-30 17:38:24 UTC
Changeset 323
Comment 4 Walter Bright 2009-12-31 11:18:57 UTC
Fixed dmd 2.038