diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-06-03 18:00:45 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-06-03 18:00:45 +0300 |
commit | 3ce400bb00363a4b207ba966937d26c746d25e1b (patch) | |
tree | 5e86238d450afa6fab2aa750000218244eecf402 | |
parent | ab18654e593085feb92e8f93f5c575d6ce62cda4 (diff) | |
download | Nim-3ce400bb00363a4b207ba966937d26c746d25e1b.tar.gz |
bugfix: finally blocks were not executed when the except block is exited by raise or return
-rwxr-xr-x | compiler/ccgstmts.nim | 29 | ||||
-rw-r--r-- | compiler/cgendata.nim | 5 | ||||
-rw-r--r-- | tests/run/texceptions.nim | 66 |
3 files changed, 87 insertions, 13 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 46e4f75df..d21093845 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -205,15 +205,19 @@ proc blockLeaveActions(p: BProc, howMany: int) = stack[i-1] = p.nestedTryStmts[L-i] setLen(p.nestedTryStmts, L-howMany) + var alreadyPoppedCnt = p.inExceptBlock for tryStmt in items(stack): - appcg(p, cpsStmts, "#popSafePoint();$n", []) + if alreadyPoppedCnt > 0: + dec alreadyPoppedCnt + else: + appcg(p, cpsStmts, "#popSafePoint();$n", []) var finallyStmt = lastSon(tryStmt) if finallyStmt.kind == nkFinally: genStmts(p, finallyStmt.sons[0]) # push old elements again: for i in countdown(howMany-1, 0): p.nestedTryStmts.add(stack[i]) - for i in countdown(p.popCurrExc-1, 0): + for i in countdown(p.inExceptBlock-1, 0): appcg(p, cpsStmts, "#popCurrentException();$n", []) proc genReturnStmt(p: BProc, t: PNode) = @@ -310,7 +314,13 @@ proc getRaiseFrmt(p: BProc): string = #else: result = "#raiseException((#E_Base*)$1, $2);$n" -proc genRaiseStmt(p: BProc, t: PNode) = +proc genRaiseStmt(p: BProc, t: PNode) = + if p.inExceptBlock > 0: + # if the current try stmt have a finally block, + # we must execute it before reraising + var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon + if finallyBlock.kind == nkFinally: + genStmts(p, finallyBlock.sons[0]) if t.sons[0].kind != nkEmpty: var a: TLoc InitLocExpr(p, t.sons[0], a) @@ -628,7 +638,7 @@ proc genTryStmt(p: BProc, t: PNode) = add(p.nestedTryStmts, t) genStmts(p, t.sons[0]) endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n")) - discard pop(p.nestedTryStmts) + inc p.inExceptBlock var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): var blen = sonsLen(t.sons[i]) @@ -637,13 +647,10 @@ proc genTryStmt(p: BProc, t: PNode) = if i > 1: appf(p.s(cpsStmts), "else") startBlock(p) appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) - inc p.popCurrExc genStmts(p, t.sons[i].sons[0]) - dec p.popCurrExc appcg(p, cpsStmts, "#popCurrentException();$n", []) endBlock(p) else: - inc p.popCurrExc var orExpr: PRope = nil for j in countup(0, blen - 2): assert(t.sons[i].sons[j].kind == nkType) @@ -655,9 +662,10 @@ proc genTryStmt(p: BProc, t: PNode) = startBlock(p, "if ($1) {$n", [orExpr]) appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) genStmts(p, t.sons[i].sons[blen-1]) - dec p.popCurrExc endBlock(p, ropecg(p.module, "#popCurrentException();}$n")) inc(i) + dec p.inExceptBlock + discard pop(p.nestedTryStmts) appf(p.s(cpsStmts), "}$n") # end of else block if i < length and t.sons[i].kind == nkFinally: genSimpleBlock(p, t.sons[i].sons[0]) @@ -820,9 +828,8 @@ proc genStmts(p: BProc, t: PNode) = initLocExpr(p, t.sons[0], a) of nkAsmStmt: genAsmStmt(p, t) of nkTryStmt: - #if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t) - #else: - genTryStmt(p, t) + if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t) + else: genTryStmt(p, t) of nkRaiseStmt: genRaiseStmt(p, t) of nkTypeSection: # we have to emit the type information for object types here to support diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index a22c13f3a..bcdf53afd 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -62,8 +62,9 @@ type ThreadVarAccessed*: bool # true if the proc already accessed some threadvar nestedTryStmts*: seq[PNode] # in how many nested try statements we are # (the vars must be volatile then) - popCurrExc*: Natural # how often to emit 'popCurrentException()' - # before 'break'|'return' + inExceptBlock*: int # are we currently inside an except block? + # leaving such scopes by raise or by return must + # execute any applicable finally blocks labels*: Natural # for generating unique labels in the C proc blocks*: seq[TBlock] # nested blocks breakIdx*: int # the block that will be exited diff --git a/tests/run/texceptions.nim b/tests/run/texceptions.nim new file mode 100644 index 000000000..2e6101c2a --- /dev/null +++ b/tests/run/texceptions.nim @@ -0,0 +1,66 @@ +discard """ + output: ''' +BEFORE +FINALLY + +BEFORE +EXCEPT +FINALLY +RECOVER + +BEFORE +EXCEPT +FINALLY +''' +""" + +echo "" + +proc no_expcetion = + try: + echo "BEFORE" + + except: + echo "EXCEPT" + raise + + finally: + echo "FINALLY" + +try: no_expcetion() +except: echo "RECOVER" + +echo "" + +proc reraise_in_except = + try: + echo "BEFORE" + raise newException(EIO, "") + + except: + echo "EXCEPT" + raise + + finally: + echo "FINALLY" + +try: reraise_in_except() +except: echo "RECOVER" + +echo "" + +proc return_in_except = + try: + echo "BEFORE" + raise newException(EIO, "") + + except: + echo "EXCEPT" + return + + finally: + echo "FINALLY" + +try: return_in_except() +except: echo "RECOVER" + |