summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/destroyer.nim3
-rw-r--r--compiler/dfa.nim22
-rw-r--r--tests/destructor/tprevent_assign2.nim46
3 files changed, 55 insertions, 16 deletions
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index 3f78cac6c..2a82b6f3b 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -216,6 +216,7 @@ proc isLastRead(n: PNode; c: var Con): bool =
   let s = n.sym
   var pcs: seq[int] = @[instr+1]
   var takenGotos: IntSet
+  var takenForks = initIntSet()
   while pcs.len > 0:
     var pc = pcs.pop
 
@@ -251,7 +252,7 @@ proc isLastRead(n: PNode; c: var Con): bool =
           inc pc
       of fork:
         # we follow the next instruction but push the dest onto our "work" stack:
-        if not takenGotos.containsOrIncl(pc):
+        if not takenForks.containsOrIncl(pc):
           pcs.add pc + c.g[pc].dest
         inc pc
   #echo c.graph.config $ n.info, " last read here!"
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 04937663a..4b624e93b 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -53,8 +53,9 @@ type
 
   Con = object
     code: ControlFlowGraph
-    inCall: int
+    inCall, inTryStmt: int
     blocks: seq[TBlock]
+    tryStmtFixups: seq[TPosition]
 
 proc debugInfo(info: TLineInfo): string =
   result = $info.line #info.toFilename & ":" & $info.line
@@ -225,8 +226,17 @@ proc genCase(c: var Con; n: PNode) =
 
 proc genTry(c: var Con; n: PNode) =
   var endings: seq[TPosition] = @[]
+  inc c.inTryStmt
+  var newFixups: seq[TPosition]
+  swap(newFixups, c.tryStmtFixups)
+
   let elsePos = c.forkI(n)
   c.gen(n.sons[0])
+  dec c.inTryStmt
+  for f in newFixups:
+    c.patch(f)
+  swap(newFixups, c.tryStmtFixups)
+
   c.patch(elsePos)
   for i in 1 ..< n.len:
     let it = n.sons[i]
@@ -244,7 +254,10 @@ proc genTry(c: var Con; n: PNode) =
 
 proc genRaise(c: var Con; n: PNode) =
   gen(c, n.sons[0])
-  c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
+  if c.inTryStmt > 0:
+    c.tryStmtFixups.add c.gotoI(n)
+  else:
+    c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
 proc genReturn(c: var Con; n: PNode) =
   if n.sons[0].kind != nkEmpty: gen(c, n.sons[0])
@@ -275,6 +288,9 @@ proc genCall(c: var Con; n: PNode) =
     gen(c, n[i])
     if t != nil and i < t.len and t.sons[i].kind == tyVar:
       genDef(c, n[i])
+  # every call can potentially raise:
+  if c.inTryStmt > 0:
+    c.tryStmtFixups.add c.forkI(n)
   dec c.inCall
 
 proc genMagic(c: var Con; n: PNode; m: TMagic) =
@@ -340,6 +356,8 @@ proc gen(c: var Con; n: PNode) =
     gen(c, n.sons[1])
   of nkObjDownConv, nkStringToCString, nkCStringToString: gen(c, n.sons[0])
   of nkVarSection, nkLetSection: genVarSection(c, n)
+  of nkDefer:
+    doAssert false, "dfa construction pass requires the elimination of 'defer'"
   else: discard
 
 proc dfa(code: seq[Instr]; conf: ConfigRef) =
diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim
index 4ef62d2fd..feb635964 100644
--- a/tests/destructor/tprevent_assign2.nim
+++ b/tests/destructor/tprevent_assign2.nim
@@ -1,6 +1,12 @@
 discard """
   errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
-  line: 44
+
+  cmd: "nim check --hint[Performance]:off $file"
+  nimout: '''
+tprevent_assign2.nim(53, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
+tprevent_assign2.nim(55, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
+tprevent_assign2.nim(66, 29) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(68, 9)
+'''
 """
 
 type
@@ -19,18 +25,21 @@ proc take2(a, b: sink Foo) =
 
 proc allowThis() =
   var otherTree: Foo
-  for i in 0..3:
-    while true:
-      #if i == 0:
-      otherTree = createTree(44)
-      case i
-      of 0:
-        echo otherTree
-        take2(createTree(34), otherTree)
-      of 1:
-        take2(createTree(34), otherTree)
-      else:
-        discard
+  try:
+    for i in 0..3:
+      while true:
+        #if i == 0:
+        otherTree = createTree(44)
+        case i
+        of 0:
+          echo otherTree
+          take2(createTree(34), otherTree)
+        of 1:
+          take2(createTree(34), otherTree)
+        else:
+          discard
+  finally:
+    discard
 
 proc preventThis() =
   var otherTree: Foo
@@ -46,3 +55,14 @@ proc preventThis() =
         take2(createTree(34), otherTree)
       else:
         discard
+
+proc preventThis2() =
+  var otherTree: Foo
+  try:
+    try:
+      otherTree = createTree(44)
+      echo otherTree
+    finally:
+      take2(createTree(34), otherTree)
+  finally:
+    echo otherTree