diff options
Diffstat (limited to 'Objects/genobject.c')
-rw-r--r-- | Objects/genobject.c | 72 |
1 files changed, 51 insertions, 21 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c index 7bcf016c34..70d6e1492a 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -208,16 +208,9 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) } } else { - PyObject *e = PyObject_CallFunctionObjArgs( - PyExc_StopIteration, result, NULL); - /* Async generators cannot return anything but None */ assert(!PyAsyncGen_CheckExact(gen)); - - if (e != NULL) { - PyErr_SetObject(PyExc_StopIteration, e); - Py_DECREF(e); - } + _PyGen_SetStopIterationValue(result); } Py_CLEAR(result); } @@ -562,6 +555,43 @@ gen_iternext(PyGenObject *gen) } /* + * Set StopIteration with specified value. Value can be arbitrary object + * or NULL. + * + * Returns 0 if StopIteration is set and -1 if any other exception is set. + */ +int +_PyGen_SetStopIterationValue(PyObject *value) +{ + PyObject *e; + + if (value == NULL || + (!PyTuple_Check(value) && + !PyObject_TypeCheck(value, (PyTypeObject *) PyExc_StopIteration))) + { + /* Delay exception instantiation if we can */ + PyErr_SetObject(PyExc_StopIteration, value); + return 0; + } + /* Construct an exception instance manually with + * PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject. + * + * We do this to handle a situation when "value" is a tuple, in which + * case PyErr_SetObject would set the value of StopIteration to + * the first element of the tuple. + * + * (See PyErr_SetObject/_PyErr_CreateException code for details.) + */ + e = PyObject_CallFunctionObjArgs(PyExc_StopIteration, value, NULL); + if (e == NULL) { + return -1; + } + PyErr_SetObject(PyExc_StopIteration, e); + Py_DECREF(e); + return 0; +} + +/* * If StopIteration exception is set, fetches its 'value' * attribute if any, otherwise sets pvalue to None. * @@ -571,7 +601,8 @@ gen_iternext(PyGenObject *gen) */ int -_PyGen_FetchStopIterationValue(PyObject **pvalue) { +_PyGen_FetchStopIterationValue(PyObject **pvalue) +{ PyObject *et, *ev, *tb; PyObject *value = NULL; @@ -583,8 +614,15 @@ _PyGen_FetchStopIterationValue(PyObject **pvalue) { value = ((PyStopIterationObject *)ev)->value; Py_INCREF(value); Py_DECREF(ev); - } else if (et == PyExc_StopIteration) { - /* avoid normalisation and take ev as value */ + } else if (et == PyExc_StopIteration && !PyTuple_Check(ev)) { + /* Avoid normalisation and take ev as value. + * + * Normalization is required if the value is a tuple, in + * that case the value of StopIteration would be set to + * the first element of the tuple. + * + * (See _PyErr_CreateException code for details.) + */ value = ev; } else { /* normalisation required */ @@ -1106,7 +1144,7 @@ typedef struct { static PyObject * aiter_wrapper_iternext(PyAIterWrapper *aw) { - PyErr_SetObject(PyExc_StopIteration, aw->ags_aiter); + _PyGen_SetStopIterationValue(aw->ags_aiter); return NULL; } @@ -1504,16 +1542,8 @@ async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result) if (_PyAsyncGenWrappedValue_CheckExact(result)) { /* async yield */ - PyObject *e = PyObject_CallFunctionObjArgs( - PyExc_StopIteration, - ((_PyAsyncGenWrappedValue*)result)->agw_val, - NULL); + _PyGen_SetStopIterationValue(((_PyAsyncGenWrappedValue*)result)->agw_val); Py_DECREF(result); - if (e == NULL) { - return NULL; - } - PyErr_SetObject(PyExc_StopIteration, e); - Py_DECREF(e); return NULL; } |