diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-01-03 18:56:05 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-01-03 18:56:05 +0100 |
commit | cb9110c43d4ae9c29a0a1e0d54f7735712d4ba62 (patch) | |
tree | 630e4ab6d76a8415beb7d8135ea9531179d99c78 | |
parent | 2ee2022c29ec4774eda51cb431052a9fc24982a7 (diff) | |
download | Nim-cb9110c43d4ae9c29a0a1e0d54f7735712d4ba62.tar.gz |
--define:nimQuirky exception handling for Nim; in preparation of a blog post
-rw-r--r-- | compiler/ccgstmts.nim | 58 | ||||
-rw-r--r-- | compiler/lineinfos.nim | 2 | ||||
-rw-r--r-- | compiler/pragmas.nim | 6 | ||||
-rw-r--r-- | compiler/semcall.nim | 1 | ||||
-rw-r--r-- | compiler/vm.nim | 18 | ||||
-rw-r--r-- | lib/system.nim | 22 | ||||
-rw-r--r-- | lib/system/excpt.nim | 2 |
7 files changed, 77 insertions, 32 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 6c33b302d..a077331c4 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -167,7 +167,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = let tryStmt = p.nestedTryStmts.pop if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions: # Pop safe points generated by try - if not tryStmt.inExcept: + if not tryStmt.inExcept and not isDefined(p.config, "nimQuirky"): linefmt(p, cpsStmts, "#popSafePoint();$n") # Pop this try-stmt of the list of nested trys @@ -382,7 +382,7 @@ proc genReturnStmt(p: BProc, t: PNode) = blockLeaveActions(p, howManyTrys = p.nestedTryStmts.len, howManyExcepts = p.inExceptBlockLen) - if (p.finallySafePoints.len > 0): + if (p.finallySafePoints.len > 0) and not isDefined(p.config, "nimQuirky"): # If we're in a finally block, and we came here by exception # consume it before we return. var safePoint = p.finallySafePoints[p.finallySafePoints.len-1] @@ -919,29 +919,38 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = # if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) - p.module.includeHeader("<setjmp.h>") + let quirkyExceptions = isDefined(p.config, "nimQuirky") + if not quirkyExceptions: + p.module.includeHeader("<setjmp.h>") genLineDir(p, t) - var safePoint = getTempName(p.module) discard cgsym(p.module, "Exception") - linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) - linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) - if isDefined(p.config, "nimStdSetjmp"): - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) - elif isDefined(p.config, "nimSigSetjmp"): - linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint) - elif isDefined(p.config, "nimRawSetjmp"): - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint) - else: - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) - startBlock(p, "if ($1.status == 0) {$n", [safePoint]) + var safePoint: Rope + if not quirkyExceptions: + safePoint = getTempName(p.module) + linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) + linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) + if isDefined(p.config, "nimStdSetjmp"): + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + elif isDefined(p.config, "nimSigSetjmp"): + linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint) + elif isDefined(p.config, "nimRawSetjmp"): + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint) + else: + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + startBlock(p, "if ($1.status == 0) {$n", [safePoint]) var length = sonsLen(t) add(p.nestedTryStmts, (t, false)) expr(p, t.sons[0], d) - linefmt(p, cpsStmts, "#popSafePoint();$n") - endBlock(p) - startBlock(p, "else {$n") - linefmt(p, cpsStmts, "#popSafePoint();$n") - genRestoreFrameAfterException(p) + if not quirkyExceptions: + linefmt(p, cpsStmts, "#popSafePoint();$n") + endBlock(p) + startBlock(p, "else {$n") + linefmt(p, cpsStmts, "#popSafePoint();$n") + genRestoreFrameAfterException(p) + elif 1 < length and t.sons[1].kind == nkExceptBranch: + startBlock(p, "if (#getCurrentException()) {$n") + else: + startBlock(p) p.nestedTryStmts[^1].inExcept = true var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): @@ -952,7 +961,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = # general except section: if i > 1: lineF(p, cpsStmts, "else", []) startBlock(p) - linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) + if not quirkyExceptions: + linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) expr(p, t.sons[i].sons[0], d) linefmt(p, cpsStmts, "#popCurrentException();$n") endBlock(p) @@ -968,7 +978,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = [genTypeInfo(p.module, t[i][j].typ, t[i][j].info)]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) - linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) + if not quirkyExceptions: + linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) expr(p, t.sons[i].sons[blen-1], d) linefmt(p, cpsStmts, "#popCurrentException();$n") endBlock(p) @@ -979,7 +990,8 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = p.finallySafePoints.add(safePoint) genSimpleBlock(p, t.sons[i].sons[0]) discard pop(p.finallySafePoints) - linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint) + if not quirkyExceptions: + linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint) proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = var res = "" diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index b1ecf779e..e8bdb1dca 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -224,7 +224,7 @@ type proc `==`*(a, b: FileIndex): bool {.borrow.} -proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} = +proc raiseRecoverableError*(msg: string) {.noinline.} = raise newException(ERecoverableError, msg) const diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 58f64f7b0..7db25a7d1 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -864,7 +864,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, incl(sym.flags, sfSideEffect) of wNoreturn: noVal(c, it) - incl(sym.flags, sfNoReturn) + # Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode! + if not isDefined(c.config, "nimQuirky"): + incl(sym.flags, sfNoReturn) if sym.typ[0] != nil: localError(c.config, sym.ast[paramsPos][0].info, ".noreturn with return type not allowed") @@ -1119,7 +1121,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: sym.flags.incl sfUsed of wLiftLocals: discard else: invalidPragma(c, it) - elif sym == nil or (sym != nil and sym.kind in {skVar, skLet, skParam, + elif sym == nil or (sym != nil and sym.kind in {skVar, skLet, skParam, skField, skProc, skFunc, skConverter, skMethod, skType}): n.sons[i] = semCustomPragma(c, it) elif sym != nil: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 7e0ea5490..5d77d8325 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -239,6 +239,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = if c.config.m.errorOutputs == {}: # fail fast: globalError(c.config, n.info, "type mismatch") + return if errors.len == 0: localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree) return diff --git a/compiler/vm.nim b/compiler/vm.nim index c8784c3e7..698635956 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -80,7 +80,7 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = add(s, x.prc.name.s) msgWriteln(c.config, s) -proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, +proc stackTraceB(c: PCtx, tos: PStackFrame, pc: int, msg: string, lineInfo: TLineInfo) = msgWriteln(c.config, "stack trace: (most recent call last)") stackTraceAux(c, tos, pc) @@ -88,8 +88,14 @@ proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, if c.mode == emRepl: globalError(c.config, lineInfo, msg) else: localError(c.config, lineInfo, msg) -proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) = - stackTrace(c, tos, pc, msg, c.debug[pc]) +template stackTrace(c: PCtx, tos: PStackFrame, pc: int, + msg: string, lineInfo: TLineInfo) = + stackTraceB(c, tos, pc, msg, lineInfo) + return + +template stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) = + stackTraceB(c, tos, pc, msg, c.debug[pc]) + return proc bailOut(c: PCtx; tos: PStackFrame) = stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " & @@ -950,13 +956,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeBC(rkInt) let a = regs[rb].node let b = regs[rc].node - if a.kind == nkSym and a.sym.kind in skProcKinds and + if a.kind == nkSym and a.sym.kind in skProcKinds and b.kind == nkSym and b.sym.kind in skProcKinds: regs[ra].intVal = if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1 else: 0 - else: - stackTrace(c, tos, pc, "node is not a proc symbol") + else: + stackTrace(c, tos, pc, "node is not a proc symbol") of opcEcho: let rb = instr.regB if rb == 1: diff --git a/lib/system.nim b/lib/system.nim index b9f86f549..38f45ff7a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2968,6 +2968,28 @@ when not declared(sysFatal): proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = rawoutput(message) panic(arg) + elif defined(nimQuirky): + proc name(t: typedesc): string {.magic: "TypeTrait".} + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = + var buf = newStringOfCap(200) + add(buf, "Error: unhandled exception: ") + add(buf, message) + add(buf, " [") + add(buf, name exceptn) + add(buf, "]") + echo buf + quit 1 + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = + var buf = newStringOfCap(200) + add(buf, "Error: unhandled exception: ") + add(buf, message) + add(buf, arg) + add(buf, " [") + add(buf, name exceptn) + add(buf, "]") + echo buf + quit 1 else: proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = var e: ref exceptn diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 84a1da343..3c0e42c6e 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -357,6 +357,8 @@ proc raiseExceptionAux(e: ref Exception) = raiseCounter.inc # skip zero at overflow e.raiseId = raiseCounter {.emit: "`e`->raise();".} + elif defined(nimQuirky): + if currException == nil: currException = e else: if excHandler != nil: if not excHandler.hasRaiseAction or excHandler.raiseAction(e): |