mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
Um, I thought I'd already checked this in.
Anyway, this is the changes to the with-statement so that __exit__ must return a true value in order for a pending exception to be ignored. The PEP (343) is already updated.
This commit is contained in:
parent
692cdbc5d6
commit
f669436189
11 changed files with 61 additions and 106 deletions
|
@ -2189,48 +2189,51 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
|
|||
Below that are 1-3 values indicating how/why
|
||||
we entered the finally clause:
|
||||
- SECOND = None
|
||||
- (SECOND, THIRD) = (WHY_RETURN or WHY_CONTINUE), retval
|
||||
- (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval
|
||||
- SECOND = WHY_*; no retval below it
|
||||
- (SECOND, THIRD, FOURTH) = exc_info()
|
||||
In the last case, we must call
|
||||
TOP(SECOND, THIRD, FOURTH)
|
||||
otherwise we must call
|
||||
TOP(None, None, None)
|
||||
but we must preserve the stack entries below TOP.
|
||||
The code here just sets the stack up for the call;
|
||||
separate CALL_FUNCTION(3) and POP_TOP opcodes are
|
||||
emitted by the compiler.
|
||||
|
||||
In addition, if the stack represents an exception,
|
||||
we "zap" this information; __exit__() should
|
||||
re-raise the exception if it wants to, and if
|
||||
__exit__() returns normally, END_FINALLY should
|
||||
*not* re-raise the exception. (But non-local
|
||||
gotos should still be resumed.)
|
||||
*and* the function call returns a 'true' value, we
|
||||
"zap" this information, to prevent END_FINALLY from
|
||||
re-raising the exception. (But non-local gotos
|
||||
should still be resumed.)
|
||||
*/
|
||||
|
||||
x = TOP();
|
||||
u = SECOND();
|
||||
if (PyInt_Check(u) || u == Py_None) {
|
||||
u = v = w = Py_None;
|
||||
Py_INCREF(u);
|
||||
Py_INCREF(v);
|
||||
Py_INCREF(w);
|
||||
}
|
||||
else {
|
||||
v = THIRD();
|
||||
w = FOURTH();
|
||||
/* Zap the exception from the stack,
|
||||
to fool END_FINALLY. */
|
||||
STACKADJ(-2);
|
||||
SET_TOP(x);
|
||||
Py_INCREF(Py_None);
|
||||
SET_SECOND(Py_None);
|
||||
}
|
||||
STACKADJ(3);
|
||||
SET_THIRD(u);
|
||||
SET_SECOND(v);
|
||||
SET_TOP(w);
|
||||
/* XXX Not the fastest way to call it... */
|
||||
x = PyObject_CallFunctionObjArgs(x, u, v, w, NULL);
|
||||
if (x == NULL)
|
||||
break; /* Go to error exit */
|
||||
if (u != Py_None && PyObject_IsTrue(x)) {
|
||||
/* There was an exception and a true return */
|
||||
Py_DECREF(x);
|
||||
x = TOP(); /* Again */
|
||||
STACKADJ(-3);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1382,7 +1382,7 @@ opcode_stack_effect(int opcode, int oparg)
|
|||
case BREAK_LOOP:
|
||||
return 0;
|
||||
case WITH_CLEANUP:
|
||||
return 3;
|
||||
return -1; /* XXX Sometimes more */
|
||||
case LOAD_LOCALS:
|
||||
return 1;
|
||||
case RETURN_VALUE:
|
||||
|
@ -3472,8 +3472,6 @@ compiler_with(struct compiler *c, stmt_ty s)
|
|||
!compiler_nameop(c, tmpexit, Del))
|
||||
return 0;
|
||||
ADDOP(c, WITH_CLEANUP);
|
||||
ADDOP_I(c, CALL_FUNCTION, 3);
|
||||
ADDOP(c, POP_TOP);
|
||||
|
||||
/* Finally block ends. */
|
||||
ADDOP(c, END_FINALLY);
|
||||
|
|
|
@ -55,6 +55,7 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
|
|||
Python 2.5a0: 62071
|
||||
Python 2.5a0: 62081 (ast-branch)
|
||||
Python 2.5a0: 62091 (with)
|
||||
Python 2.5a0: 62092 (changed WITH_CLEANUP opcode)
|
||||
.
|
||||
*/
|
||||
#define MAGIC (62092 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue