Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Prev Previous commit
Next Next commit
moved PREP_RERAISE_STAR helpers from ceval.c to exceptions.c
  • Loading branch information
iritkatriel committed Dec 29, 2021
commit ee9f0f2106e708515e76f6f3a0d5daaecacf40e7
6 changes: 3 additions & 3 deletions Include/internal/pycore_pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ PyAPI_FUNC(PyObject *) _PyExc_CreateExceptionGroup(
const char *msg,
PyObject *excs);

PyAPI_FUNC(PyObject *) _PyExc_ExceptionGroupProjection(
PyObject *left,
PyObject *right);
PyAPI_FUNC(PyObject *) _PyExc_PrepReraiseStar(
PyObject *orig,
PyObject *excs);

PyAPI_FUNC(int) _PyErr_CheckSignalsTstate(PyThreadState *tstate);

Expand Down
1 change: 1 addition & 0 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.11a4 3467 (Change CALL_xxx opcodes)
# Python 3.11a4 3468 (Add SEND opcode)
# Python 3.11a4 3469 (bpo-45711: remove type, traceback from exc_info)
# Python 3.11a4 3470 (bpo-45711: PREP_RERAISE_STAR no longer pushes lasti)

#
# MAGIC must change whenever the bytecode emitted by the compiler may no
Expand Down
120 changes: 118 additions & 2 deletions Objects/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1207,8 +1207,8 @@ collect_exception_group_leaves(PyObject *exc, PyObject *leaves)
* of eg which contains all leaf exceptions that are contained
* in any exception group in keep.
*/
PyObject *
_PyExc_ExceptionGroupProjection(PyObject *eg, PyObject *keep)
static PyObject *
exception_group_projection(PyObject *eg, PyObject *keep)
{
assert(_PyBaseExceptionGroup_Check(eg));
assert(PyList_CheckExact(keep));
Expand Down Expand Up @@ -1245,6 +1245,122 @@ _PyExc_ExceptionGroupProjection(PyObject *eg, PyObject *keep)
return result;
}

static bool
is_same_exception_metadata(PyObject *exc1, PyObject *exc2)
{
assert(PyExceptionInstance_Check(exc1));
assert(PyExceptionInstance_Check(exc2));

PyBaseExceptionObject *e1 = (PyBaseExceptionObject *)exc1;
PyBaseExceptionObject *e2 = (PyBaseExceptionObject *)exc2;

return (e1->note == e2->note &&
e1->traceback == e2->traceback &&
e1->cause == e2->cause &&
e1->context == e2->context);
}

/*
This function is used by the interpreter to calculate
the exception group to be raised at the end of a
try-except* construct.

orig: the original except that was caught.
excs: a list of exceptions that were raised/reraised
in the except* clauses.

Calculates an exception group to raise. It contains
all exceptions in excs, where those that were reraised
have same nesting structure as in orig, and those that
were raised (if any) are added as siblings in a new EG.

Returns NULL and sets an exception on failure.
*/
PyObject *
_PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs)
{
assert(PyExceptionInstance_Check(orig));
assert(PyList_Check(excs));

Py_ssize_t numexcs = PyList_GET_SIZE(excs);

if (numexcs == 0) {
return Py_NewRef(Py_None);
}

if (!_PyBaseExceptionGroup_Check(orig)) {
/* a naked exception was caught and wrapped. Only one except* clause
* could have executed,so there is at most one exception to raise.
*/

assert(numexcs == 1 || (numexcs == 2 && PyList_GET_ITEM(excs, 1) == Py_None));

PyObject *e = PyList_GET_ITEM(excs, 0);
assert(e != NULL);
return Py_NewRef(e);
}

PyObject *raised_list = PyList_New(0);
if (raised_list == NULL) {
return NULL;
}
PyObject* reraised_list = PyList_New(0);
if (reraised_list == NULL) {
Py_DECREF(raised_list);
return NULL;
}

/* Now we are holding refs to raised_list and reraised_list */

PyObject *result = NULL;

/* Split excs into raised and reraised by comparing metadata with orig */
for (Py_ssize_t i = 0; i < numexcs; i++) {
PyObject *e = PyList_GET_ITEM(excs, i);
assert(e != NULL);
if (Py_IsNone(e)) {
continue;
}
bool is_reraise = is_same_exception_metadata(e, orig);
PyObject *append_list = is_reraise ? reraised_list : raised_list;
if (PyList_Append(append_list, e) < 0) {
goto done;
}
}

PyObject *reraised_eg = exception_group_projection(orig, reraised_list);
if (reraised_eg == NULL) {
goto done;
}

if (!Py_IsNone(reraised_eg)) {
assert(is_same_exception_metadata(reraised_eg, orig));
}
Py_ssize_t num_raised = PyList_GET_SIZE(raised_list);
if (num_raised == 0) {
result = reraised_eg;
}
else if (num_raised > 0) {
int res = 0;
if (!Py_IsNone(reraised_eg)) {
res = PyList_Append(raised_list, reraised_eg);
}
Py_DECREF(reraised_eg);
if (res < 0) {
goto done;
}
result = _PyExc_CreateExceptionGroup("", raised_list);
if (result == NULL) {
goto done;
}
}

done:
Py_XDECREF(raised_list);
Py_XDECREF(reraised_list);
return result;
}

static PyMemberDef BaseExceptionGroup_members[] = {
{"message", T_OBJECT, offsetof(PyBaseExceptionGroupObject, msg), READONLY,
PyDoc_STR("exception message")},
Expand Down
131 changes: 1 addition & 130 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,6 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type,


static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
static PyObject *do_reraise_star(PyObject *excs, PyObject *orig);
static int exception_group_match(
PyObject* exc_value, PyObject *match_type,
PyObject **match, PyObject **rest);
Expand Down Expand Up @@ -2777,7 +2776,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(PyList_Check(excs));
PyObject *orig = POP();

PyObject *val = do_reraise_star(excs, orig);
PyObject *val = _PyExc_PrepReraiseStar(orig, excs);
Py_DECREF(excs);
Py_DECREF(orig);

Expand Down Expand Up @@ -6311,134 +6310,6 @@ exception_group_match(PyObject* exc_value, PyObject *match_type,
return 0;
}

/* Logic for the final raise/reraise of a try-except* contruct
(too complicated for inlining).
*/

static bool
is_same_exception_metadata(PyObject *exc1, PyObject *exc2)
{
assert(PyExceptionInstance_Check(exc1));
assert(PyExceptionInstance_Check(exc2));

PyObject *tb1 = PyException_GetTraceback(exc1);
PyObject *ctx1 = PyException_GetContext(exc1);
PyObject *cause1 = PyException_GetCause(exc1);
PyObject *tb2 = PyException_GetTraceback(exc2);
PyObject *ctx2 = PyException_GetContext(exc2);
PyObject *cause2 = PyException_GetCause(exc2);

bool result = (Py_Is(tb1, tb2) &&
Py_Is(ctx1, ctx2) &&
Py_Is(cause1, cause2));

Py_XDECREF(tb1);
Py_XDECREF(ctx1);
Py_XDECREF(cause1);
Py_XDECREF(tb2);
Py_XDECREF(ctx2);
Py_XDECREF(cause2);
return result;
}

/*
excs: a list of exceptions to raise/reraise
orig: the original except that was caught

Calculates an exception group to raise. It contains
all exceptions in excs, where those that were reraised
have same nesting structure as in orig, and those that
were raised (if any) are added as siblings in a new EG.

Returns NULL and sets an exception on failure.
*/
static PyObject *
do_reraise_star(PyObject *excs, PyObject *orig)
{
assert(PyList_Check(excs));
assert(PyExceptionInstance_Check(orig));

Py_ssize_t numexcs = PyList_GET_SIZE(excs);

if (numexcs == 0) {
return Py_NewRef(Py_None);
}

if (!_PyBaseExceptionGroup_Check(orig)) {
/* a naked exception was caught and wrapped. Only one except* clause
* could have executed,so there is at most one exception to raise.
*/

assert(numexcs == 1 || (numexcs == 2 && PyList_GET_ITEM(excs, 1) == Py_None));

PyObject *e = PyList_GET_ITEM(excs, 0);
assert(e != NULL);
return Py_NewRef(e);
}


PyObject *raised_list = PyList_New(0);
if (raised_list == NULL) {
return NULL;
}
PyObject* reraised_list = PyList_New(0);
if (reraised_list == NULL) {
Py_DECREF(raised_list);
return NULL;
}

/* Now we are holding refs to raised_list and reraised_list */

PyObject *result = NULL;

/* Split excs into raised and reraised by comparing metadata with orig */
for (Py_ssize_t i = 0; i < numexcs; i++) {
PyObject *e = PyList_GET_ITEM(excs, i);
assert(e != NULL);
if (Py_IsNone(e)) {
continue;
}
bool is_reraise = is_same_exception_metadata(e, orig);
PyObject *append_list = is_reraise ? reraised_list : raised_list;
if (PyList_Append(append_list, e) < 0) {
goto done;
}
}

PyObject *reraised_eg = _PyExc_ExceptionGroupProjection(orig, reraised_list);
if (reraised_eg == NULL) {
goto done;
}

if (!Py_IsNone(reraised_eg)) {
assert(is_same_exception_metadata(reraised_eg, orig));
}

Py_ssize_t num_raised = PyList_GET_SIZE(raised_list);
if (num_raised == 0) {
result = reraised_eg;
}
else if (num_raised > 0) {
int res = 0;
if (!Py_IsNone(reraised_eg)) {
res = PyList_Append(raised_list, reraised_eg);
}
Py_DECREF(reraised_eg);
if (res < 0) {
goto done;
}
result = _PyExc_CreateExceptionGroup("", raised_list);
if (result == NULL) {
goto done;
}
}

done:
Py_XDECREF(raised_list);
Py_XDECREF(reraised_list);
return result;
}

/* Iterate v argcnt times and store the results on the stack (via decreasing
sp). Return 1 for success, 0 if error.

Expand Down