summary refs log tree commit diff stats
path: root/tests/destructor
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-01-01 10:01:49 +0100
committerGitHub <noreply@github.com>2020-01-01 10:01:49 +0100
commitc3344862b0d6061cc1581f29c81b29b75c78615a (patch)
tree75661179ec450bb4e2783603c09f4304dfe42a45 /tests/destructor
parent8a63caca07349742d071dcd3a7d3e3055fe617cf (diff)
downloadNim-c3344862b0d6061cc1581f29c81b29b75c78615a.tar.gz
--exception:goto switch for deterministic exception handling (#12977)
This implements "deterministic" exception handling for Nim based on goto instead of setjmp. This means raising an exception is much cheaper than in C++'s table based implementations. Supports hard realtime systems. Default for --gc:arc and the C target because it's generally a good idea and arc is all about deterministic behavior.

Note: This implies that fatal runtime traps are not catchable anymore! This needs to be documented.
Diffstat (limited to 'tests/destructor')
-rwxr-xr-xtests/destructor/tgotoexceptions.nim117
-rw-r--r--tests/destructor/tgotoexceptions2.nim104
-rw-r--r--tests/destructor/tgotoexceptions3.nim7
3 files changed, 228 insertions, 0 deletions
diff --git a/tests/destructor/tgotoexceptions.nim b/tests/destructor/tgotoexceptions.nim
new file mode 100755
index 000000000..f76592270
--- /dev/null
+++ b/tests/destructor/tgotoexceptions.nim
@@ -0,0 +1,117 @@
+discard """
+  output: '''
+msg1
+msg2
+finally2
+finally1
+begin
+one iteration!
+caught!
+except1
+finally1
+caught! 2
+BEFORE
+FINALLY
+BEFORE
+EXCEPT
+FINALLY
+RECOVER
+BEFORE
+EXCEPT: IOError: hi
+FINALLY
+'''
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+"""
+
+#bug 7204
+proc nested_finally =
+  try:
+    raise newException(KeyError, "msg1")
+  except KeyError as ex:
+    echo ex.msg
+    try:
+      raise newException(ValueError, "msg2")
+    except:
+      echo getCurrentExceptionMsg()
+    finally:
+      echo "finally2"
+  finally:
+    echo "finally1"
+
+nested_finally()
+
+proc doraise =
+  raise newException(ValueError, "gah")
+
+proc main =
+  while true:
+    try:
+      echo "begin"
+      doraise()
+    finally:
+      echo "one ", "iteration!"
+
+try:
+  main()
+except:
+  echo "caught!"
+
+when true:
+  proc p =
+    try:
+      raise newException(Exception, "Hello")
+    except:
+      echo "except1"
+      raise
+    finally:
+      echo "finally1"
+
+  try:
+    p()
+  except:
+    echo "caught! 2"
+
+
+proc noException =
+  try:
+    echo "BEFORE"
+
+  except:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: noException()
+except: echo "RECOVER"
+
+proc reraise_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "")
+
+  except IOError:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: reraise_in_except()
+except: echo "RECOVER"
+
+proc return_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "hi")
+
+  except:
+    echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg()
+    return
+
+  finally:
+    echo "FINALLY"
+
+try: return_in_except()
+except: echo "RECOVER"
diff --git a/tests/destructor/tgotoexceptions2.nim b/tests/destructor/tgotoexceptions2.nim
new file mode 100644
index 000000000..057caf7b7
--- /dev/null
+++ b/tests/destructor/tgotoexceptions2.nim
@@ -0,0 +1,104 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+  output: '''
+B1
+B2
+catch
+A1
+1
+B1
+B2
+catch
+A1
+A2
+0
+B1
+B2
+A1
+1
+B1
+B2
+A1
+A2
+3
+A
+B
+C
+'''
+"""
+
+# More thorough test of return-in-finaly
+
+var raiseEx = true
+var returnA = true
+var returnB = false
+
+proc main: int =
+  try: #A
+    try: #B
+      if raiseEx:
+        raise newException(OSError, "")
+      return 3
+    finally: #B
+      echo "B1"
+      if returnB:
+        return 2
+      echo "B2"
+  except OSError: #A
+    echo "catch"
+  finally: #A
+    echo "A1"
+    if returnA:
+      return 1
+    echo "A2"
+
+for x in [true, false]:
+  for y in [true, false]:
+    # echo "raiseEx: " & $x
+    # echo "returnA: " & $y
+    # echo "returnB: " & $z
+    # in the original test returnB was set to true too and
+    # this leads to swallowing the OSError exception. This is
+    # somewhat compatible with Python but it's non-sense, 'finally'
+    # should not be allowed to swallow exceptions. The goto based
+    # implementation does something sane so we don't "correct" its
+    # behavior just to be compatible with v1.
+    raiseEx = x
+    returnA = y
+    echo main()
+
+# Various tests of return nested in double try/except statements
+
+proc test1() =
+
+  defer: echo "A"
+
+  try:
+    raise newException(OSError, "Problem")
+  except OSError:
+    return
+
+test1()
+
+
+proc test2() =
+
+  defer: echo "B"
+
+  try:
+    return
+  except OSError:
+    discard
+
+test2()
+
+proc test3() =
+  try:
+    try:
+      raise newException(OSError, "Problem")
+    except OSError:
+      return
+  finally:
+    echo "C"
+
+test3()
diff --git a/tests/destructor/tgotoexceptions3.nim b/tests/destructor/tgotoexceptions3.nim
new file mode 100644
index 000000000..308d288b2
--- /dev/null
+++ b/tests/destructor/tgotoexceptions3.nim
@@ -0,0 +1,7 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+  outputsub: "Error: unhandled exception: Problem [OSError]"
+  exitcode: "1"
+"""
+
+raise newException(OSError, "Problem")