summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorAmaury Forgeot d'Arc <amauryfa@gmail.com>2010-09-10 21:39:53 (GMT)
committerAmaury Forgeot d'Arc <amauryfa@gmail.com>2010-09-10 21:39:53 (GMT)
commitba117ef7e9b2f7f2fbec62a9fcfe371a68024769 (patch)
tree3ca491174a99860c368d8d243d8db31b13b6ecf8 /Python/ceval.c
parent4785916d62aeb97692bab08bb9e77952853084a4 (diff)
downloadcpython-ba117ef7e9b2f7f2fbec62a9fcfe371a68024769.zip
cpython-ba117ef7e9b2f7f2fbec62a9fcfe371a68024769.tar.gz
cpython-ba117ef7e9b2f7f2fbec62a9fcfe371a68024769.tar.bz2
#4617: Previously it was illegal to delete a name from the local
namespace if it occurs as a free variable in a nested block. This limitation of the compiler has been lifted, and a new opcode introduced (DELETE_DEREF). This sample was valid in 2.6, but fails to compile in 3.x without this change:: >>> def f(): ... def print_error(): ... print(e) ... try: ... something ... except Exception as e: ... print_error() ... # implicit "del e" here This sample has always been invalid in Python, and now works:: >>> def outer(x): ... def inner(): ... return x ... inner() ... del x There is no need to bump the PYC magic number: the new opcode is used for code that did not compile before.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c50
1 files changed, 34 insertions, 16 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 1f78f95..f0d278c 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -135,6 +135,7 @@ static PyObject * cmp_outcome(int, PyObject *, PyObject *);
static PyObject * import_from(PyObject *, PyObject *);
static int import_all_from(PyObject *, PyObject *);
static void format_exc_check_arg(PyObject *, const char *, PyObject *);
+static void format_exc_unbound(PyCodeObject *co, int oparg);
static PyObject * unicode_concatenate(PyObject *, PyObject *,
PyFrameObject *, unsigned char *);
static PyObject * special_lookup(PyObject *, char *, PyObject **);
@@ -2143,6 +2144,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
);
break;
+ TARGET(DELETE_DEREF)
+ x = freevars[oparg];
+ if (PyCell_GET(x) != NULL) {
+ PyCell_Set(x, NULL);
+ continue;
+ }
+ err = -1;
+ format_exc_unbound(co, oparg);
+ break;
+
TARGET(LOAD_CLOSURE)
x = freevars[oparg];
Py_INCREF(x);
@@ -2158,22 +2169,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
err = -1;
- /* Don't stomp existing exception */
- if (PyErr_Occurred())
- break;
- if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
- v = PyTuple_GET_ITEM(co->co_cellvars,
- oparg);
- format_exc_check_arg(
- PyExc_UnboundLocalError,
- UNBOUNDLOCAL_ERROR_MSG,
- v);
- } else {
- v = PyTuple_GET_ITEM(co->co_freevars, oparg -
- PyTuple_GET_SIZE(co->co_cellvars));
- format_exc_check_arg(PyExc_NameError,
- UNBOUNDFREE_ERROR_MSG, v);
- }
+ format_exc_unbound(co, oparg);
break;
TARGET(STORE_DEREF)
@@ -4352,6 +4348,28 @@ format_exc_check_arg(PyObject *exc, const char *format_str, PyObject *obj)
PyErr_Format(exc, format_str, obj_str);
}
+static void
+format_exc_unbound(PyCodeObject *co, int oparg)
+{
+ PyObject *name;
+ /* Don't stomp existing exception */
+ if (PyErr_Occurred())
+ return;
+ if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
+ name = PyTuple_GET_ITEM(co->co_cellvars,
+ oparg);
+ format_exc_check_arg(
+ PyExc_UnboundLocalError,
+ UNBOUNDLOCAL_ERROR_MSG,
+ name);
+ } else {
+ name = PyTuple_GET_ITEM(co->co_freevars, oparg -
+ PyTuple_GET_SIZE(co->co_cellvars));
+ format_exc_check_arg(PyExc_NameError,
+ UNBOUNDFREE_ERROR_MSG, name);
+ }
+}
+
static PyObject *
unicode_concatenate(PyObject *v, PyObject *w,
PyFrameObject *f, unsigned char *next_instr)