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
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
}