Commit b93cdb56 authored by Stefan Behnel's avatar Stefan Behnel

Initial (incomplete) attempt at supporting the Py3.7 exception state stack.

parent bc487ccb
...@@ -4256,7 +4256,10 @@ class GeneratorBodyDefNode(DefNode): ...@@ -4256,7 +4256,10 @@ class GeneratorBodyDefNode(DefNode):
code.put_xgiveref(Naming.retval_cname) code.put_xgiveref(Naming.retval_cname)
else: else:
code.put_xdecref_clear(Naming.retval_cname, py_object_type) code.put_xdecref_clear(Naming.retval_cname, py_object_type)
# For Py3.7, clearing is already done below.
code.putln("#if !CYTHON_USE_EXC_INFO_STACK")
code.putln("__Pyx_Coroutine_ResetAndClearException(%s);" % Naming.generator_cname) code.putln("__Pyx_Coroutine_ResetAndClearException(%s);" % Naming.generator_cname)
code.putln("#endif")
code.putln('%s->resume_label = -1;' % Naming.generator_cname) code.putln('%s->resume_label = -1;' % Naming.generator_cname)
# clean up as early as possible to help breaking any reference cycles # clean up as early as possible to help breaking any reference cycles
code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname) code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname)
......
...@@ -364,13 +364,23 @@ static void __Pyx_Generator_Replace_StopIteration(CYTHON_UNUSED int in_async_gen ...@@ -364,13 +364,23 @@ static void __Pyx_Generator_Replace_StopIteration(CYTHON_UNUSED int in_async_gen
typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyThreadState *, PyObject *); typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyThreadState *, PyObject *);
#if CYTHON_USE_EXC_INFO_STACK
// See https://bugs.python.org/issue25612
#define __Pyx_ExcInfoStruct _PyErr_StackItem
#else
// Minimal replacement struct for Py<3.7, without the Py3.7 exception state stack.
typedef struct { typedef struct {
PyObject_HEAD
__pyx_coroutine_body_t body;
PyObject *closure;
PyObject *exc_type; PyObject *exc_type;
PyObject *exc_value; PyObject *exc_value;
PyObject *exc_traceback; PyObject *exc_traceback;
} __Pyx_ExcInfoStruct;
#endif
typedef struct {
PyObject_HEAD
__pyx_coroutine_body_t body;
PyObject *closure;
__Pyx_ExcInfoStruct gi_exc_state;
PyObject *gi_weakreflist; PyObject *gi_weakreflist;
PyObject *classobj; PyObject *classobj;
PyObject *yieldfrom; PyObject *yieldfrom;
...@@ -391,20 +401,26 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( ...@@ -391,20 +401,26 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit(
__pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure, __pyx_CoroutineObject *gen, __pyx_coroutine_body_t body, PyObject *code, PyObject *closure,
PyObject *name, PyObject *qualname, PyObject *module_name); /*proto*/ PyObject *name, PyObject *qualname, PyObject *module_name); /*proto*/
static CYTHON_INLINE void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *self);
static int __Pyx_Coroutine_clear(PyObject *self); /*proto*/ static int __Pyx_Coroutine_clear(PyObject *self); /*proto*/
static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); /*proto*/ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); /*proto*/
static PyObject *__Pyx_Coroutine_Close(PyObject *self); /*proto*/ static PyObject *__Pyx_Coroutine_Close(PyObject *self); /*proto*/
static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); /*proto*/ static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); /*proto*/
// macros for exception state swapping instead of inline functions to make use of the local thread state context // macros for exception state swapping instead of inline functions to make use of the local thread state context
#if CYTHON_USE_EXC_INFO_STACK
#define __Pyx_Coroutine_SwapException(self) __Pyx_Coroutine_ResetFrameBackpointer(self)
#define __Pyx_Coroutine_ResetAndClearException(self) __Pyx_Coroutine_ExceptionClear(&(self)->gi_exc_state)
#else
#define __Pyx_Coroutine_SwapException(self) { \ #define __Pyx_Coroutine_SwapException(self) { \
__Pyx_ExceptionSwap(&(self)->exc_type, &(self)->exc_value, &(self)->exc_traceback); \ __Pyx_ExceptionSwap(&(self)->gi_exc_state.exc_type, &(self)->gi_exc_state.exc_value, &(self)->gi_exc_state.exc_traceback); \
__Pyx_Coroutine_ResetFrameBackpointer(self); \ __Pyx_Coroutine_ResetFrameBackpointer(self); \
} }
#define __Pyx_Coroutine_ResetAndClearException(self) { \ #define __Pyx_Coroutine_ResetAndClearException(self) { \
__Pyx_ExceptionReset((self)->exc_type, (self)->exc_value, (self)->exc_traceback); \ __Pyx_ExceptionReset((self)->gi_exc_state.exc_type, (self)->gi_exc_state.exc_value, (self)->gi_exc_state.exc_traceback); \
(self)->exc_type = (self)->exc_value = (self)->exc_traceback = NULL; \ (self)->gi_exc_state.exc_type = (self)->gi_exc_state.exc_value = (self)->gi_exc_state.exc_traceback = NULL; \
} }
#endif
#if CYTHON_FAST_THREAD_STATE #if CYTHON_FAST_THREAD_STATE
#define __Pyx_PyGen_FetchStopIterationValue(pvalue) \ #define __Pyx_PyGen_FetchStopIterationValue(pvalue) \
...@@ -573,18 +589,19 @@ static int __Pyx_PyGen__FetchStopIterationValue(CYTHON_UNUSED PyThreadState *$lo ...@@ -573,18 +589,19 @@ static int __Pyx_PyGen__FetchStopIterationValue(CYTHON_UNUSED PyThreadState *$lo
} }
static CYTHON_INLINE static CYTHON_INLINE
void __Pyx_Coroutine_ExceptionClear(__pyx_CoroutineObject *self) { void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) {
PyObject *exc_type = self->exc_type; PyObject *t, *v, *tb;
PyObject *exc_value = self->exc_value; t = exc_state->exc_type;
PyObject *exc_traceback = self->exc_traceback; v = exc_state->exc_value;
tb = exc_state->exc_traceback;
self->exc_type = NULL;
self->exc_value = NULL; exc_state->exc_type = NULL;
self->exc_traceback = NULL; exc_state->exc_value = NULL;
exc_state->exc_traceback = NULL;
Py_XDECREF(exc_type);
Py_XDECREF(exc_value); Py_XDECREF(t);
Py_XDECREF(exc_traceback); Py_XDECREF(v);
Py_XDECREF(tb);
} }
#define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL) #define __Pyx_Coroutine_AlreadyRunningError(gen) (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL)
...@@ -649,6 +666,7 @@ static ...@@ -649,6 +666,7 @@ static
PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) { PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, int closing) {
__Pyx_PyThreadState_declare __Pyx_PyThreadState_declare
PyThreadState *tstate; PyThreadState *tstate;
__Pyx_ExcInfoStruct *exc_state;
PyObject *retval; PyObject *retval;
assert(!self->is_running); assert(!self->is_running);
...@@ -671,42 +689,58 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, i ...@@ -671,42 +689,58 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value, i
#endif #endif
// Traceback/Frame rules: // Traceback/Frame rules:
// - on entry, save external exception state in self->exc_*, restore it on exit // - on entry, save external exception state in self->gi_exc_state, restore it on exit
// - on exit, keep internally generated exceptions in self->exc_*, clear everything else // - on exit, keep internally generated exceptions in self->gi_exc_state, clear everything else
// - on entry, set "f_back" pointer of internal exception traceback to (current) outer call frame // - on entry, set "f_back" pointer of internal exception traceback to (current) outer call frame
// - on exit, clear "f_back" of internal exception traceback // - on exit, clear "f_back" of internal exception traceback
// - do not touch external frames and tracebacks // - do not touch external frames and tracebacks
if (self->exc_type) { exc_state = &self->gi_exc_state;
#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON if (exc_state->exc_type) {
#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
// FIXME: what to do in PyPy? // FIXME: what to do in PyPy?
#else #else
// Generators always return to their most recent caller, not // Generators always return to their most recent caller, not
// necessarily their creator. // necessarily their creator.
if (self->exc_traceback) { if (exc_state->exc_traceback) {
PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback; PyTracebackObject *tb = (PyTracebackObject *) exc_state->exc_traceback;
PyFrameObject *f = tb->tb_frame; PyFrameObject *f = tb->tb_frame;
Py_XINCREF(tstate->frame); Py_XINCREF(tstate->frame);
assert(f->f_back == NULL); assert(f->f_back == NULL);
f->f_back = tstate->frame; f->f_back = tstate->frame;
} }
#endif #endif
}
#if CYTHON_USE_EXC_INFO_STACK
// See https://bugs.python.org/issue25612
exc_state->previous_item = tstate->exc_info;
tstate->exc_info = exc_state;
#else
if (exc_state->exc_type) {
// We were in an except handler when we left, // We were in an except handler when we left,
// restore the exception state which was put aside. // restore the exception state which was put aside.
__Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, __Pyx_ExceptionSwap(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback);
&self->exc_traceback);
// self->exc_* now holds the exception state of the caller // self->exc_* now holds the exception state of the caller
} else { } else {
// save away the exception state of the caller // save away the exception state of the caller
__Pyx_Coroutine_ExceptionClear(self); __Pyx_Coroutine_ExceptionClear(exc_state);
__Pyx_ExceptionSave(&self->exc_type, &self->exc_value, &self->exc_traceback); __Pyx_ExceptionSave(&exc_state->exc_type, &exc_state->exc_value, &exc_state->exc_traceback);
} }
#endif
self->is_running = 1; self->is_running = 1;
retval = self->body((PyObject *) self, tstate, value); retval = self->body((PyObject *) self, tstate, value);
self->is_running = 0; self->is_running = 0;
#if CYTHON_USE_EXC_INFO_STACK
// See https://bugs.python.org/issue25612
exc_state = &self->gi_exc_state;
tstate->exc_info = exc_state->previous_item;
exc_state->previous_item = NULL;
#endif
return retval; return retval;
} }
...@@ -714,11 +748,13 @@ static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__pyx_CoroutineO ...@@ -714,11 +748,13 @@ static CYTHON_INLINE void __Pyx_Coroutine_ResetFrameBackpointer(__pyx_CoroutineO
// Don't keep the reference to f_back any longer than necessary. It // Don't keep the reference to f_back any longer than necessary. It
// may keep a chain of frames alive or it could create a reference // may keep a chain of frames alive or it could create a reference
// cycle. // cycle.
if (likely(self->exc_traceback)) { PyObject *tb = self->gi_exc_state.exc_traceback;
if (likely(tb)) {
#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON #if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
// FIXME: what to do in PyPy? // FIXME: what to do in PyPy?
#else #else
PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback; PyTracebackObject *tb = (PyTracebackObject *) tb;
PyFrameObject *f = tb->tb_frame; PyFrameObject *f = tb->tb_frame;
Py_CLEAR(f->f_back); Py_CLEAR(f->f_back);
#endif #endif
...@@ -1039,14 +1075,18 @@ static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) { ...@@ -1039,14 +1075,18 @@ static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) {
return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1); return __Pyx__Coroutine_Throw(self, typ, val, tb, args, 1);
} }
static CYTHON_INLINE int __Pyx_Coroutine_traverse_excstate(__Pyx_ExcInfoStruct *exc_state, visitproc visit, void *arg) {
Py_VISIT(exc_state->exc_type);
Py_VISIT(exc_state->exc_value);
Py_VISIT(exc_state->exc_traceback);
return 0;
}
static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) { static int __Pyx_Coroutine_traverse(__pyx_CoroutineObject *gen, visitproc visit, void *arg) {
Py_VISIT(gen->closure); Py_VISIT(gen->closure);
Py_VISIT(gen->classobj); Py_VISIT(gen->classobj);
Py_VISIT(gen->yieldfrom); Py_VISIT(gen->yieldfrom);
Py_VISIT(gen->exc_type); return __Pyx_Coroutine_traverse_excstate(&gen->gi_exc_state, visit, arg);
Py_VISIT(gen->exc_value);
Py_VISIT(gen->exc_traceback);
return 0;
} }
static int __Pyx_Coroutine_clear(PyObject *self) { static int __Pyx_Coroutine_clear(PyObject *self) {
...@@ -1055,9 +1095,7 @@ static int __Pyx_Coroutine_clear(PyObject *self) { ...@@ -1055,9 +1095,7 @@ static int __Pyx_Coroutine_clear(PyObject *self) {
Py_CLEAR(gen->closure); Py_CLEAR(gen->closure);
Py_CLEAR(gen->classobj); Py_CLEAR(gen->classobj);
Py_CLEAR(gen->yieldfrom); Py_CLEAR(gen->yieldfrom);
Py_CLEAR(gen->exc_type); __Pyx_Coroutine_ExceptionClear(&gen->gi_exc_state);
Py_CLEAR(gen->exc_value);
Py_CLEAR(gen->exc_traceback);
#ifdef __Pyx_AsyncGen_USED #ifdef __Pyx_AsyncGen_USED
if (__Pyx_AsyncGen_CheckExact(self)) { if (__Pyx_AsyncGen_CheckExact(self)) {
Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer); Py_CLEAR(((__pyx_PyAsyncGenObject*)gen)->ag_finalizer);
...@@ -1315,9 +1353,12 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit( ...@@ -1315,9 +1353,12 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_NewInit(
gen->resume_label = 0; gen->resume_label = 0;
gen->classobj = NULL; gen->classobj = NULL;
gen->yieldfrom = NULL; gen->yieldfrom = NULL;
gen->exc_type = NULL; gen->gi_exc_state.exc_type = NULL;
gen->exc_value = NULL; gen->gi_exc_state.exc_value = NULL;
gen->exc_traceback = NULL; gen->gi_exc_state.exc_traceback = NULL;
#if CYTHON_USE_EXC_INFO_STACK
gen->gi_exc_state.previous_item = NULL;
#endif
gen->gi_weakreflist = NULL; gen->gi_weakreflist = NULL;
Py_XINCREF(qualname); Py_XINCREF(qualname);
gen->gi_qualname = qualname; gen->gi_qualname = qualname;
...@@ -1862,8 +1903,8 @@ static void __Pyx__ReturnWithStopIteration(PyObject* value) { ...@@ -1862,8 +1903,8 @@ static void __Pyx__ReturnWithStopIteration(PyObject* value) {
} }
#if CYTHON_FAST_THREAD_STATE #if CYTHON_FAST_THREAD_STATE
__Pyx_PyThreadState_assign __Pyx_PyThreadState_assign
#if PY_VERSION_HEX >= 0x030700A3 #if CYTHON_USE_EXC_INFO_STACK
if (!$local_tstate_cname->exc_state.exc_type) if (!$local_tstate_cname->exc_info->exc_type)
#else #else
if (!$local_tstate_cname->exc_type) if (!$local_tstate_cname->exc_type)
#endif #endif
......
...@@ -307,6 +307,31 @@ bad: ...@@ -307,6 +307,31 @@ bad:
} }
#endif #endif
/////////////// GetTopmostException.proto ///////////////
#if CYTHON_USE_EXC_INFO_STACK
static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate);
#endif
/////////////// GetTopmostException ///////////////
#if CYTHON_USE_EXC_INFO_STACK
// Copied from errors.c in CPython.
static _PyErr_StackItem *
__Pyx_PyErr_GetTopmostException(PyThreadState *tstate)
{
_PyErr_StackItem *exc_info = tstate->exc_info;
while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) &&
exc_info->previous_item != NULL)
{
exc_info = exc_info->previous_item;
}
return exc_info;
}
#endif
/////////////// GetException.proto /////////////// /////////////// GetException.proto ///////////////
//@substitute: naming //@substitute: naming
//@requires: PyThreadStateGet //@requires: PyThreadStateGet
...@@ -360,13 +385,16 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) ...@@ -360,13 +385,16 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb)
*value = local_value; *value = local_value;
*tb = local_tb; *tb = local_tb;
#if CYTHON_FAST_THREAD_STATE #if CYTHON_FAST_THREAD_STATE
#if PY_VERSION_HEX >= 0x030700A3 #if CYTHON_USE_EXC_INFO_STACK
tmp_type = tstate->exc_state.exc_type; {
tmp_value = tstate->exc_state.exc_value; _PyErr_StackItem *exc_info = tstate->exc_info;
tmp_tb = tstate->exc_state.exc_traceback; tmp_type = exc_info->exc_type;
tstate->exc_state.exc_type = local_type; tmp_value = exc_info->exc_value;
tstate->exc_state.exc_value = local_value; tmp_tb = exc_info->exc_traceback;
tstate->exc_state.exc_traceback = local_tb; exc_info->exc_type = local_type;
exc_info->exc_value = local_value;
exc_info->exc_traceback = local_tb;
}
#else #else
tmp_type = tstate->exc_type; tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value; tmp_value = tstate->exc_value;
...@@ -398,16 +426,18 @@ bad: ...@@ -398,16 +426,18 @@ bad:
static CYTHON_INLINE void __Pyx_ReraiseException(void); /*proto*/ static CYTHON_INLINE void __Pyx_ReraiseException(void); /*proto*/
/////////////// ReRaiseException.proto /////////////// /////////////// ReRaiseException ///////////////
//@requires: GetTopmostException
static CYTHON_INLINE void __Pyx_ReraiseException(void) { static CYTHON_INLINE void __Pyx_ReraiseException(void) {
PyObject *type = NULL, *value = NULL, *tb = NULL; PyObject *type = NULL, *value = NULL, *tb = NULL;
#if CYTHON_FAST_THREAD_STATE #if CYTHON_FAST_THREAD_STATE
PyThreadState *tstate = PyThreadState_GET(); PyThreadState *tstate = PyThreadState_GET();
#if PY_VERSION_HEX >= 0x030700A3 #if CYTHON_USE_EXC_INFO_STACK
type = tstate->exc_state.exc_type; _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate);
value = tstate->exc_state.exc_value; type = exc_info->exc_type;
tb = tstate->exc_state.exc_traceback; value = exc_info->exc_value;
tb = exc_info->exc_traceback;
#else #else
type = tstate->exc_type; type = tstate->exc_type;
value = tstate->exc_value; value = tstate->exc_value;
...@@ -456,10 +486,11 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject ...@@ -456,10 +486,11 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject
#if CYTHON_FAST_THREAD_STATE #if CYTHON_FAST_THREAD_STATE
static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
#if PY_VERSION_HEX >= 0x030700A3 #if CYTHON_USE_EXC_INFO_STACK
*type = tstate->exc_state.exc_type; _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate);
*value = tstate->exc_state.exc_value; *type = exc_info->exc_type;
*tb = tstate->exc_state.exc_traceback; *value = exc_info->exc_value;
*tb = exc_info->exc_traceback;
#else #else
*type = tstate->exc_type; *type = tstate->exc_type;
*value = tstate->exc_value; *value = tstate->exc_value;
...@@ -473,13 +504,14 @@ static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject * ...@@ -473,13 +504,14 @@ static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject *
static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb; PyObject *tmp_type, *tmp_value, *tmp_tb;
#if PY_VERSION_HEX >= 0x030700A3 #if CYTHON_USE_EXC_INFO_STACK
tmp_type = tstate->exc_state.exc_type; _PyErr_StackItem *exc_info = tstate->exc_info;
tmp_value = tstate->exc_state.exc_value; tmp_type = exc_info->exc_type;
tmp_tb = tstate->exc_state.exc_traceback; tmp_value = exc_info->exc_value;
tstate->exc_state.exc_type = type; tmp_tb = exc_info->exc_traceback;
tstate->exc_state.exc_value = value; exc_info->exc_type = type;
tstate->exc_state.exc_traceback = tb; exc_info->exc_value = value;
exc_info->exc_traceback = tb;
#else #else
tmp_type = tstate->exc_type; tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value; tmp_value = tstate->exc_value;
...@@ -511,14 +543,15 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, ...@@ -511,14 +543,15 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb; PyObject *tmp_type, *tmp_value, *tmp_tb;
#if PY_VERSION_HEX >= 0x030700A3 #if CYTHON_USE_EXC_INFO_STACK
tmp_type = tstate->exc_state.exc_type; _PyErr_StackItem *exc_info = tstate->exc_info;
tmp_value = tstate->exc_state.exc_value; tmp_type = exc_info->exc_type;
tmp_tb = tstate->exc_state.exc_traceback; tmp_value = exc_info->exc_value;
tmp_tb = exc_info->exc_traceback;
tstate->exc_state.exc_type = *type; exc_info->exc_type = *type;
tstate->exc_state.exc_value = *value; exc_info->exc_value = *value;
tstate->exc_state.exc_traceback = *tb; exc_info->exc_traceback = *tb;
#else #else
tmp_type = tstate->exc_type; tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value; tmp_value = tstate->exc_value;
......
...@@ -81,6 +81,8 @@ ...@@ -81,6 +81,8 @@
#define CYTHON_USE_TP_FINALIZE 0 #define CYTHON_USE_TP_FINALIZE 0
#undef CYTHON_USE_DICT_VERSIONS #undef CYTHON_USE_DICT_VERSIONS
#define CYTHON_USE_DICT_VERSIONS 0 #define CYTHON_USE_DICT_VERSIONS 0
#undef CYTHON_USE_EXC_INFO_STACK
#define CYTHON_USE_EXC_INFO_STACK 0
#elif defined(PYSTON_VERSION) #elif defined(PYSTON_VERSION)
#define CYTHON_COMPILING_IN_PYPY 0 #define CYTHON_COMPILING_IN_PYPY 0
...@@ -122,6 +124,8 @@ ...@@ -122,6 +124,8 @@
#define CYTHON_USE_TP_FINALIZE 0 #define CYTHON_USE_TP_FINALIZE 0
#undef CYTHON_USE_DICT_VERSIONS #undef CYTHON_USE_DICT_VERSIONS
#define CYTHON_USE_DICT_VERSIONS 0 #define CYTHON_USE_DICT_VERSIONS 0
#undef CYTHON_USE_EXC_INFO_STACK
#define CYTHON_USE_EXC_INFO_STACK 0
#else #else
#define CYTHON_COMPILING_IN_PYPY 0 #define CYTHON_COMPILING_IN_PYPY 0
...@@ -186,6 +190,9 @@ ...@@ -186,6 +190,9 @@
#ifndef CYTHON_USE_DICT_VERSIONS #ifndef CYTHON_USE_DICT_VERSIONS
#define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1) #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1)
#endif #endif
#ifndef CYTHON_USE_EXC_INFO_STACK
#define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3)
#endif
#endif #endif
#if !defined(CYTHON_FAST_PYCCALL) #if !defined(CYTHON_FAST_PYCCALL)
......
# Python test set -- part 5, built-in exceptions # Python test set -- part 5, built-in exceptions
# Copied from CPython 3.7.
# cython: language_level=3
# mode: run
# tag: generator, exception, tryfinally, tryexcept
import copy import copy
import os import os
...@@ -12,6 +17,12 @@ from test.support import (TESTFN, captured_stderr, check_impl_detail, ...@@ -12,6 +17,12 @@ from test.support import (TESTFN, captured_stderr, check_impl_detail,
check_warnings, cpython_only, gc_collect, run_unittest, check_warnings, cpython_only, gc_collect, run_unittest,
no_tracing, unlink, import_module, script_helper, no_tracing, unlink, import_module, script_helper,
SuppressCrashReport) SuppressCrashReport)
no_tracing = unittest.skip("For nested functions, Cython generates a C call without recursion checks.")
cpython_only = unittest.skip("Tests for _testcapi make no sense here.")
class NaiveException(Exception): class NaiveException(Exception):
def __init__(self, x): def __init__(self, x):
self.x = x self.x = x
...@@ -80,8 +91,8 @@ class ExceptionTests(unittest.TestCase): ...@@ -80,8 +91,8 @@ class ExceptionTests(unittest.TestCase):
self.raise_catch(MemoryError, "MemoryError") self.raise_catch(MemoryError, "MemoryError")
self.raise_catch(NameError, "NameError") self.raise_catch(NameError, "NameError")
try: x = undefined_variable #try: x = undefined_variable
except NameError: pass #except NameError: pass
self.raise_catch(OverflowError, "OverflowError") self.raise_catch(OverflowError, "OverflowError")
x = 1 x = 1
...@@ -649,16 +660,19 @@ class ExceptionTests(unittest.TestCase): ...@@ -649,16 +660,19 @@ class ExceptionTests(unittest.TestCase):
obj = wr() obj = wr()
self.assertIsNone(obj) self.assertIsNone(obj)
'''
# This is currently a compile error in Cython-3, although it works in Cython-2 => could also work in Cy-3.
def test_exception_target_in_nested_scope(self): def test_exception_target_in_nested_scope(self):
# issue 4617: This used to raise a SyntaxError # issue 4617: This used to raise a SyntaxError
# "can not delete variable 'e' referenced in nested scope" # "can not delete variable 'e' referenced in nested scope"
def print_error(): def print_error():
e e
try: try:
something 1/0
except Exception as e: except Exception as e:
print_error() print_error()
# implicit "del e" here # implicit "del e" here
'''
def test_generator_leaking(self): def test_generator_leaking(self):
# Test that generator exception state doesn't leak into the calling # Test that generator exception state doesn't leak into the calling
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment