bugfix: finally blocks were not executed when the except block is exited by raise or return
This commit is contained in:
parent
ab18654e59
commit
3ce400bb00
3 changed files with 87 additions and 13 deletions
|
|
@ -205,15 +205,19 @@ proc blockLeaveActions(p: BProc, howMany: int) =
|
||||||
stack[i-1] = p.nestedTryStmts[L-i]
|
stack[i-1] = p.nestedTryStmts[L-i]
|
||||||
setLen(p.nestedTryStmts, L-howMany)
|
setLen(p.nestedTryStmts, L-howMany)
|
||||||
|
|
||||||
|
var alreadyPoppedCnt = p.inExceptBlock
|
||||||
for tryStmt in items(stack):
|
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)
|
var finallyStmt = lastSon(tryStmt)
|
||||||
if finallyStmt.kind == nkFinally:
|
if finallyStmt.kind == nkFinally:
|
||||||
genStmts(p, finallyStmt.sons[0])
|
genStmts(p, finallyStmt.sons[0])
|
||||||
# push old elements again:
|
# push old elements again:
|
||||||
for i in countdown(howMany-1, 0):
|
for i in countdown(howMany-1, 0):
|
||||||
p.nestedTryStmts.add(stack[i])
|
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", [])
|
appcg(p, cpsStmts, "#popCurrentException();$n", [])
|
||||||
|
|
||||||
proc genReturnStmt(p: BProc, t: PNode) =
|
proc genReturnStmt(p: BProc, t: PNode) =
|
||||||
|
|
@ -310,7 +314,13 @@ proc getRaiseFrmt(p: BProc): string =
|
||||||
#else:
|
#else:
|
||||||
result = "#raiseException((#E_Base*)$1, $2);$n"
|
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:
|
if t.sons[0].kind != nkEmpty:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
InitLocExpr(p, t.sons[0], a)
|
InitLocExpr(p, t.sons[0], a)
|
||||||
|
|
@ -628,7 +638,7 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
add(p.nestedTryStmts, t)
|
add(p.nestedTryStmts, t)
|
||||||
genStmts(p, t.sons[0])
|
genStmts(p, t.sons[0])
|
||||||
endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n"))
|
endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n"))
|
||||||
discard pop(p.nestedTryStmts)
|
inc p.inExceptBlock
|
||||||
var i = 1
|
var i = 1
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||||
var blen = sonsLen(t.sons[i])
|
var blen = sonsLen(t.sons[i])
|
||||||
|
|
@ -637,13 +647,10 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
if i > 1: appf(p.s(cpsStmts), "else")
|
if i > 1: appf(p.s(cpsStmts), "else")
|
||||||
startBlock(p)
|
startBlock(p)
|
||||||
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
||||||
inc p.popCurrExc
|
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
dec p.popCurrExc
|
|
||||||
appcg(p, cpsStmts, "#popCurrentException();$n", [])
|
appcg(p, cpsStmts, "#popCurrentException();$n", [])
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
else:
|
else:
|
||||||
inc p.popCurrExc
|
|
||||||
var orExpr: PRope = nil
|
var orExpr: PRope = nil
|
||||||
for j in countup(0, blen - 2):
|
for j in countup(0, blen - 2):
|
||||||
assert(t.sons[i].sons[j].kind == nkType)
|
assert(t.sons[i].sons[j].kind == nkType)
|
||||||
|
|
@ -655,9 +662,10 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
startBlock(p, "if ($1) {$n", [orExpr])
|
startBlock(p, "if ($1) {$n", [orExpr])
|
||||||
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
||||||
genStmts(p, t.sons[i].sons[blen-1])
|
genStmts(p, t.sons[i].sons[blen-1])
|
||||||
dec p.popCurrExc
|
|
||||||
endBlock(p, ropecg(p.module, "#popCurrentException();}$n"))
|
endBlock(p, ropecg(p.module, "#popCurrentException();}$n"))
|
||||||
inc(i)
|
inc(i)
|
||||||
|
dec p.inExceptBlock
|
||||||
|
discard pop(p.nestedTryStmts)
|
||||||
appf(p.s(cpsStmts), "}$n") # end of else block
|
appf(p.s(cpsStmts), "}$n") # end of else block
|
||||||
if i < length and t.sons[i].kind == nkFinally:
|
if i < length and t.sons[i].kind == nkFinally:
|
||||||
genSimpleBlock(p, t.sons[i].sons[0])
|
genSimpleBlock(p, t.sons[i].sons[0])
|
||||||
|
|
@ -820,9 +828,8 @@ proc genStmts(p: BProc, t: PNode) =
|
||||||
initLocExpr(p, t.sons[0], a)
|
initLocExpr(p, t.sons[0], a)
|
||||||
of nkAsmStmt: genAsmStmt(p, t)
|
of nkAsmStmt: genAsmStmt(p, t)
|
||||||
of nkTryStmt:
|
of nkTryStmt:
|
||||||
#if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t)
|
if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t)
|
||||||
#else:
|
else: genTryStmt(p, t)
|
||||||
genTryStmt(p, t)
|
|
||||||
of nkRaiseStmt: genRaiseStmt(p, t)
|
of nkRaiseStmt: genRaiseStmt(p, t)
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
# we have to emit the type information for object types here to support
|
# we have to emit the type information for object types here to support
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,9 @@ type
|
||||||
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
|
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||||
# (the vars must be volatile then)
|
# (the vars must be volatile then)
|
||||||
popCurrExc*: Natural # how often to emit 'popCurrentException()'
|
inExceptBlock*: int # are we currently inside an except block?
|
||||||
# before 'break'|'return'
|
# leaving such scopes by raise or by return must
|
||||||
|
# execute any applicable finally blocks
|
||||||
labels*: Natural # for generating unique labels in the C proc
|
labels*: Natural # for generating unique labels in the C proc
|
||||||
blocks*: seq[TBlock] # nested blocks
|
blocks*: seq[TBlock] # nested blocks
|
||||||
breakIdx*: int # the block that will be exited
|
breakIdx*: int # the block that will be exited
|
||||||
|
|
|
||||||
66
tests/run/texceptions.nim
Normal file
66
tests/run/texceptions.nim
Normal file
|
|
@ -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"
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue