diff options
Diffstat (limited to 'Objects/genobject.c')
-rw-r--r-- | Objects/genobject.c | 60 |
1 files changed, 50 insertions, 10 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c index 9172e6a010..0d5d54fdba 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -154,12 +154,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) /* Delay exception instantiation if we can */ PyErr_SetNone(PyExc_StopIteration); } else { - PyObject *e = PyObject_CallFunctionObjArgs( - PyExc_StopIteration, result, NULL); - if (e != NULL) { - PyErr_SetObject(PyExc_StopIteration, e); - Py_DECREF(e); - } + _PyGen_SetStopIterationValue(result); } Py_CLEAR(result); } @@ -460,6 +455,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. * @@ -469,7 +501,8 @@ gen_iternext(PyGenObject *gen) */ int -_PyGen_FetchStopIterationValue(PyObject **pvalue) { +_PyGen_FetchStopIterationValue(PyObject **pvalue) +{ PyObject *et, *ev, *tb; PyObject *value = NULL; @@ -481,8 +514,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 */ @@ -1012,7 +1052,7 @@ typedef struct { static PyObject * aiter_wrapper_iternext(PyAIterWrapper *aw) { - PyErr_SetObject(PyExc_StopIteration, aw->aw_aiter); + _PyGen_SetStopIterationValue(aw->aw_aiter); return NULL; } |