This commit is contained in:
cooldome 2018-03-29 08:19:03 +01:00 • committed by Andreas Rumpf
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 return false
result = true result = true
proc inExceptBlockLen(p: BProc): int =
for x in p.nestedTryStmts:
if x.inExcept: result.inc
proc genVarTuple(p: BProc, n: PNode) = proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc var tup, field: TLoc
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple") if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
@ -96,7 +100,7 @@ proc startBlock(p: BProc, start: FormatStr = "{$n",
setLen(p.blocks, result + 1) setLen(p.blocks, result + 1)
p.blocks[result].id = p.labels p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 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.} = proc assignLabel(b: var TBlock): Rope {.inline.} =
b.label = "LA" & b.id.rope b.label = "LA" & b.id.rope
@ -344,26 +348,22 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts. # Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts, # Deals with issues faced when jumping out of try/except/finally stmts,
var stack: seq[PNode] var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
newSeq(stack, 0)
var alreadyPoppedCnt = p.inExceptBlock
for i in countup(1, howManyTrys): for i in countup(1, howManyTrys):
let tryStmt = p.nestedTryStmts.pop
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
# Pop safe points generated by try # Pop safe points generated by try
if alreadyPoppedCnt > 0: if not tryStmt.inExcept:
dec alreadyPoppedCnt
else:
linefmt(p, cpsStmts, "#popSafePoint();$n") linefmt(p, cpsStmts, "#popSafePoint();$n")
# Pop this try-stmt of the list of nested trys # Pop this try-stmt of the list of nested trys
# so we don't infinite recurse on it in the next step. # so we don't infinite recurse on it in the next step.
var tryStmt = p.nestedTryStmts.pop
stack.add(tryStmt) stack.add(tryStmt)
# Find finally-stmt for this try-stmt # Find finally-stmt for this try-stmt
# and generate a copy of its sons # and generate a copy of its sons
var finallyStmt = lastSon(tryStmt) var finallyStmt = lastSon(tryStmt.n)
if finallyStmt.kind == nkFinally: if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0]) 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]) if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p, blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len, howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlock) howManyExcepts = p.inExceptBlockLen)
if (p.finallySafePoints.len > 0): if (p.finallySafePoints.len > 0):
# If we're in a finally block, and we came here by exception # If we're in a finally block, and we came here by exception
# consume it before we return. # consume it before we return.
@ -567,15 +567,15 @@ proc genBreakStmt(p: BProc, t: PNode) =
let label = assignLabel(p.blocks[idx]) let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlock - p.blocks[idx].nestedExceptStmts) p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t) genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label]) lineF(p, cpsStmts, "goto $1;$n", [label])
proc genRaiseStmt(p: BProc, t: PNode) = 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, # if the current try stmt have a finally block,
# we must execute it before reraising # 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: if finallyBlock.kind == nkFinally:
genSimpleBlock(p, finallyBlock.sons[0]) genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty: if t.sons[0].kind != nkEmpty:
@ -812,14 +812,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let end_label = getLabel(p) let end_label = getLabel(p)
discard cgsym(p.module, "Exception") discard cgsym(p.module, "Exception")
add(p.nestedTryStmts, t) add(p.nestedTryStmts, (t, false))
startBlock(p, "try {$n") startBlock(p, "try {$n")
expr(p, t[0], d) expr(p, t[0], d)
endBlock(p) endBlock(p)
var catchAllPresent = false var catchAllPresent = false
inc p.inExceptBlock p.nestedTryStmts[^1].inExcept = true
for i in 1..<t.len: for i in 1..<t.len:
if t[i].kind != nkExceptBranch: break 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 genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
endBlock(p) endBlock(p)
discard pop(p.nestedTryStmts)
if not catchAllPresent and t[^1].kind == nkFinally: if not catchAllPresent and t[^1].kind == nkFinally:
# finally requires catch all presence # finally requires catch all presence
startBlock(p, "catch (...) {$n") startBlock(p, "catch (...) {$n")
@ -846,9 +848,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
line(p, cpsStmts, ~"throw;$n") line(p, cpsStmts, ~"throw;$n")
endBlock(p) endBlock(p)
dec p.inExceptBlock
discard pop(p.nestedTryStmts)
if t[^1].kind == nkFinally: if t[^1].kind == nkFinally:
genSimpleBlock(p, t[^1][0]) 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) linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
startBlock(p, "if ($1.status == 0) {$n", [safePoint]) startBlock(p, "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t) var length = sonsLen(t)
add(p.nestedTryStmts, t) add(p.nestedTryStmts, (t, false))
expr(p, t.sons[0], d) expr(p, t.sons[0], d)
linefmt(p, cpsStmts, "#popSafePoint();$n") linefmt(p, cpsStmts, "#popSafePoint();$n")
endBlock(p) endBlock(p)
@ -910,7 +909,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "#popSafePoint();$n") linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.options: if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
inc p.inExceptBlock p.nestedTryStmts[^1].inExcept = true
var i = 1 var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
# bug #4230: avoid false sharing between branches: # 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") linefmt(p, cpsStmts, "#popCurrentException();$n")
endBlock(p) endBlock(p)
inc(i) inc(i)
dec p.inExceptBlock
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:

View file

@ -70,11 +70,10 @@ type
threadVarAccessed*: bool # true if the proc already accessed some threadvar threadVarAccessed*: bool # true if the proc already accessed some threadvar
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
currLineInfo*: TLineInfo # AST codegen will make this superfluous currLineInfo*: TLineInfo # AST codegen will make this superfluous
nestedTryStmts*: seq[PNode] # in how many nested try statements we are nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
# 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? # bool is true when are in the except part of a try block
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
# using return in finally statements # 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

View file

@ -7,6 +7,11 @@ msg1
msg2 msg2
finally2 finally2
finally1 finally1
-----------
except1
finally1
except2
finally2
''' '''
""" """
# Test return in try statement: # Test return in try statement:
@ -40,3 +45,18 @@ proc nested_finally =
echo "finally1" 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"