From 7889107be7cb5a28aabcdfa33778bdce3e9b5c27 Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Thu, 1 Mar 2001 06:09:34 +0000 Subject: [PATCH] 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. --- Python/compile.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index bd6a679658d..efef05b25a9 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;