summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2019-01-03 18:56:05 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-01-03 18:56:05 +0100
commitcb9110c43d4ae9c29a0a1e0d54f7735712d4ba62 (patch)
tree630e4ab6d76a8415beb7d8135ea9531179d99c78
parent2ee2022c29ec4774eda51cb431052a9fc24982a7 (diff)
downloadNim-cb9110c43d4ae9c29a0a1e0d54f7735712d4ba62.tar.gz
--define:nimQuirky exception handling for Nim; in preparation of a blog post
-rw-r--r--compiler/ccgstmts.nim58
-rw-r--r--compiler/lineinfos.nim2
-rw-r--r--compiler/pragmas.nim6
-rw-r--r--compiler/semcall.nim1
-rw-r--r--compiler/vm.nim18
-rw-r--r--lib/system.nim22
-rw-r--r--lib/system/excpt.nim2
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):