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 /compiler/ccgcalls.nim | |
parent | 48169847265e13d3b12d670230ad6d33a9d384cc (diff) | |
download | Nim-bc37668c5a6f1664b34a16af2dee8aa9218b97a4.tar.gz |
fixes #13782 (#13834)
Diffstat (limited to 'compiler/ccgcalls.nim')
-rw-r--r-- | compiler/ccgcalls.nim | 75 |
1 files changed, 56 insertions, 19 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) |