Bug 3634 – return value not passed to out contracts of private methods
Status
RESOLVED
Resolution
DUPLICATE
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Linux
Creation time
2009-12-18T22:37:00Z
Last change time
2015-06-09T01:27:04Z
Keywords
wrong-code
Assigned to
nobody
Creator
witold.baryluk+d
Comments
Comment #0 by witold.baryluk+d — 2009-12-18T22:37:44Z
This code failes, but it should pass.
class A {
this() {
x_ = 10;
}
private:
uint x_;
uint x()
out(ret) {
assert(ret == 10); // fails // line 10
assert(ret == x_); // fails
}
body {
return x_;
}
}
import std.stdio;
void main() {
auto a = new A();
writefln("%d", a.x());
}
$ dmd2 -debug a.d; ./a
core.exception.AssertError@t(10): Assertion failure
$
When I change x() method to 'public' problems dissaper.
Here is dissambled code
assume CS:.text._D1t1A1xMFZk
_D1t1A1xMFZk:
push EBP
mov EBP,ESP
sub ESP,0Ch
add EAX,8
mov ECX,[EAX]
mov -8[EBP],ECX
mov -0Ch[EBP],EAX
mov EAX,0Ah
call near ptr _D1t8__assertFiZv@PC32
mov EDX,-0Ch[EBP]
cmp dword ptr [EDX],0
je L2D
mov EAX,0Bh
call near ptr _D1t8__assertFiZv@PC32
L2D: mov EAX,-8[EBP]
leave
ret
nop
nop
.text._D1t1A1xMFZk ends
Also without "-debug" switch the same code is generated.
If i comment a assert statments (or don't use ret), method properly returns value to callee.
In release mode it works correclty (but contracts are called):
.text._D1t1A1xMFZk segment
assume CS:.text._D1t1A1xMFZk
_D1t1A1xMFZk:
push EBP
mov EBP,ESP
sub ESP,4
mov EAX,8[EAX]
leave
ret
nop
.text._D1t1A1xMFZk ends
Comment #1 by witold.baryluk+d — 2009-12-18T22:59:08Z
Original code (with "private") fails also with "-O", "-O -inline", and many others.
Here is simplified case:
class A {
this() {
x_ = 0x40;
}
private:
uint x_;
//public:
uint x()
out(ret) {
pppp(ret);
}
body {
return x_;
}
}
import std.stdio;
void main() { auto a = new A(); }
void pppp(uint xxx) { xxx ++; }
.text._D1t1A1xMFZk segment
assume CS:.text._D1t1A1xMFZk
_D1t1A1xMFZk:
push EBP
mov EBP,ESP
sub ESP,8
mov ECX,8[EAX] // move field x_ to the ECX register
mov -8[EBP],ECX // save ret in EBP[-8]
xor EAX,EAX // set ret = 0
call near ptr _D1t4ppppFkZv@PC32 // call pppp(EAX)
mov EAX,-8[EBP] // restore ret after return from ppp
leave
ret // return
.text._D1t1A1xMFZk ends
When changed to "public":
.text._D1t1A1xMFZk segment
assume CS:.text._D1t1A1xMFZk
_D1t1A1xMFZk:
push EBP
mov EBP,ESP
sub ESP,8
mov -4[EBP],EAX
call near ptr _D9invariant12_d_invariantFC6ObjectZv@PC32
mov EAX,-4[EBP]
mov ECX,8[EAX]
mov -8[EBP],ECX
lea EDX,-8[EBP]
push EDX
call near ptr _D1t1A1xMFZk8__ensureMFKxkZv@PC32
mov EAX,-8[EBP]
leave
ret
nop
nop
nop
.text._D1t1A1xMFZk ends
.text._D1t1A1xMFZk8__ensureMFKxkZv segment
assume CS:.text._D1t1A1xMFZk8__ensureMFKxkZv
_D1t1A1xMFZk8__ensureMFKxkZv:
push EBP
mov EBP,ESP
sub ESP,4
mov ECX,8[EBP] // take address of field x_ and put into ECX
mov EAX,[ECX] // move content of field x_ into EAX
call near ptr _D1t4ppppFkZv@PC32 // call pppp(EAX)
leave
ret 4 // return
.text._D1t1A1xMFZk8__ensureMFKxkZv ends
_D9invariant12_d_invariantFC6ObjectZv@PC32 is and Object.invariant() from base class.
Comment #2 by witold.baryluk+d — 2009-12-18T23:03:34Z
Using "protected" attributed it works correctly:
.text._D1t1A1xMFZk segment
assume CS:.text._D1t1A1xMFZk
_D1t1A1xMFZk:
push EBP
mov EBP,ESP
sub ESP,8
mov ECX,8[EAX]
mov -8[EBP],ECX
lea EDX,-8[EBP]
push EDX
call near ptr _D1t1A1xMFZk8__ensureMFKxkZv@PC32
mov EAX,-8[EBP]
leave
ret
nop
nop
.text._D1t1A1xMFZk ends
.text._D1t1A1xMFZk8__ensureMFKxkZv segment
assume CS:.text._D1t1A1xMFZk8__ensureMFKxkZv
_D1t1A1xMFZk8__ensureMFKxkZv:
push EBP
mov EBP,ESP
sub ESP,4
mov ECX,8[EBP]
mov EAX,[ECX]
call near ptr _D1t4ppppFkZv@PC32
leave
ret 4
.text._D1t1A1xMFZk8__ensureMFKxkZv ends
I was first thinking this is problem with constatnt propagation, but i don't think this is good guess. Hope someone with better knowledge of backend can say something more relevant. :)
Comment #3 by clugdbug — 2010-06-07T00:11:57Z
This was a regression in 2.037. Fixed in the beta of 2.047.
*** This issue has been marked as a duplicate of issue 3667 ***