value is implicitly moved even though it's used afterwards
zerbina opened this issue · comments
Example
type Object = object
has: bool
var wasDestroyed = false
proc `=destroy`(x: var Object) =
if x.has:
wasDestroyed = true
proc f_sink(x: sink Object) =
# disarm the destructor:
x.has = false
proc test() =
var o = Object(has: true)
try:
try:
f_sink(o) # must not be sunken
raise CatchableError.newException("")
except IOError:
# omitting the inner try makes the code work as expected
discard "not reached"
except CatchableError:
doAssert not wasDestroyed
discard o # use `o`, preventing it from being moved earlier
test()
doAssert wasDestroyed
Actual Output
The second assertion fails, as o
was erroneously sunken into the call argument, where the destructor was then disarmed, and wasDestructor
thus never set to true.
Expected Output
The program compiles and runs without error. o
is used beyond the procedure call, so it should not be moved.
Additional Information
The culprit is here:
nimskull/compiler/sem/mirexec.nim
Lines 524 to 533 in f401e73
There's no connection between the raise
and the outer except
in the control-flow graph, due to a missing edge between the inner and outer except
.
There was a small error in the provided example, causing it to always fail, even when o
is not sunken. I've correct the test case now.