diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-03-01 06:09:34 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-03-01 06:09:34 (GMT) |
commit | 7889107be7cb5a28aabcdfa33778bdce3e9b5c27 (patch) | |
tree | 5fd51200881acad3410e05b2eb52e7204e23a8ec /Python/compile.c | |
parent | a52e8fe49a625d13d89967bc17adeb71520bf3d0 (diff) | |
download | cpython-7889107be7cb5a28aabcdfa33778bdce3e9b5c27.zip cpython-7889107be7cb5a28aabcdfa33778bdce3e9b5c27.tar.gz cpython-7889107be7cb5a28aabcdfa33778bdce3e9b5c27.tar.bz2 |
Fix core dump in example from Samuele Pedroni:
from __future__ import nested_scopes
x=7
def f():
x=1
def g():
global x
def i():
def h():
return x
return h()
return i()
return g()
print f()
print x
This kind of code didn't work correctly because x was treated as free
in i, leading to an attempt to load x in g to make a closure for i.
Solution is to make global decl apply to nested scopes unless their is
an assignment. Thus, x in h is global.
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/Python/compile.c b/Python/compile.c index bd6a679..efef05b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -179,6 +179,8 @@ code_hash(PyCodeObject *co) return h; } +/* XXX code objects need to participate in GC? */ + PyTypeObject PyCode_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -2132,8 +2134,13 @@ com_make_closure(struct compiling *c, PyCodeObject *co) else /* (reftype == FREE) */ arg = com_lookup_arg(c->c_freevars, name); if (arg == -1) { - fprintf(stderr, "lookup %s in %s %d %d\n", - PyObject_REPR(name), c->c_name, reftype, arg); + fprintf(stderr, "lookup %s in %s %d %d\n" + "freevars of %s: %s\n", + PyObject_REPR(name), + c->c_name, + reftype, arg, + PyString_AS_STRING(co->co_name), + PyObject_REPR(co->co_freevars)); Py_FatalError("com_make_closure()"); } com_addoparg(c, LOAD_CLOSURE, arg); @@ -4424,8 +4431,8 @@ symtable_update_free_vars(struct symtable *st) child = (PySymtableEntryObject *) PyList_GET_ITEM(ste->ste_children, i); while (PyDict_Next(child->ste_symbols, &pos, &name, &o)) { - int v = PyInt_AS_LONG(o); - if (!(is_free(v))) + int flags = PyInt_AS_LONG(o); + if (!(is_free(flags))) continue; /* avoids indentation */ if (list == NULL) { list = PyList_New(0); @@ -4438,18 +4445,24 @@ symtable_update_free_vars(struct symtable *st) return -1; } } -/* - if (st->st_nested_scopes == 0 - && list && PyList_GET_SIZE(list) > 0) { - fprintf(stderr, "function %s has children with " - "the following free vars:\n%s\n", - PyString_AS_STRING(ste->ste_name), - PyObject_REPR(list)); - continue; - } -*/ for (j = 0; list && j < PyList_GET_SIZE(list); j++) { + PyObject *v; name = PyList_GET_ITEM(list, j); + v = PyDict_GetItem(ste->ste_symbols, name); + /* If a name N is declared global in scope A and + referenced in scope B contained (perhaps + indirectly) in A and there are no scopes + with bindings for N between B and A, then N + is global in B. + */ + if (v) { + int flags = PyInt_AS_LONG(v); + if (flags & DEF_GLOBAL) { + symtable_undo_free(st, child->ste_id, + name); + continue; + } + } if (ste->ste_nested) { if (symtable_add_def_o(st, ste->ste_symbols, name, def) < 0) { @@ -4481,13 +4494,14 @@ symtable_check_global(struct symtable *st, PyObject *child, PyObject *name) PyObject *o; int v; PySymtableEntryObject *ste = st->st_cur; - + if (ste->ste_type == TYPE_CLASS) return symtable_undo_free(st, child, name); o = PyDict_GetItem(ste->ste_symbols, name); if (o == NULL) return symtable_undo_free(st, child, name); v = PyInt_AS_LONG(o); + if (is_free(v) || (v & DEF_GLOBAL)) return symtable_undo_free(st, child, name); else @@ -4506,6 +4520,7 @@ symtable_undo_free(struct symtable *st, PyObject *id, ste = (PySymtableEntryObject *)PyDict_GetItem(st->st_symbols, id); if (ste == NULL) return -1; + info = PyDict_GetItem(ste->ste_symbols, name); if (info == NULL) return 0; @@ -4938,6 +4953,7 @@ symtable_global(struct symtable *st, node *n) int i; if (st->st_nscopes == 1) { + /* XXX must check that we are compiling file_input */ if (symtable_warn(st, "global statement has no meaning at module level") < 0) return; |