Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 55183) +++ Python/ceval.c (working copy) @@ -479,7 +479,7 @@ WHY_YIELD = 0x0040 /* 'yield' operator */ }; -static enum why_code do_raise(PyObject *, PyObject *, PyObject *); +static enum why_code do_raise(PyObject *); static int unpack_iterable(PyObject *, int, PyObject **); /* for manipulating the thread switch and periodic "stuff" - used to be @@ -1624,18 +1624,12 @@ default: switch (opcode) { #endif case RAISE_VARARGS: - u = v = w = NULL; + u = NULL; switch (oparg) { - case 3: - u = POP(); /* traceback */ - /* Fallthrough */ - case 2: - v = POP(); /* value */ - /* Fallthrough */ case 1: - w = POP(); /* exc */ + u = POP(); /* inst */ case 0: /* Fallthrough */ - why = do_raise(w, v, u); + why = do_raise(u); break; default: PyErr_SetString(PyExc_SystemError, @@ -3010,100 +3004,60 @@ /* Logic for the raise statement (too complicated for inlining). This *consumes* a reference count to each of its arguments. */ static enum why_code -do_raise(PyObject *type, PyObject *value, PyObject *tb) +do_raise(PyObject *cls_inst) { - if (type == NULL) { - /* Reraise */ - PyThreadState *tstate = PyThreadState_GET(); - type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; - value = tstate->exc_value; - tb = tstate->exc_traceback; - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - } + PyThreadState *tstate = NULL; + PyObject *type = NULL; + PyObject *tb = NULL; - /* We support the following forms of raise: - raise , - raise , - raise , None - raise , - raise , None - raise , - raise , None + tstate = PyThreadState_GET(); - An omitted second argument is the same as None. + tb = tstate->exc_traceback; + Py_XINCREF(tb); - In addition, raise , is the same as - raising the tuple's first item (and it better have one!); - this rule is applied recursively. + if (cls_inst == NULL) { + /* Reraise */ + cls_inst = tstate->exc_value; + type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; + Py_XINCREF(cls_inst); + Py_XINCREF(type); + } - Finally, an optional third argument can be supplied, which - gives the traceback to be substituted (useful when - re-raising an exception after examining it). */ + else if (PyExceptionClass_Check(cls_inst)) { + /* At end must be: type => type of instance * + * cls_inst => instance * + * tb => traceback */ + PyObject *tmp; - /* First, check the traceback argument, replacing None with - NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = NULL; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } + PyErr_NormalizeException(&cls_inst, &type, &tb); + tmp = type; + type = cls_inst; + cls_inst = tmp; + } + + else if (PyExceptionInstance_Check(cls_inst)) { + type = PyExceptionInstance_Class(cls_inst); + Py_INCREF(type); + } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } + else { + PyErr_Format(PyExc_TypeError, + "exceptions must be classes or instances, not %s", + cls_inst->ob_type->tp_name); + Py_XDECREF(cls_inst); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; + } - /* Next, repeatedly, replace a tuple exception with its first item */ - while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { - PyObject *tmp = type; - type = PyTuple_GET_ITEM(type, 0); - Py_INCREF(type); - Py_DECREF(tmp); - } - - if (PyExceptionClass_Check(type)) - PyErr_NormalizeException(&type, &value, &tb); - - else if (PyExceptionInstance_Check(type)) { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - else { - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - type = PyExceptionInstance_Class(type); - Py_INCREF(type); - } - } - else { - /* Not something you can raise. You get an exception - anyway, just not what you specified :-) */ - PyErr_Format(PyExc_TypeError, - "exceptions must be classes or instances, not %s", - type->ob_type->tp_name); - goto raise_error; - } - PyErr_Restore(type, value, tb); - if (tb == NULL) - return WHY_EXCEPTION; - else - return WHY_RERAISE; - raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return WHY_EXCEPTION; + if (cls_inst != NULL) + ((PyBaseExceptionObject *)cls_inst)->traceback = tb; + + PyErr_Restore(type, cls_inst, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; } /* Iterate v argcnt times and store the results on the stack (via decreasing Index: Python/graminit.c =================================================================== --- Python/graminit.c (revision 55183) +++ Python/graminit.c (working copy) @@ -458,31 +458,13 @@ {26, 2}, {0, 1}, }; -static arc arcs_23_2[2] = { - {27, 3}, +static arc arcs_23_2[1] = { {0, 2}, }; -static arc arcs_23_3[1] = { - {26, 4}, -}; -static arc arcs_23_4[2] = { - {27, 5}, - {0, 4}, -}; -static arc arcs_23_5[1] = { - {26, 6}, -}; -static arc arcs_23_6[1] = { - {0, 6}, -}; -static state states_23[7] = { +static state states_23[3] = { {1, arcs_23_0}, {2, arcs_23_1}, - {2, arcs_23_2}, - {1, arcs_23_3}, - {2, arcs_23_4}, - {1, arcs_23_5}, - {1, arcs_23_6}, + {1, arcs_23_2}, }; static arc arcs_24_0[2] = { {70, 1}, @@ -1825,7 +1807,7 @@ "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000"}, {278, "yield_stmt", 0, 2, states_22, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200"}, - {279, "raise_stmt", 0, 7, states_23, + {279, "raise_stmt", 0, 3, states_23, "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"}, {280, "import_stmt", 0, 2, states_24, "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000"}, Index: Python/ast.c =================================================================== --- Python/ast.c (revision 55183) +++ Python/ast.c (working copy) @@ -2143,7 +2143,7 @@ return_stmt: 'return' [testlist] yield_stmt: yield_expr yield_expr: 'yield' testlist - raise_stmt: 'raise' [test [',' test [',' test]]] + raise_stmt: 'raise' [test] */ node *ch; @@ -2172,44 +2172,15 @@ } case raise_stmt: if (NCH(ch) == 1) - return Raise(NULL, NULL, NULL, LINENO(n), n->n_col_offset, + return Raise(NULL, LINENO(n), n->n_col_offset, c->c_arena); else if (NCH(ch) == 2) { expr_ty expression = ast_for_expr(c, CHILD(ch, 1)); if (!expression) return NULL; - return Raise(expression, NULL, NULL, LINENO(n), + return Raise(expression, LINENO(n), n->n_col_offset, c->c_arena); } - else if (NCH(ch) == 4) { - expr_ty expr1, expr2; - - expr1 = ast_for_expr(c, CHILD(ch, 1)); - if (!expr1) - return NULL; - expr2 = ast_for_expr(c, CHILD(ch, 3)); - if (!expr2) - return NULL; - - return Raise(expr1, expr2, NULL, LINENO(n), n->n_col_offset, - c->c_arena); - } - else if (NCH(ch) == 6) { - expr_ty expr1, expr2, expr3; - - expr1 = ast_for_expr(c, CHILD(ch, 1)); - if (!expr1) - return NULL; - expr2 = ast_for_expr(c, CHILD(ch, 3)); - if (!expr2) - return NULL; - expr3 = ast_for_expr(c, CHILD(ch, 5)); - if (!expr3) - return NULL; - - return Raise(expr1, expr2, expr3, LINENO(n), n->n_col_offset, - c->c_arena); - } default: PyErr_Format(PyExc_SystemError, "unexpected flow_stmt: %d", TYPE(ch)); Index: Python/symtable.c =================================================================== --- Python/symtable.c (revision 55183) +++ Python/symtable.c (working copy) @@ -1008,13 +1008,8 @@ VISIT_SEQ(st, stmt, s->v.If.orelse); break; case Raise_kind: - if (s->v.Raise.type) { - VISIT(st, expr, s->v.Raise.type); - if (s->v.Raise.inst) { - VISIT(st, expr, s->v.Raise.inst); - if (s->v.Raise.tback) - VISIT(st, expr, s->v.Raise.tback); - } + if (s->v.Raise.inst) { + VISIT(st, expr, s->v.Raise.inst); } break; case TryExcept_kind: Index: Python/compile.c =================================================================== --- Python/compile.c (revision 55183) +++ Python/compile.c (working copy) @@ -2054,17 +2054,9 @@ return compiler_if(c, s); case Raise_kind: n = 0; - if (s->v.Raise.type) { - VISIT(c, expr, s->v.Raise.type); + if (s->v.Raise.inst) { + VISIT(c, expr, s->v.Raise.inst); n++; - if (s->v.Raise.inst) { - VISIT(c, expr, s->v.Raise.inst); - n++; - if (s->v.Raise.tback) { - VISIT(c, expr, s->v.Raise.tback); - n++; - } - } } ADDOP_I(c, RAISE_VARARGS, n); break; Index: Python/Python-ast.c =================================================================== --- Python/Python-ast.c (revision 55183) +++ Python/Python-ast.c (working copy) @@ -102,9 +102,7 @@ }; static PyTypeObject *Raise_type; static char *Raise_fields[]={ - "type", "inst", - "tback", }; static PyTypeObject *TryExcept_type; static char *TryExcept_fields[]={ @@ -489,7 +487,7 @@ if (!If_type) return 0; With_type = make_type("With", stmt_type, With_fields, 3); if (!With_type) return 0; - Raise_type = make_type("Raise", stmt_type, Raise_fields, 3); + Raise_type = make_type("Raise", stmt_type, Raise_fields, 1); if (!Raise_type) return 0; TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3); if (!TryExcept_type) return 0; @@ -1031,17 +1029,14 @@ } stmt_ty -Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int col_offset, - PyArena *arena) +Raise(expr_ty inst, int lineno, int col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Raise_kind; - p->v.Raise.type = type; p->v.Raise.inst = inst; - p->v.Raise.tback = tback; p->lineno = lineno; p->col_offset = col_offset; return p; @@ -2086,21 +2081,11 @@ case Raise_kind: result = PyType_GenericNew(Raise_type, NULL, NULL); if (!result) goto failed; - value = ast2obj_expr(o->v.Raise.type); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "type", value) == -1) - goto failed; - Py_DECREF(value); value = ast2obj_expr(o->v.Raise.inst); if (!value) goto failed; if (PyObject_SetAttrString(result, "inst", value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_expr(o->v.Raise.tback); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "tback", value) == -1) - goto failed; - Py_DECREF(value); break; case TryExcept_kind: result = PyType_GenericNew(TryExcept_type, NULL, NULL); Index: Include/Python-ast.h =================================================================== --- Include/Python-ast.h (revision 55183) +++ Include/Python-ast.h (working copy) @@ -133,9 +133,7 @@ } With; struct { - expr_ty type; expr_ty inst; - expr_ty tback; } Raise; struct { @@ -390,9 +388,9 @@ #define With(a0, a1, a2, a3, a4, a5) _Py_With(a0, a1, a2, a3, a4, a5) stmt_ty _Py_With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int lineno, int col_offset, PyArena *arena); -#define Raise(a0, a1, a2, a3, a4, a5) _Py_Raise(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int - col_offset, PyArena *arena); +#define Raise(a0, a1, a2, a3) _Py_Raise(a0, a1, a2, a3) +stmt_ty _Py_Raise(expr_ty inst, int lineno, int col_offset, + PyArena *arena); #define TryExcept(a0, a1, a2, a3, a4, a5) _Py_TryExcept(a0, a1, a2, a3, a4, a5) stmt_ty _Py_TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int lineno, int col_offset, PyArena *arena); Index: Include/pyerrors.h =================================================================== --- Include/pyerrors.h (revision 55183) +++ Include/pyerrors.h (working copy) @@ -11,6 +11,7 @@ PyObject *dict; PyObject *args; PyObject *message; + PyObject *traceback; } PyBaseExceptionObject; typedef struct { @@ -18,6 +19,7 @@ PyObject *dict; PyObject *args; PyObject *message; + PyObject *traceback; PyObject *msg; PyObject *filename; PyObject *lineno; @@ -32,6 +34,7 @@ PyObject *dict; PyObject *args; PyObject *message; + PyObject *traceback; PyObject *encoding; PyObject *object; PyObject *start; @@ -45,6 +48,7 @@ PyObject *dict; PyObject *args; PyObject *message; + PyObject *traceback; PyObject *code; } PySystemExitObject; @@ -53,6 +57,7 @@ PyObject *dict; PyObject *args; PyObject *message; + PyObject *traceback; PyObject *myerrno; PyObject *strerror; PyObject *filename; @@ -64,6 +69,7 @@ PyObject *dict; PyObject *args; PyObject *message; + PyObject *traceback; PyObject *myerrno; PyObject *strerror; PyObject *filename; Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (revision 55183) +++ Grammar/Grammar (working copy) @@ -59,7 +59,7 @@ continue_stmt: 'continue' return_stmt: 'return' [testlist] yield_stmt: yield_expr -raise_stmt: 'raise' [test [',' test [',' test]]] +raise_stmt: 'raise' [test] import_stmt: import_name | import_from import_name: 'import' dotted_as_names import_from: ('from' ('.'* dotted_name | '.'+) Index: Objects/exceptions.c =================================================================== --- Objects/exceptions.c (revision 55183) +++ Objects/exceptions.c (working copy) @@ -49,6 +49,9 @@ Py_DECREF(self); return NULL; } + + Py_INCREF(Py_None); + self->traceback = Py_None; return (PyObject *)self; } @@ -77,6 +80,7 @@ Py_CLEAR(self->dict); Py_CLEAR(self->args); Py_CLEAR(self->message); + Py_CLEAR(self->traceback); return 0; } @@ -94,6 +98,7 @@ Py_VISIT(self->dict); Py_VISIT(self->args); Py_VISIT(self->message); + Py_VISIT(self->traceback); return 0; } @@ -177,10 +182,25 @@ Py_RETURN_NONE; } +static int BaseException_set_traceback(PyBaseExceptionObject *, PyObject *); +static PyObject * +BaseException_with_traceback(PyBaseExceptionObject *self, PyObject *tb) +{ + int ret; + + ret = BaseException_set_traceback(self, tb); + if (ret == -1) + return NULL; + + Py_RETURN_NONE; +} + + static PyMethodDef BaseException_methods[] = { {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, {"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, + {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O }, {NULL, NULL, 0, NULL}, }; @@ -298,11 +318,41 @@ return 0; } +static PyObject * +BaseException_get_traceback(PyBaseExceptionObject *self) +{ + if (self->traceback == NULL) + Py_RETURN_NONE; + + Py_INCREF(self->traceback); + Py_RETURN_NONE; +} + +static int +BaseException_set_traceback(PyBaseExceptionObject *self, PyObject *val) +{ + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted"); + return -1; + } + else if (!PyTraceBack_Check(val) && (val != Py_None)) { + PyErr_SetString(PyExc_TypeError, + "argument's type must be a traceback, or None"); + return -1; + } + Py_XDECREF(self->traceback); + self->traceback = val; + Py_INCREF(self->traceback); + return 0; +} + static PyGetSetDef BaseException_getset[] = { {"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict}, {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, {"message", (getter)BaseException_get_message, (setter)BaseException_set_message}, + {"__traceback__", (getter)BaseException_get_traceback, + (setter)BaseException_set_traceback}, {NULL}, }; Index: Parser/Python.asdl =================================================================== --- Parser/Python.asdl (revision 55183) +++ Parser/Python.asdl (working copy) @@ -27,8 +27,7 @@ | If(expr test, stmt* body, stmt* orelse) | With(expr context_expr, expr? optional_vars, stmt* body) - -- 'type' is a bad name - | Raise(expr? type, expr? inst, expr? tback) + | Raise(expr? inst) | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) | TryFinally(stmt* body, stmt* finalbody) | Assert(expr test, expr? msg)