Skip to content

Commit

Permalink
fixes #13782 (#13834)
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq authored Apr 1, 2020
1 parent 4816984 commit bc37668
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 20 deletions.
75 changes: 56 additions & 19 deletions compiler/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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)

Expand Down Expand Up @@ -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(~", ")
Expand All @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand All @@ -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)
3 changes: 3 additions & 0 deletions compiler/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions compiler/cgendata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
22 changes: 21 additions & 1 deletion tests/destructor/tgotoexceptions4.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ discard """
caught in fun
caughtsome msgMyExcept
in finally
caught1'''
caught1
123
123'''
"""

when true:
Expand Down Expand Up @@ -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()

0 comments on commit bc37668

Please sign in to comment.