diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-10-14 13:19:33 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-10-14 17:36:55 +0200 |
commit | b39302b0d2e2771b34283ef9f43d9971f206a2a6 (patch) | |
tree | 51d487c04591e121cc5491f609b3c4b5bc8072ca | |
parent | a30ba8cc370736b8b737292a8c2b46adadc6f8be (diff) | |
download | Nim-b39302b0d2e2771b34283ef9f43d9971f206a2a6.tar.gz |
DFA: implement exception handling properly
-rw-r--r-- | compiler/destroyer.nim | 3 | ||||
-rw-r--r-- | compiler/dfa.nim | 22 | ||||
-rw-r--r-- | tests/destructor/tprevent_assign2.nim | 46 |
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 |