Bug 5798 – Weakly pure function calls skipped inside a comma expression

Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
All
Creation time
2011-03-30T13:19:00Z
Last change time
2011-07-14T21:07:52Z
Keywords
patch, wrong-code
Assigned to
nobody
Creator
timon.gehr

Comments

Comment #0 by timon.gehr — 2011-03-30T13:19:58Z
Hello, The following code fails the assertion: import std.algorithm; import std.stdio; int main(){ int a=1,b=0,c; swap(a,b),c=b; assert(a==0); return 0; } (This one passes: import std.stdio; int main(){ int a=1,b=0,c; tmp=b,b=a,a=tmp,c=b; assert(a==0); return 0; } As well as this one: import std.algorithm; import std.stdio; int main(){ int a=1,b=0,c; swap(a,b);c=b; assert(a==0); return 0; } )
Comment #1 by kennytm — 2011-03-30T14:08:55Z
Test case that does not depend on Phobos: void assign9(ref int lhs) pure { lhs = 9; } void assign8(ref int rhs) pure { rhs = 8; } int main(){ int a=1,b=2; assign8(b),assign9(a); assert(a == 9); assert(b == 8); // <-- fail assign9(b),assign8(a); assert(a == 8); assert(b == 9); // <-- fail return 0; } Removing the 'pure' attributes make all asserts pass.
Comment #2 by timon.gehr — 2011-04-19T12:57:50Z
I changed importance to mayor, because this also affects some compiler rewrites, and the fix is trivial. Eg: int weakly_pure_function(out param)pure{...} 1^^weakly_pure_function(param), will be optimized away to (weakly_pure_function(param),1) and then only 1, without setting the param. This bug exists because the compiler incorrectly assumes that a weakly pure function has no side effects. Suggested fix: in expression.c, function CallExp::checkSideEffect, replace (~line 7278) - if (t->ty == Tfunction && ((TypeFunction *)t)->purity) - return 0; by + if (t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak) + return 0;
Comment #3 by kennytm — 2011-04-25T02:14:51Z
Comma expression is also used in for-loops, which may trigger this bug. In particular, the equal() function since commit ec2c8460* does not work with a range with pure popFront() since it says for (; !r1.empty; r1.popFront(), r2.popFront()) // ^ For instance, the following code, which works in 2.052, no longer work in the git master version: ----------------------------------------------------------------- import std.array, std.algorithm; struct X { int _front; pure nothrow: @property int front() const { return _front; } void popFront() { ++ _front; } @property bool empty() const { return _front == 10; } } void main() { X x; //assert(equal(array(x), [0,1,2,3,4,5,6,7,8,9])); // ok x._front = 0; assert(equal(x, [0,1,2,3,4,5,6,7,8,9])); // asserts } ----------------------------------------------------------------- * https://github.com/D-Programming-Language/phobos/commit/ec2c8460#L0R4324
Comment #4 by bugzilla — 2011-05-04T23:56:25Z
Comment #5 by kennytm — 2011-06-24T02:26:41Z
I thought this in a 'for' loop (comment 3) has been fixed, but it doesn't. Re-opening.
Comment #6 by kennytm — 2011-06-24T02:28:28Z
*** Issue 6206 has been marked as a duplicate of this issue. ***
Comment #7 by bugzilla — 2011-06-24T02:39:10Z
Adding my test case from issue 6206 here, since it's much smaller and doesn't pull in any Phobos modules. struct S { int i = 0; void incr() pure { ++i; } } void main() { S s; for (int j=0; j<10; s.incr(), ++j) { } assert (s.i == 10); // fails }
Comment #8 by yebblies — 2011-07-14T21:07:52Z
These all seem to be working with dmd 2.054