This commit is contained in:
cooldome
2018-03-29 08:19:03 +01:00
committed by Andreas Rumpf
parent 50229293ae
commit bcda71a8a7
3 changed files with 44 additions and 27 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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"