mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
a52e8fe49a
commit
7889107be7
|
@ -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) {
|
||||
|
@ -4488,6 +4501,7 @@ symtable_check_global(struct symtable *st, PyObject *child, PyObject *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;
|
||||
|
|
Loading…
Reference in New Issue