diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-04-01 20:30:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-01 20:30:28 +0200 |
commit | bc37668c5a6f1664b34a16af2dee8aa9218b97a4 (patch) | |
tree | 893c8d78a061209f3d418859f5868539b36ed28e | |
parent | 48169847265e13d3b12d670230ad6d33a9d384cc (diff) | |
download | Nim-bc37668c5a6f1664b34a16af2dee8aa9218b97a4.tar.gz |
fixes #13782 (#13834)
-rw-r--r-- | compiler/ccgcalls.nim | 75 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 3 | ||||
-rw-r--r-- | compiler/cgendata.nim | 1 | ||||
-rw-r--r-- | tests/destructor/tgotoexceptions4.nim | 22 |
4 files changed, 81 insertions, 20 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index de979f4a0..9155064a5 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..<ri.len: @@ -18,8 +30,19 @@ proc leftAppearsOnRightSide(le, ri: PNode): bool = proc hasNoInit(call: PNode): bool {.inline.} = result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags +proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool = + if d.k in {locTemp, locNone} or not canRaise: + result = true + elif d.k == locLocalVar and p.withinTryWithExcept == 0: + # we cannot observe a store to a local variable if the current proc + # has no error handler: + result = true + else: + result = false + proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, callee, params: Rope) = + let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0]) genLineDir(p, ri) var pl = callee & ~"(" & params # getUniqueType() is too expensive here: @@ -44,6 +67,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl.add(~");$n") line(p, cpsStmts, pl) genAssignment(p, d, tmp, {}) # no need for deep copying + if canRaise: raiseExit(p) else: pl.add(~")") if p.module.compileToCpp: @@ -63,16 +87,29 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, initLoc(list, locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying - else: + if canRaise: raiseExit(p) + + 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 initLoc(list, locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying + if canRaise: raiseExit(p) + else: + var tmp: TLoc + getTemp(p, typ[0], tmp, needsInit=true) + var list: TLoc + initLoc(list, locCall, d.lode, OnUnknown) + list.r = pl + genAssignment(p, tmp, list, {}) # no need for deep copying + if canRaise: raiseExit(p) + genAssignment(p, d, tmp, {}) else: pl.add(~");$n") line(p, cpsStmts, pl) + if canRaise: raiseExit(p) proc genBoundsCheck(p: BProc; arr, a, b: TLoc) @@ -244,6 +281,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc]) let rawProc = getRawProcType(p, typ) + let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0]) if typ[0] != nil: if isInvalidReturnType(p.config, typ[0]): if ri.len > 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 c1012cede..bb9d30b8f 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 326bdeb45..bf7daeea6 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 918169084..b2b481256 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() |