mirror of https://github.com/python/cpython
gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (in Objects/) (#102218)
This commit is contained in:
parent
b097925858
commit
11a2c6ce51
|
@ -119,7 +119,7 @@ As a consequence of this, split keys have a maximum size of 16.
|
||||||
#include "pycore_dict.h" // PyDictKeysObject
|
#include "pycore_dict.h" // PyDictKeysObject
|
||||||
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
|
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
|
||||||
#include "pycore_object.h" // _PyObject_GC_TRACK()
|
#include "pycore_object.h" // _PyObject_GC_TRACK()
|
||||||
#include "pycore_pyerrors.h" // _PyErr_Fetch()
|
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
|
||||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||||
#include "stringlib/eq.h" // unicode_eq()
|
#include "stringlib/eq.h" // unicode_eq()
|
||||||
|
|
||||||
|
|
|
@ -3781,16 +3781,13 @@ PyObject *
|
||||||
_PyErr_TrySetFromCause(const char *format, ...)
|
_PyErr_TrySetFromCause(const char *format, ...)
|
||||||
{
|
{
|
||||||
PyObject* msg_prefix;
|
PyObject* msg_prefix;
|
||||||
PyObject *exc, *val, *tb;
|
|
||||||
PyTypeObject *caught_type;
|
|
||||||
PyObject *instance_args;
|
PyObject *instance_args;
|
||||||
Py_ssize_t num_args, caught_type_size, base_exc_size;
|
Py_ssize_t num_args, caught_type_size, base_exc_size;
|
||||||
PyObject *new_exc, *new_val, *new_tb;
|
|
||||||
va_list vargs;
|
va_list vargs;
|
||||||
int same_basic_size;
|
int same_basic_size;
|
||||||
|
|
||||||
PyErr_Fetch(&exc, &val, &tb);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
caught_type = (PyTypeObject *)exc;
|
PyTypeObject *caught_type = Py_TYPE(exc);
|
||||||
/* Ensure type info indicates no extra state is stored at the C level
|
/* Ensure type info indicates no extra state is stored at the C level
|
||||||
* and that the type can be reinstantiated using PyErr_Format
|
* and that the type can be reinstantiated using PyErr_Format
|
||||||
*/
|
*/
|
||||||
|
@ -3810,31 +3807,30 @@ _PyErr_TrySetFromCause(const char *format, ...)
|
||||||
* more state than just the exception type. Accordingly, we just
|
* more state than just the exception type. Accordingly, we just
|
||||||
* leave it alone.
|
* leave it alone.
|
||||||
*/
|
*/
|
||||||
PyErr_Restore(exc, val, tb);
|
PyErr_SetRaisedException(exc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the args are empty or contain a single string */
|
/* Check the args are empty or contain a single string */
|
||||||
PyErr_NormalizeException(&exc, &val, &tb);
|
instance_args = ((PyBaseExceptionObject *)exc)->args;
|
||||||
instance_args = ((PyBaseExceptionObject *)val)->args;
|
|
||||||
num_args = PyTuple_GET_SIZE(instance_args);
|
num_args = PyTuple_GET_SIZE(instance_args);
|
||||||
if (num_args > 1 ||
|
if (num_args > 1 ||
|
||||||
(num_args == 1 &&
|
(num_args == 1 &&
|
||||||
!PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) {
|
!PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) {
|
||||||
/* More than 1 arg, or the one arg we do have isn't a string
|
/* More than 1 arg, or the one arg we do have isn't a string
|
||||||
*/
|
*/
|
||||||
PyErr_Restore(exc, val, tb);
|
PyErr_SetRaisedException(exc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure the instance dict is also empty */
|
/* Ensure the instance dict is also empty */
|
||||||
if (!_PyObject_IsInstanceDictEmpty(val)) {
|
if (!_PyObject_IsInstanceDictEmpty(exc)) {
|
||||||
/* While we could potentially copy a non-empty instance dictionary
|
/* While we could potentially copy a non-empty instance dictionary
|
||||||
* to the replacement exception, for now we take the more
|
* to the replacement exception, for now we take the more
|
||||||
* conservative path of leaving exceptions with attributes set
|
* conservative path of leaving exceptions with attributes set
|
||||||
* alone.
|
* alone.
|
||||||
*/
|
*/
|
||||||
PyErr_Restore(exc, val, tb);
|
PyErr_SetRaisedException(exc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3847,28 +3843,19 @@ _PyErr_TrySetFromCause(const char *format, ...)
|
||||||
* types as well, but that's quite a bit trickier due to the extra
|
* types as well, but that's quite a bit trickier due to the extra
|
||||||
* state potentially stored on OSError instances.
|
* state potentially stored on OSError instances.
|
||||||
*/
|
*/
|
||||||
/* Ensure the traceback is set correctly on the existing exception */
|
|
||||||
if (tb != NULL) {
|
|
||||||
PyException_SetTraceback(val, tb);
|
|
||||||
Py_DECREF(tb);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start(vargs, format);
|
va_start(vargs, format);
|
||||||
msg_prefix = PyUnicode_FromFormatV(format, vargs);
|
msg_prefix = PyUnicode_FromFormatV(format, vargs);
|
||||||
va_end(vargs);
|
va_end(vargs);
|
||||||
if (msg_prefix == NULL) {
|
if (msg_prefix == NULL) {
|
||||||
Py_DECREF(exc);
|
Py_DECREF(exc);
|
||||||
Py_DECREF(val);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyErr_Format(exc, "%U (%s: %S)",
|
PyErr_Format((PyObject*)Py_TYPE(exc), "%U (%s: %S)",
|
||||||
msg_prefix, Py_TYPE(val)->tp_name, val);
|
msg_prefix, Py_TYPE(exc)->tp_name, exc);
|
||||||
Py_DECREF(exc);
|
|
||||||
Py_DECREF(msg_prefix);
|
Py_DECREF(msg_prefix);
|
||||||
PyErr_Fetch(&new_exc, &new_val, &new_tb);
|
PyObject *new_exc = PyErr_GetRaisedException();
|
||||||
PyErr_NormalizeException(&new_exc, &new_val, &new_tb);
|
PyException_SetCause(new_exc, exc);
|
||||||
PyException_SetCause(new_val, val);
|
PyErr_SetRaisedException(new_exc);
|
||||||
PyErr_Restore(new_exc, new_val, new_tb);
|
return new_exc;
|
||||||
return new_val;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1308,7 +1308,6 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
|
||||||
/* Merge locals into fast locals */
|
/* Merge locals into fast locals */
|
||||||
PyObject *locals;
|
PyObject *locals;
|
||||||
PyObject **fast;
|
PyObject **fast;
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
|
||||||
PyCodeObject *co;
|
PyCodeObject *co;
|
||||||
locals = frame->f_locals;
|
locals = frame->f_locals;
|
||||||
if (locals == NULL) {
|
if (locals == NULL) {
|
||||||
|
@ -1317,7 +1316,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
|
||||||
fast = _PyFrame_GetLocalsArray(frame);
|
fast = _PyFrame_GetLocalsArray(frame);
|
||||||
co = frame->f_code;
|
co = frame->f_code;
|
||||||
|
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
for (int i = 0; i < co->co_nlocalsplus; i++) {
|
for (int i = 0; i < co->co_nlocalsplus; i++) {
|
||||||
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
|
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
|
||||||
|
|
||||||
|
@ -1374,7 +1373,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
|
||||||
}
|
}
|
||||||
Py_XDECREF(value);
|
Py_XDECREF(value);
|
||||||
}
|
}
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -69,8 +69,6 @@ void
|
||||||
_PyGen_Finalize(PyObject *self)
|
_PyGen_Finalize(PyObject *self)
|
||||||
{
|
{
|
||||||
PyGenObject *gen = (PyGenObject *)self;
|
PyGenObject *gen = (PyGenObject *)self;
|
||||||
PyObject *res = NULL;
|
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
|
||||||
|
|
||||||
if (gen->gi_frame_state >= FRAME_COMPLETED) {
|
if (gen->gi_frame_state >= FRAME_COMPLETED) {
|
||||||
/* Generator isn't paused, so no need to close */
|
/* Generator isn't paused, so no need to close */
|
||||||
|
@ -82,23 +80,22 @@ _PyGen_Finalize(PyObject *self)
|
||||||
PyObject *finalizer = agen->ag_origin_or_finalizer;
|
PyObject *finalizer = agen->ag_origin_or_finalizer;
|
||||||
if (finalizer && !agen->ag_closed) {
|
if (finalizer && !agen->ag_closed) {
|
||||||
/* Save the current exception, if any. */
|
/* Save the current exception, if any. */
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
|
|
||||||
res = PyObject_CallOneArg(finalizer, self);
|
|
||||||
|
|
||||||
|
PyObject *res = PyObject_CallOneArg(finalizer, self);
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
PyErr_WriteUnraisable(self);
|
PyErr_WriteUnraisable(self);
|
||||||
} else {
|
} else {
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
}
|
}
|
||||||
/* Restore the saved exception. */
|
/* Restore the saved exception. */
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the current exception, if any. */
|
/* Save the current exception, if any. */
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
|
|
||||||
/* If `gen` is a coroutine, and if it was never awaited on,
|
/* If `gen` is a coroutine, and if it was never awaited on,
|
||||||
issue a RuntimeWarning. */
|
issue a RuntimeWarning. */
|
||||||
|
@ -109,9 +106,7 @@ _PyGen_Finalize(PyObject *self)
|
||||||
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
|
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = gen_close(gen, NULL);
|
PyObject *res = gen_close(gen, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
PyErr_WriteUnraisable(self);
|
PyErr_WriteUnraisable(self);
|
||||||
|
@ -120,9 +115,10 @@ _PyGen_Finalize(PyObject *self)
|
||||||
else {
|
else {
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Restore the saved exception. */
|
/* Restore the saved exception. */
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -648,39 +644,11 @@ _PyGen_SetStopIterationValue(PyObject *value)
|
||||||
int
|
int
|
||||||
_PyGen_FetchStopIterationValue(PyObject **pvalue)
|
_PyGen_FetchStopIterationValue(PyObject **pvalue)
|
||||||
{
|
{
|
||||||
PyObject *et, *ev, *tb;
|
|
||||||
PyObject *value = NULL;
|
PyObject *value = NULL;
|
||||||
|
|
||||||
if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
||||||
PyErr_Fetch(&et, &ev, &tb);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
if (ev) {
|
value = Py_NewRef(((PyStopIterationObject *)exc)->value);
|
||||||
/* exception will usually be normalised already */
|
Py_DECREF(exc);
|
||||||
if (PyObject_TypeCheck(ev, (PyTypeObject *) et)) {
|
|
||||||
value = Py_NewRef(((PyStopIterationObject *)ev)->value);
|
|
||||||
Py_DECREF(ev);
|
|
||||||
} 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 */
|
|
||||||
PyErr_NormalizeException(&et, &ev, &tb);
|
|
||||||
if (!PyObject_TypeCheck(ev, (PyTypeObject *)PyExc_StopIteration)) {
|
|
||||||
PyErr_Restore(et, ev, tb);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
value = Py_NewRef(((PyStopIterationObject *)ev)->value);
|
|
||||||
Py_DECREF(ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Py_XDECREF(et);
|
|
||||||
Py_XDECREF(tb);
|
|
||||||
} else if (PyErr_Occurred()) {
|
} else if (PyErr_Occurred()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,13 +370,12 @@ _PyObject_Dump(PyObject* op)
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
PyGILState_STATE gil = PyGILState_Ensure();
|
PyGILState_STATE gil = PyGILState_Ensure();
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
|
||||||
|
|
||||||
(void)PyObject_Print(op, stderr, 0);
|
(void)PyObject_Print(op, stderr, 0);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
PyGILState_Release(gil);
|
PyGILState_Release(gil);
|
||||||
|
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
@ -860,25 +859,22 @@ set_attribute_error_context(PyObject* v, PyObject* name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Intercept AttributeError exceptions and augment them to offer suggestions later.
|
// Intercept AttributeError exceptions and augment them to offer suggestions later.
|
||||||
PyObject *type, *value, *traceback;
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
PyErr_Fetch(&type, &value, &traceback);
|
if (!PyErr_GivenExceptionMatches(exc, PyExc_AttributeError)) {
|
||||||
PyErr_NormalizeException(&type, &value, &traceback);
|
|
||||||
// Check if the normalized exception is indeed an AttributeError
|
|
||||||
if (!PyErr_GivenExceptionMatches(value, PyExc_AttributeError)) {
|
|
||||||
goto restore;
|
goto restore;
|
||||||
}
|
}
|
||||||
PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) value;
|
PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) exc;
|
||||||
// Check if this exception was already augmented
|
// Check if this exception was already augmented
|
||||||
if (the_exc->name || the_exc->obj) {
|
if (the_exc->name || the_exc->obj) {
|
||||||
goto restore;
|
goto restore;
|
||||||
}
|
}
|
||||||
// Augment the exception with the name and object
|
// Augment the exception with the name and object
|
||||||
if (PyObject_SetAttr(value, &_Py_ID(name), name) ||
|
if (PyObject_SetAttr(exc, &_Py_ID(name), name) ||
|
||||||
PyObject_SetAttr(value, &_Py_ID(obj), v)) {
|
PyObject_SetAttr(exc, &_Py_ID(obj), v)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
restore:
|
restore:
|
||||||
PyErr_Restore(type, value, traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2190,9 +2186,8 @@ Py_ReprLeave(PyObject *obj)
|
||||||
PyObject *dict;
|
PyObject *dict;
|
||||||
PyObject *list;
|
PyObject *list;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
|
||||||
|
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
|
|
||||||
dict = PyThreadState_GetDict();
|
dict = PyThreadState_GetDict();
|
||||||
if (dict == NULL)
|
if (dict == NULL)
|
||||||
|
@ -2213,7 +2208,7 @@ Py_ReprLeave(PyObject *obj)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
/* ignore exceptions because there is no way to report them. */
|
/* ignore exceptions because there is no way to report them. */
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Trashcan support. */
|
/* Trashcan support. */
|
||||||
|
|
|
@ -1556,10 +1556,9 @@ _PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value,
|
||||||
res = _odict_add_new_node((PyODictObject *)od, key, hash);
|
res = _odict_add_new_node((PyODictObject *)od, key, hash);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
/* Revert setting the value on the dict */
|
/* Revert setting the value on the dict */
|
||||||
PyObject *exc, *val, *tb;
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
PyErr_Fetch(&exc, &val, &tb);
|
|
||||||
(void) _PyDict_DelItem_KnownHash(od, key, hash);
|
(void) _PyDict_DelItem_KnownHash(od, key, hash);
|
||||||
_PyErr_ChainExceptions(exc, val, tb);
|
_PyErr_ChainExceptions1(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -4397,10 +4397,9 @@ static void
|
||||||
type_dealloc_common(PyTypeObject *type)
|
type_dealloc_common(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
if (type->tp_bases != NULL) {
|
if (type->tp_bases != NULL) {
|
||||||
PyObject *tp, *val, *tb;
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
PyErr_Fetch(&tp, &val, &tb);
|
|
||||||
remove_all_subclasses(type, type->tp_bases);
|
remove_all_subclasses(type, type->tp_bases);
|
||||||
PyErr_Restore(tp, val, tb);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8445,10 +8444,9 @@ slot_tp_finalize(PyObject *self)
|
||||||
{
|
{
|
||||||
int unbound;
|
int unbound;
|
||||||
PyObject *del, *res;
|
PyObject *del, *res;
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
|
||||||
|
|
||||||
/* Save the current exception, if any. */
|
/* Save the current exception, if any. */
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
|
|
||||||
/* Execute __del__ method, if any. */
|
/* Execute __del__ method, if any. */
|
||||||
del = lookup_maybe_method(self, &_Py_ID(__del__), &unbound);
|
del = lookup_maybe_method(self, &_Py_ID(__del__), &unbound);
|
||||||
|
@ -8462,7 +8460,7 @@ slot_tp_finalize(PyObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the saved exception. */
|
/* Restore the saved exception. */
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -959,9 +959,8 @@ PyObject_ClearWeakRefs(PyObject *object)
|
||||||
if (*list != NULL) {
|
if (*list != NULL) {
|
||||||
PyWeakReference *current = *list;
|
PyWeakReference *current = *list;
|
||||||
Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
|
Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
|
||||||
PyObject *err_type, *err_value, *err_tb;
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
|
|
||||||
PyErr_Fetch(&err_type, &err_value, &err_tb);
|
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
PyObject *callback = current->wr_callback;
|
PyObject *callback = current->wr_callback;
|
||||||
|
|
||||||
|
@ -980,7 +979,7 @@ PyObject_ClearWeakRefs(PyObject *object)
|
||||||
|
|
||||||
tuple = PyTuple_New(count * 2);
|
tuple = PyTuple_New(count * 2);
|
||||||
if (tuple == NULL) {
|
if (tuple == NULL) {
|
||||||
_PyErr_ChainExceptions(err_type, err_value, err_tb);
|
_PyErr_ChainExceptions1(exc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1010,7 +1009,7 @@ PyObject_ClearWeakRefs(PyObject *object)
|
||||||
Py_DECREF(tuple);
|
Py_DECREF(tuple);
|
||||||
}
|
}
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
PyErr_Restore(err_type, err_value, err_tb);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue