summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Python/compile.c145
1 files changed, 119 insertions, 26 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 2646dbe..3ff984b 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -312,7 +312,6 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags,
co->co_firstlineno = firstlineno;
Py_INCREF(lnotab);
co->co_lnotab = lnotab;
-/* PyObject_Print((PyObject *)co, stderr, 0); */
}
return co;
}
@@ -1151,7 +1150,8 @@ parsestr(char *s)
*p++ = c;
break;
case 'x':
- if (isxdigit(Py_CHARMASK(s[0])) && isxdigit(Py_CHARMASK(s[1]))) {
+ if (isxdigit(Py_CHARMASK(s[0]))
+ && isxdigit(Py_CHARMASK(s[1]))) {
unsigned int x = 0;
c = Py_CHARMASK(*s);
s++;
@@ -1173,7 +1173,8 @@ parsestr(char *s)
*p++ = x;
break;
}
- PyErr_SetString(PyExc_ValueError, "invalid \\x escape");
+ PyErr_SetString(PyExc_ValueError,
+ "invalid \\x escape");
Py_DECREF(v);
return NULL;
default:
@@ -2647,7 +2648,7 @@ com_import_stmt(struct compiling *c, node *n)
for (i = 3; i < NCH(n); i += 2) {
PyTuple_SET_ITEM(tup, (i-3)/2,
PyString_FromString(STR(
- CHILD(CHILD(n, i), 0))));
+ CHILD(CHILD(n, i), 0))));
}
}
com_addoparg(c, LOAD_CONST, com_addconst(c, tup));
@@ -3985,7 +3986,7 @@ get_ref_type(struct compiling *c, char *name)
/* Helper function to issue symbol table warnings */
-static void
+static int
symtable_warn(struct symtable *st, char *msg)
{
if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, st->st_filename,
@@ -3996,7 +3997,9 @@ symtable_warn(struct symtable *st, char *msg)
st->st_cur->ste_lineno);
}
st->st_errors++;
+ return -1;
}
+ return 0;
}
/* Helper function for setting lineno and filename */
@@ -4120,6 +4123,98 @@ symtable_freevar_offsets(PyObject *freevars, int offset)
}
static int
+symtable_check_unoptimized(struct compiling *c,
+ PySymtableEntryObject *ste,
+ struct symbol_info *si)
+{
+ char buf[300];
+
+ if (!(si->si_ncells || si->si_nfrees || ste->ste_child_free
+ || (ste->ste_nested && si->si_nimplicit)))
+ return 0;
+
+#define ILLEGAL_IMPORT_STAR \
+"import * is not allowed in function '%.100s' " \
+"because it contains a nested function with free variables"
+
+#define ILLEGAL_BARE_EXEC \
+"unqualified exec is not allowed in function '%.100s' " \
+"because it contains a nested function with free variables"
+
+#define ILLEGAL_EXEC_AND_IMPORT_STAR \
+"function '%.100s' uses import * and bare exec, which are illegal" \
+"because it contains a nested function with free variables"
+
+ /* XXX perhaps the linenos for these opt-breaking statements
+ should be stored so the exception can point to them. */
+
+ if (ste->ste_optimized == OPT_IMPORT_STAR)
+ sprintf(buf, ILLEGAL_IMPORT_STAR,
+ PyString_AS_STRING(ste->ste_name));
+ else if (ste->ste_optimized == (OPT_BARE_EXEC | OPT_EXEC))
+ sprintf(buf, ILLEGAL_BARE_EXEC,
+ PyString_AS_STRING(ste->ste_name));
+ else {
+ sprintf(buf, ILLEGAL_EXEC_AND_IMPORT_STAR,
+ PyString_AS_STRING(ste->ste_name));
+ }
+
+ if (c->c_symtable->st_nested_scopes) {
+ PyErr_SetString(PyExc_SyntaxError, buf);
+ PyErr_SyntaxLocation(c->c_symtable->st_filename,
+ ste->ste_lineno);
+ return -1;
+ } else {
+ /* XXX if the warning becomes an exception, we should
+ attached more info to it. */
+ if (PyErr_Warn(PyExc_SyntaxWarning, buf) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int
+symtable_check_shadow(struct symtable *st, PyObject *name, int flags)
+{
+ char buf[500];
+ PyObject *children, *v;
+ PySymtableEntryObject *child;
+ int i;
+
+ if (!(flags & DEF_BOUND))
+ return 0;
+ /* The semantics of this code will change with nested scopes.
+ It is defined in the current scope and referenced in a
+ child scope. Under the old rules, the child will see a
+ global. Under the new rules, the child will see the
+ binding in the current scope.
+ */
+
+ /* Find name of child function that has free variable */
+ children = st->st_cur->ste_children;
+ for (i = 0; i < PyList_GET_SIZE(children); i++) {
+ int cflags;
+ child = (PySymtableEntryObject *)PyList_GET_ITEM(children, i);
+ v = PyDict_GetItem(child->ste_symbols, name);
+ if (v == NULL)
+ continue;
+ cflags = PyInt_AS_LONG(v);
+ if (!(cflags & DEF_BOUND))
+ break;
+ }
+
+ sprintf(buf, "local name '%.100s' in '%.100s' shadows "
+ "use of '%.100s' as global in nested scope '%.100s'",
+ PyString_AS_STRING(name),
+ PyString_AS_STRING(st->st_cur->ste_name),
+ PyString_AS_STRING(name),
+ PyString_AS_STRING(child->ste_name)
+ );
+
+ return symtable_warn(st, buf);
+}
+
+static int
symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
struct symbol_info *si)
{
@@ -4129,26 +4224,8 @@ symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
c->c_nlocals = si->si_nlocals;
if (ste->ste_optimized == 0)
c->c_flags |= CO_OPTIMIZED;
- else if (si->si_ncells || si->si_nfrees
- || (ste->ste_nested && si->si_nimplicit)
- || ste->ste_child_free) {
- if (c->c_symtable->st_nested_scopes) {
- PyErr_Format(PyExc_SyntaxError,
- ILLEGAL_DYNAMIC_SCOPE,
- PyString_AS_STRING(ste->ste_name));
- PyErr_SyntaxLocation(c->c_symtable->st_filename,
- ste->ste_lineno);
- return -1;
- } else {
- char buf[200];
- sprintf(buf, ILLEGAL_DYNAMIC_SCOPE,
- PyString_AS_STRING(ste->ste_name));
- if (PyErr_Warn(PyExc_SyntaxWarning,
- buf) < 0) {
- return -1;
- }
- }
- }
+ else if (ste->ste_optimized != OPT_EXEC)
+ return symtable_check_unoptimized(c, ste, si);
}
return 0;
}
@@ -4191,6 +4268,12 @@ symtable_load_symbols(struct compiling *c)
while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
flags = PyInt_AS_LONG(v);
+ if (st->st_nested_scopes == 0
+ && (flags & (DEF_FREE | DEF_FREE_CLASS))) {
+ if (symtable_check_shadow(st, name, flags) < 0)
+ goto fail;
+ }
+
if (flags & DEF_FREE_GLOBAL)
/* undo the original DEF_FREE */
flags &= ~(DEF_FREE | DEF_FREE_CLASS);
@@ -4340,6 +4423,16 @@ 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++) {
name = PyList_GET_ITEM(list, j);
if (ste->ste_nested) {
@@ -4432,7 +4525,7 @@ symtable_exit_scope(struct symtable *st)
{
int end;
- if (st->st_pass == 1 && st->st_nested_scopes)
+ if (st->st_pass == 1)
symtable_update_free_vars(st);
Py_DECREF(st->st_cur);
end = PyList_GET_SIZE(st->st_stack) - 1;