Fixed #688 : return in except statments. Also fixed return in finally statements.
This commit is contained in:
parent
ef379d0a10
commit
739b4f214b
2 changed files with 30 additions and 18 deletions
|
|
@ -263,33 +263,33 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||||
|
|
||||||
|
|
||||||
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||||
# This is called by return and break stmts.
|
# Called by return and break stmts.
|
||||||
# When jumping out of try/except/finally stmts,
|
# Deals with issues faced when jumping out of try/except/finally stmts,
|
||||||
# we need to pop safe points from try statements,
|
|
||||||
# execute finally-stmts, and pop exceptions
|
|
||||||
# from except stmts
|
|
||||||
|
|
||||||
let L = p.nestedTryStmts.len
|
|
||||||
|
|
||||||
# danger of endless recursion! we workaround this here by a temp stack
|
|
||||||
var stack: seq[PNode]
|
var stack: seq[PNode]
|
||||||
newSeq(stack, howManyTrys)
|
newSeq(stack, 0)
|
||||||
for i in countup(1, howManyTrys):
|
|
||||||
stack[i-1] = p.nestedTryStmts[L-i]
|
|
||||||
setLen(p.nestedTryStmts, L-howManyTrys)
|
|
||||||
|
|
||||||
var alreadyPoppedCnt = p.inExceptBlock
|
var alreadyPoppedCnt = p.inExceptBlock
|
||||||
for tryStmt in items(stack):
|
for i in countup(1, howManyTrys):
|
||||||
|
|
||||||
if gCmd != cmdCompileToCpp:
|
if gCmd != cmdCompileToCpp:
|
||||||
|
# Pop safe points generated by try
|
||||||
if alreadyPoppedCnt > 0:
|
if alreadyPoppedCnt > 0:
|
||||||
dec alreadyPoppedCnt
|
dec alreadyPoppedCnt
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||||
# Find finally-stmts for this try-stmt
|
|
||||||
# and generate a copy of the finally stmts here
|
# Pop this try-stmt of the list of nested trys
|
||||||
|
# so we don't infinite recurse on it in the next step.
|
||||||
|
var tryStmt = p.nestedTryStmts.pop
|
||||||
|
stack.add(tryStmt)
|
||||||
|
|
||||||
|
# Find finally-stmt for this try-stmt
|
||||||
|
# and generate a copy of its sons
|
||||||
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(howManyTrys-1, 0):
|
for i in countdown(howManyTrys-1, 0):
|
||||||
p.nestedTryStmts.add(stack[i])
|
p.nestedTryStmts.add(stack[i])
|
||||||
|
|
@ -304,7 +304,14 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||||
p.beforeRetNeeded = true
|
p.beforeRetNeeded = true
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
|
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
|
||||||
blockLeaveActions(p, min(1, p.nestedTryStmts.len), p.inExceptBlock)
|
blockLeaveActions(p,
|
||||||
|
howManyTrys = p.nestedTryStmts.len,
|
||||||
|
howManyExcepts = p.inExceptBlock)
|
||||||
|
if (p.finallySafePoints.len > 0):
|
||||||
|
# If we're in a finally block, and we came here by exception
|
||||||
|
# consume it before we return.
|
||||||
|
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
||||||
|
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
|
||||||
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
||||||
|
|
||||||
proc genComputedGoto(p: BProc; n: PNode) =
|
proc genComputedGoto(p: BProc; n: PNode) =
|
||||||
|
|
@ -843,7 +850,9 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
discard pop(p.nestedTryStmts)
|
discard pop(p.nestedTryStmts)
|
||||||
endBlock(p) # end of else block
|
endBlock(p) # end of else block
|
||||||
if i < length and t.sons[i].kind == nkFinally:
|
if i < length and t.sons[i].kind == nkFinally:
|
||||||
|
p.finallySafePoints.add(safePoint)
|
||||||
exprBlock(p, t.sons[i].sons[0], d)
|
exprBlock(p, t.sons[i].sons[0], d)
|
||||||
|
discard pop(p.finallySafePoints)
|
||||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||||
|
|
||||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,13 @@ type
|
||||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
prc*: PSym # the Nimrod proc that this C proc belongs to
|
||||||
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
||||||
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)
|
||||||
inExceptBlock*: int # are we currently inside an except block?
|
inExceptBlock*: int # are we currently inside an except block?
|
||||||
# leaving such scopes by raise or by return must
|
# leaving such scopes by raise or by return must
|
||||||
# execute any applicable finally blocks
|
# execute any applicable finally blocks
|
||||||
|
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
|
||||||
|
# using return in finally statements
|
||||||
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
|
||||||
|
|
@ -142,6 +144,7 @@ proc newProc*(prc: PSym, module: BModule): BProc =
|
||||||
else: result.options = gOptions
|
else: result.options = gOptions
|
||||||
newSeq(result.blocks, 1)
|
newSeq(result.blocks, 1)
|
||||||
result.nestedTryStmts = @[]
|
result.nestedTryStmts = @[]
|
||||||
|
result.finallySafePoints = @[]
|
||||||
|
|
||||||
iterator cgenModules*: var BModule =
|
iterator cgenModules*: var BModule =
|
||||||
for i in 0..high(gModules):
|
for i in 0..high(gModules):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue