nim-works / nimskull

An in development statically typed systems programming language; with sustainability at its core. We, the community of users, maintain it.

Home Page:https://nim-works.github.io/nimskull/index.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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:

# after a structured exit of the handler, control-flow continues after
# the code section it is attached to. Node-wise, this is the ``end``
# node terminating the ``try`` the handler is part of
# TODO: with this approach, either the last branch needs to fork
# control-flow to the next exception handler or ``mirgen`` has to
# introduce a catch-all handler
if tree[i+1].kind == mnkFinally:
# only add an edge if the there's a finalizer -- no edge is needed
# if there's none
exit opGoto, i, findHidden()

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.

Fixed by #1281. Control-flow between nested try/except statements/expressions is now represented correctly within the CFG.