implement bare 'raise' statement outside of except blocks
authorStefan Behnel <stefan_ml@behnel.de>
Fri, 24 Aug 2012 15:45:14 +0000 (17:45 +0200)
committerStefan Behnel <stefan_ml@behnel.de>
Fri, 24 Aug 2012 15:45:14 +0000 (17:45 +0200)
Cython/Compiler/Nodes.py
Cython/Utility/Exceptions.c
tests/run/reraise.py [new file with mode: 0644]

index e2119ec..188de3d 100644 (file)
@@ -5006,7 +5006,7 @@ class ReraiseStatNode(StatNode):
     is_terminator = True
 
     def analyse_expressions(self, env):
-        env.use_utility_code(restore_exception_utility_code)
+        pass
 
     nogil_check = Node.gil_error
     gil_message = "Raising exception"
@@ -5014,6 +5014,7 @@ class ReraiseStatNode(StatNode):
     def generate_execution_code(self, code):
         vars = code.funcstate.exc_vars
         if vars:
+            code.globalstate.use_utility_code(restore_exception_utility_code)
             for varname in vars:
                 code.put_giveref(varname)
             code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars))
@@ -5022,8 +5023,9 @@ class ReraiseStatNode(StatNode):
             code.putln()
             code.putln(code.error_goto(self.pos))
         else:
-            error(self.pos, "Reraise not inside except clause")
-
+            code.globalstate.use_utility_code(
+                UtilityCode.load_cached("ReRaiseException", "Exceptions.c"))
+            code.putln("__Pyx_ReraiseException(); %s" % code.error_goto(self.pos))
 
 class AssertStatNode(StatNode):
     #  assert statement
index 33b068e..4de4c36 100644 (file)
@@ -255,6 +255,41 @@ bad:
     return -1;
 }
 
+/////////////// ReRaiseException.proto ///////////////
+
+static CYTHON_INLINE void __Pyx_ReraiseException(void); /*proto*/
+
+/////////////// ReRaiseException.proto ///////////////
+
+static CYTHON_INLINE void __Pyx_ReraiseException(void) {
+    PyObject *type = NULL, *value = NULL, *tb = NULL;
+#if CYTHON_COMPILING_IN_CPYTHON
+    PyThreadState *tstate = PyThreadState_GET();
+    type = tstate->exc_type;
+    value = tstate->exc_value;
+    tb = tstate->exc_traceback;
+#else
+    PyErr_GetExcInfo(type, value, tb);
+#endif
+    if (!type || type == Py_None) {
+#if !CYTHON_COMPILING_IN_CPYTHON
+        Py_XDECREF(type);
+        Py_XDECREF(value);
+        Py_XDECREF(tb);
+#endif
+        PyErr_SetString(PyExc_RuntimeError,
+            "No active exception to reraise"); // message copied from Py3
+    } else {
+#if CYTHON_COMPILING_IN_CPYTHON
+        Py_INCREF(type);
+        Py_XINCREF(value);
+        Py_XINCREF(tb);
+
+#endif
+        PyErr_Restore(type, value, tb);
+    }
+}
+
 /////////////// SaveResetException.proto ///////////////
 
 static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
diff --git a/tests/run/reraise.py b/tests/run/reraise.py
new file mode 100644 (file)
index 0000000..1303266
--- /dev/null
@@ -0,0 +1,35 @@
+
+def reraise():
+    raise
+
+def test_reraise():
+    """
+    >>> test_reraise()
+    Traceback (most recent call last):
+    ValueError: TEST
+    """
+    try:
+        raise ValueError("TEST")
+    except ValueError:
+        raise
+
+def test_reraise_indirect():
+    """
+    >>> test_reraise_indirect()
+    Traceback (most recent call last):
+    ValueError: TEST INDIRECT
+    """
+    try:
+        raise ValueError("TEST INDIRECT")
+    except ValueError:
+        reraise()
+
+def test_reraise_error():
+    """
+    >>> try: test_reraise_error()
+    ... except (RuntimeError, TypeError): pass  # Py2, Py3, ...
+    ... else: print("FAILED")
+    """
+    import sys
+    sys.exc_clear()
+    raise