summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2006-03-10 02:28:35 (GMT)
committerGuido van Rossum <guido@python.org>2006-03-10 02:28:35 (GMT)
commitf669436189dd44a841caa9ab1ad97a3f7662bf58 (patch)
tree1a717975d09d4867e8807710a36a6c2999afdb7e /Python/ceval.c
parent692cdbc5d648da5239b5caececc954960aa024e9 (diff)
downloadcpython-f669436189dd44a841caa9ab1ad97a3f7662bf58.zip
cpython-f669436189dd44a841caa9ab1ad97a3f7662bf58.tar.gz
cpython-f669436189dd44a841caa9ab1ad97a3f7662bf58.tar.bz2
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.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c47
1 files changed, 25 insertions, 22 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index e7fb875..de2b35b 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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);
+ }
+ /* 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_SECOND(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);
}
- STACKADJ(3);
- SET_THIRD(u);
- SET_SECOND(v);
- SET_TOP(w);
break;
}