diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index de979f4a0c..9155064a5b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -9,6 +9,18 @@ # # included from cgen.nim +proc canRaiseDisp(p: BProc; n: PNode): bool = + # we assume things like sysFatal cannot raise themselves + if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: + result = false + elif optPanics in p.config.globalOptions or + (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): + # we know we can be strict: + result = canRaise(n) + else: + # we have to be *very* conservative: + result = canRaiseConservative(n) + proc leftAppearsOnRightSide(le, ri: PNode): bool = if le != nil: for i in 1.. 1: pl.add(~", ") @@ -262,8 +300,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) genCallPattern() + if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) # no need for deep copying - else: + elif isHarmlessStore(p, canRaise, d): if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc @@ -272,10 +311,24 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] else: list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] - genAssignment(p, d, list, {}) # no need for deep copying + if canRaise: raiseExit(p) + else: + var tmp: TLoc + getTemp(p, typ[0], tmp) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.lode, OnUnknown) + if tfIterator in typ.flags: + list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] + else: + list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] + genAssignment(p, tmp, list, {}) + if canRaise: raiseExit(p) + genAssignment(p, d, tmp, {}) else: genCallPattern() + if canRaise: raiseExit(p) proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = if i < typ.len: @@ -557,18 +610,6 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add(~"];$n") line(p, cpsStmts, pl) -proc canRaiseDisp(p: BProc; n: PNode): bool = - # we assume things like sysFatal cannot raise themselves - if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: - result = false - elif optPanics in p.config.globalOptions or - (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags): - # we know we can be strict: - result = canRaise(n) - else: - # we have to be *very* conservative: - result = canRaiseConservative(n) - proc genCall(p: BProc, e: PNode, d: var TLoc) = if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: genClosureCall(p, nil, e, d) @@ -579,8 +620,6 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) = else: genPrefixCall(p, nil, e, d) postStmtActions(p) - if p.config.exc == excGoto and canRaiseDisp(p, e[0]): - raiseExit(p) proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: @@ -592,5 +631,3 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = else: genPrefixCall(p, le, ri, d) postStmtActions(p) - if p.config.exc == excGoto and canRaiseDisp(p, ri[0]): - raiseExit(p) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c1012cedec..bb9d30b8fc 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1203,6 +1203,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let fin = if t[^1].kind == nkFinally: t[^1] else: nil inc p.labels let lab = p.labels + let hasExcept = t[1].kind == nkExceptBranch + if hasExcept: inc p.withinTryWithExcept p.nestedTryStmts.add((fin, false, Natural lab)) p.flags.incl nimErrorFlagAccessed @@ -1277,6 +1279,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) endBlock(p) if p.prc != nil: raiseExit(p) + if hasExcept: inc p.withinTryWithExcept proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # code to generate: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 326bdeb453..bf7daeea69 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -95,6 +95,7 @@ type splitDecls*: int # > 0 if we are in some context for C++ that # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) + withinTryWithExcept*: int # required for goto based exception handling sigConflicts*: CountTable[string] TTypeSeq* = seq[PType] diff --git a/tests/destructor/tgotoexceptions4.nim b/tests/destructor/tgotoexceptions4.nim index 9181690848..b2b481256a 100644 --- a/tests/destructor/tgotoexceptions4.nim +++ b/tests/destructor/tgotoexceptions4.nim @@ -4,7 +4,9 @@ discard """ caught in fun caughtsome msgMyExcept in finally -caught1''' +caught1 +123 +123''' """ when true: @@ -38,3 +40,21 @@ when true: except CatchableError: echo "caught1" funB() + +# bug #13782 + +import strutils +var n = 123 + +try: n = parseInt("xxx") +except: discard + +echo n + +proc sameTestButForLocalVar = + var n = 123 + try: n = parseInt("xxx") + except: discard + echo n + +sameTestButForLocalVar()