mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-03 11:42:33 +00:00
@@ -37,6 +37,10 @@ proc isAssignedImmediately(n: PNode): bool {.inline.} =
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc inExceptBlockLen(p: BProc): int =
|
||||
for x in p.nestedTryStmts:
|
||||
if x.inExcept: result.inc
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
|
||||
@@ -96,7 +100,7 @@ proc startBlock(p: BProc, start: FormatStr = "{$n",
|
||||
setLen(p.blocks, result + 1)
|
||||
p.blocks[result].id = p.labels
|
||||
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
|
||||
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
|
||||
p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16
|
||||
|
||||
proc assignLabel(b: var TBlock): Rope {.inline.} =
|
||||
b.label = "LA" & b.id.rope
|
||||
@@ -344,26 +348,22 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
# Called by return and break stmts.
|
||||
# Deals with issues faced when jumping out of try/except/finally stmts,
|
||||
|
||||
var stack: seq[PNode]
|
||||
newSeq(stack, 0)
|
||||
var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
|
||||
|
||||
var alreadyPoppedCnt = p.inExceptBlock
|
||||
for i in countup(1, howManyTrys):
|
||||
let tryStmt = p.nestedTryStmts.pop
|
||||
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
|
||||
# Pop safe points generated by try
|
||||
if alreadyPoppedCnt > 0:
|
||||
dec alreadyPoppedCnt
|
||||
else:
|
||||
if not tryStmt.inExcept:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
|
||||
# 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.n)
|
||||
if finallyStmt.kind == nkFinally:
|
||||
genStmts(p, finallyStmt.sons[0])
|
||||
|
||||
@@ -384,7 +384,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
|
||||
blockLeaveActions(p,
|
||||
howManyTrys = p.nestedTryStmts.len,
|
||||
howManyExcepts = p.inExceptBlock)
|
||||
howManyExcepts = p.inExceptBlockLen)
|
||||
if (p.finallySafePoints.len > 0):
|
||||
# If we're in a finally block, and we came here by exception
|
||||
# consume it before we return.
|
||||
@@ -567,15 +567,15 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||
let label = assignLabel(p.blocks[idx])
|
||||
blockLeaveActions(p,
|
||||
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
|
||||
p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
|
||||
p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts)
|
||||
genLineDir(p, t)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [label])
|
||||
|
||||
proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
if p.inExceptBlock > 0 and p.inExceptBlock == p.nestedTryStmts.len:
|
||||
if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
|
||||
# if the current try stmt have a finally block,
|
||||
# we must execute it before reraising
|
||||
var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
|
||||
var finallyBlock = p.nestedTryStmts[^1].n[^1]
|
||||
if finallyBlock.kind == nkFinally:
|
||||
genSimpleBlock(p, finallyBlock.sons[0])
|
||||
if t.sons[0].kind != nkEmpty:
|
||||
@@ -812,14 +812,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
|
||||
let end_label = getLabel(p)
|
||||
discard cgsym(p.module, "Exception")
|
||||
add(p.nestedTryStmts, t)
|
||||
add(p.nestedTryStmts, (t, false))
|
||||
startBlock(p, "try {$n")
|
||||
expr(p, t[0], d)
|
||||
endBlock(p)
|
||||
|
||||
var catchAllPresent = false
|
||||
|
||||
inc p.inExceptBlock
|
||||
p.nestedTryStmts[^1].inExcept = true
|
||||
for i in 1..<t.len:
|
||||
if t[i].kind != nkExceptBranch: break
|
||||
|
||||
@@ -839,6 +839,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
|
||||
endBlock(p)
|
||||
|
||||
discard pop(p.nestedTryStmts)
|
||||
|
||||
if not catchAllPresent and t[^1].kind == nkFinally:
|
||||
# finally requires catch all presence
|
||||
startBlock(p, "catch (...) {$n")
|
||||
@@ -846,9 +848,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
endBlock(p)
|
||||
|
||||
dec p.inExceptBlock
|
||||
discard pop(p.nestedTryStmts)
|
||||
|
||||
if t[^1].kind == nkFinally:
|
||||
genSimpleBlock(p, t[^1][0])
|
||||
|
||||
@@ -902,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
var length = sonsLen(t)
|
||||
add(p.nestedTryStmts, t)
|
||||
add(p.nestedTryStmts, (t, false))
|
||||
expr(p, t.sons[0], d)
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
endBlock(p)
|
||||
@@ -910,7 +909,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
if optStackTrace in p.options:
|
||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
||||
inc p.inExceptBlock
|
||||
p.nestedTryStmts[^1].inExcept = true
|
||||
var i = 1
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
@@ -941,7 +940,6 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
endBlock(p)
|
||||
inc(i)
|
||||
dec p.inExceptBlock
|
||||
discard pop(p.nestedTryStmts)
|
||||
endBlock(p) # end of else block
|
||||
if i < length and t.sons[i].kind == nkFinally:
|
||||
|
||||
@@ -70,11 +70,10 @@ type
|
||||
threadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
|
||||
currLineInfo*: TLineInfo # AST codegen will make this superfluous
|
||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
inExceptBlock*: int # are we currently inside an except block?
|
||||
# leaving such scopes by raise or by return must
|
||||
# execute any applicable finally blocks
|
||||
nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
|
||||
# in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
# bool is true when are in the except part of a try block
|
||||
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
|
||||
# using return in finally statements
|
||||
labels*: Natural # for generating unique labels in the C proc
|
||||
|
||||
@@ -7,6 +7,11 @@ msg1
|
||||
msg2
|
||||
finally2
|
||||
finally1
|
||||
-----------
|
||||
except1
|
||||
finally1
|
||||
except2
|
||||
finally2
|
||||
'''
|
||||
"""
|
||||
# Test return in try statement:
|
||||
@@ -39,4 +44,19 @@ proc nested_finally =
|
||||
finally:
|
||||
echo "finally1"
|
||||
|
||||
nested_finally()
|
||||
nested_finally()
|
||||
|
||||
echo "-----------"
|
||||
#bug 7414
|
||||
try:
|
||||
try:
|
||||
raise newException(Exception, "Hello")
|
||||
except:
|
||||
echo "except1"
|
||||
raise
|
||||
finally:
|
||||
echo "finally1"
|
||||
except:
|
||||
echo "except2"
|
||||
finally:
|
||||
echo "finally2"
|
||||
Reference in New Issue
Block a user