Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 61188) +++ Python/ceval.c (working copy) @@ -2253,18 +2253,21 @@ case WITH_CLEANUP: { - /* TOP is the context.__exit__ bound method. - Below that are 1-3 values indicating how/why - we entered the finally clause: - - SECOND = None - - (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval - - SECOND = WHY_*; no retval below it - - (SECOND, THIRD, FOURTH) = exc_info() + /* At the top of the stack are 1-3 values indicating + how/why we entered the finally clause: + - TOP = None + - (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval + - TOP = WHY_*; no retval below it + - (TOP, SECOND, THIRD) = exc_info() + Below them is EXIT, the context.__exit__ bound method. In the last case, we must call - TOP(SECOND, THIRD, FOURTH) + EXIT(TOP, SECOND, THIRD) otherwise we must call - TOP(None, None, None) + EXIT(None, None, None) + In all cases, we remove EXIT from the stack, leaving + the rest in the same order. + In addition, if the stack represents an exception, *and* the function call returns a 'true' value, we "zap" this information, to prevent END_FINALLY from @@ -2272,36 +2275,59 @@ should still be resumed.) */ - x = TOP(); - u = SECOND(); - if (PyInt_Check(u) || u == Py_None) { + PyObject *exit_result; + + u = POP(); + if (u == Py_None) { + x = TOP(); + SET_TOP(u); + v = w = Py_None; + } + else if (PyInt_Check(u)) { + switch(PyInt_AS_LONG(u)) { + case WHY_RETURN: + case WHY_CONTINUE: + /* Retval in TOP. */ + x = SECOND(); + SET_SECOND(TOP()); + SET_TOP(u); + break; + default: + x = TOP(); + SET_TOP(u); + break; + } u = v = w = Py_None; } else { - v = THIRD(); - w = FOURTH(); + v = TOP(); + w = SECOND(); + x = THIRD(); + SET_TOP(u); + SET_SECOND(v); + SET_THIRD(w); } /* XXX Not the fastest way to call it... */ - x = PyObject_CallFunctionObjArgs(x, u, v, w, NULL); - if (x == NULL) + exit_result = PyObject_CallFunctionObjArgs(x, u, v, w, + NULL); + if (exit_result == NULL) { + x = NULL; break; /* Go to error exit */ - if (u != Py_None && PyObject_IsTrue(x)) { + } + if (u != Py_None && PyObject_IsTrue(exit_result)) { /* There was an exception and a true return */ - Py_DECREF(x); - x = TOP(); /* Again */ - STACKADJ(-3); + STACKADJ(-2); Py_INCREF(Py_None); SET_TOP(Py_None); - Py_DECREF(x); Py_DECREF(u); Py_DECREF(v); Py_DECREF(w); } else { - /* Let END_FINALLY do its thing */ - Py_DECREF(x); - x = POP(); - Py_DECREF(x); + /* The stack was rearranged to remove EXIT + above. Let END_FINALLY do its thing */ } + Py_DECREF(x); + Py_DECREF(exit_result); break; } Index: Python/compile.c =================================================================== --- Python/compile.c (revision 61188) +++ Python/compile.c (working copy) @@ -2887,11 +2887,10 @@ /* Evaluate EXPR */ VISIT(c, expr, s->v.With.context_expr); - /* Squirrel away context.__exit__ */ + /* Squirrel away context.__exit__ by stuffing it under context */ ADDOP(c, DUP_TOP); ADDOP_O(c, LOAD_ATTR, exit_attr, names); - if (!compiler_nameop(c, tmpexit, Store)) - return 0; + ADDOP(c, ROT_TWO); /* Call context.__enter__() */ ADDOP_O(c, LOAD_ATTR, enter_attr, names); @@ -2935,10 +2934,9 @@ if (!compiler_push_fblock(c, FINALLY_END, finally)) return 0; - /* Finally block starts; push tmpexit and issue our magic opcode. */ - if (!compiler_nameop(c, tmpexit, Load) || - !compiler_nameop(c, tmpexit, Del)) - return 0; + /* Finally block starts; tmpexit is on the stack under the + exception or return information. Just issue our magic + opcode. */ ADDOP(c, WITH_CLEANUP); /* Finally block ends. */