Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4419ac1

Browse files
committed
Add warning/error handlin for problematic nested scopes cases as
described in PEP 227. symtable_check_unoptimized() warns about import * and exec with "in" when it is used in a function that contains a nested function with free variables. Warnings are issued unless nested scopes are in effect, in which case these are SyntaxErrors. symtable_check_shadow() warns about assignments in a function scope that shadow free variables defined in a nested scope. This will always generate a warning -- and will behave differently with nested scopes than without. Restore full checking for free vars in children, even when nested scopes are not enabled. This is needed to support warnings for shadowing. Change symtable_warn() to return an int-- the return value of PyErr_WarnExplicit. Sundry cleanup: Remove commented out code. Break long lines.
1 parent 150a664 commit 4419ac1

1 file changed

Lines changed: 119 additions & 26 deletions

File tree

Python/compile.c

Lines changed: 119 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags,
312312
co->co_firstlineno = firstlineno;
313313
Py_INCREF(lnotab);
314314
co->co_lnotab = lnotab;
315-
/* PyObject_Print((PyObject *)co, stderr, 0); */
316315
}
317316
return co;
318317
}
@@ -1151,7 +1150,8 @@ parsestr(char *s)
11511150
*p++ = c;
11521151
break;
11531152
case 'x':
1154-
if (isxdigit(Py_CHARMASK(s[0])) && isxdigit(Py_CHARMASK(s[1]))) {
1153+
if (isxdigit(Py_CHARMASK(s[0]))
1154+
&& isxdigit(Py_CHARMASK(s[1]))) {
11551155
unsigned int x = 0;
11561156
c = Py_CHARMASK(*s);
11571157
s++;
@@ -1173,7 +1173,8 @@ parsestr(char *s)
11731173
*p++ = x;
11741174
break;
11751175
}
1176-
PyErr_SetString(PyExc_ValueError, "invalid \\x escape");
1176+
PyErr_SetString(PyExc_ValueError,
1177+
"invalid \\x escape");
11771178
Py_DECREF(v);
11781179
return NULL;
11791180
default:
@@ -2647,7 +2648,7 @@ com_import_stmt(struct compiling *c, node *n)
26472648
for (i = 3; i < NCH(n); i += 2) {
26482649
PyTuple_SET_ITEM(tup, (i-3)/2,
26492650
PyString_FromString(STR(
2650-
CHILD(CHILD(n, i), 0))));
2651+
CHILD(CHILD(n, i), 0))));
26512652
}
26522653
}
26532654
com_addoparg(c, LOAD_CONST, com_addconst(c, tup));
@@ -3985,7 +3986,7 @@ get_ref_type(struct compiling *c, char *name)
39853986

39863987
/* Helper function to issue symbol table warnings */
39873988

3988-
static void
3989+
static int
39893990
symtable_warn(struct symtable *st, char *msg)
39903991
{
39913992
if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, st->st_filename,
@@ -3996,7 +3997,9 @@ symtable_warn(struct symtable *st, char *msg)
39963997
st->st_cur->ste_lineno);
39973998
}
39983999
st->st_errors++;
4000+
return -1;
39994001
}
4002+
return 0;
40004003
}
40014004

40024005
/* Helper function for setting lineno and filename */
@@ -4119,6 +4122,98 @@ symtable_freevar_offsets(PyObject *freevars, int offset)
41194122
return 0;
41204123
}
41214124

4125+
static int
4126+
symtable_check_unoptimized(struct compiling *c,
4127+
PySymtableEntryObject *ste,
4128+
struct symbol_info *si)
4129+
{
4130+
char buf[300];
4131+
4132+
if (!(si->si_ncells || si->si_nfrees || ste->ste_child_free
4133+
|| (ste->ste_nested && si->si_nimplicit)))
4134+
return 0;
4135+
4136+
#define ILLEGAL_IMPORT_STAR \
4137+
"import * is not allowed in function '%.100s' " \
4138+
"because it contains a nested function with free variables"
4139+
4140+
#define ILLEGAL_BARE_EXEC \
4141+
"unqualified exec is not allowed in function '%.100s' " \
4142+
"because it contains a nested function with free variables"
4143+
4144+
#define ILLEGAL_EXEC_AND_IMPORT_STAR \
4145+
"function '%.100s' uses import * and bare exec, which are illegal" \
4146+
"because it contains a nested function with free variables"
4147+
4148+
/* XXX perhaps the linenos for these opt-breaking statements
4149+
should be stored so the exception can point to them. */
4150+
4151+
if (ste->ste_optimized == OPT_IMPORT_STAR)
4152+
sprintf(buf, ILLEGAL_IMPORT_STAR,
4153+
PyString_AS_STRING(ste->ste_name));
4154+
else if (ste->ste_optimized == (OPT_BARE_EXEC | OPT_EXEC))
4155+
sprintf(buf, ILLEGAL_BARE_EXEC,
4156+
PyString_AS_STRING(ste->ste_name));
4157+
else {
4158+
sprintf(buf, ILLEGAL_EXEC_AND_IMPORT_STAR,
4159+
PyString_AS_STRING(ste->ste_name));
4160+
}
4161+
4162+
if (c->c_symtable->st_nested_scopes) {
4163+
PyErr_SetString(PyExc_SyntaxError, buf);
4164+
PyErr_SyntaxLocation(c->c_symtable->st_filename,
4165+
ste->ste_lineno);
4166+
return -1;
4167+
} else {
4168+
/* XXX if the warning becomes an exception, we should
4169+
attached more info to it. */
4170+
if (PyErr_Warn(PyExc_SyntaxWarning, buf) < 0)
4171+
return -1;
4172+
}
4173+
return 0;
4174+
}
4175+
4176+
static int
4177+
symtable_check_shadow(struct symtable *st, PyObject *name, int flags)
4178+
{
4179+
char buf[500];
4180+
PyObject *children, *v;
4181+
PySymtableEntryObject *child;
4182+
int i;
4183+
4184+
if (!(flags & DEF_BOUND))
4185+
return 0;
4186+
/* The semantics of this code will change with nested scopes.
4187+
It is defined in the current scope and referenced in a
4188+
child scope. Under the old rules, the child will see a
4189+
global. Under the new rules, the child will see the
4190+
binding in the current scope.
4191+
*/
4192+
4193+
/* Find name of child function that has free variable */
4194+
children = st->st_cur->ste_children;
4195+
for (i = 0; i < PyList_GET_SIZE(children); i++) {
4196+
int cflags;
4197+
child = (PySymtableEntryObject *)PyList_GET_ITEM(children, i);
4198+
v = PyDict_GetItem(child->ste_symbols, name);
4199+
if (v == NULL)
4200+
continue;
4201+
cflags = PyInt_AS_LONG(v);
4202+
if (!(cflags & DEF_BOUND))
4203+
break;
4204+
}
4205+
4206+
sprintf(buf, "local name '%.100s' in '%.100s' shadows "
4207+
"use of '%.100s' as global in nested scope '%.100s'",
4208+
PyString_AS_STRING(name),
4209+
PyString_AS_STRING(st->st_cur->ste_name),
4210+
PyString_AS_STRING(name),
4211+
PyString_AS_STRING(child->ste_name)
4212+
);
4213+
4214+
return symtable_warn(st, buf);
4215+
}
4216+
41224217
static int
41234218
symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
41244219
struct symbol_info *si)
@@ -4129,26 +4224,8 @@ symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
41294224
c->c_nlocals = si->si_nlocals;
41304225
if (ste->ste_optimized == 0)
41314226
c->c_flags |= CO_OPTIMIZED;
4132-
else if (si->si_ncells || si->si_nfrees
4133-
|| (ste->ste_nested && si->si_nimplicit)
4134-
|| ste->ste_child_free) {
4135-
if (c->c_symtable->st_nested_scopes) {
4136-
PyErr_Format(PyExc_SyntaxError,
4137-
ILLEGAL_DYNAMIC_SCOPE,
4138-
PyString_AS_STRING(ste->ste_name));
4139-
PyErr_SyntaxLocation(c->c_symtable->st_filename,
4140-
ste->ste_lineno);
4141-
return -1;
4142-
} else {
4143-
char buf[200];
4144-
sprintf(buf, ILLEGAL_DYNAMIC_SCOPE,
4145-
PyString_AS_STRING(ste->ste_name));
4146-
if (PyErr_Warn(PyExc_SyntaxWarning,
4147-
buf) < 0) {
4148-
return -1;
4149-
}
4150-
}
4151-
}
4227+
else if (ste->ste_optimized != OPT_EXEC)
4228+
return symtable_check_unoptimized(c, ste, si);
41524229
}
41534230
return 0;
41544231
}
@@ -4191,6 +4268,12 @@ symtable_load_symbols(struct compiling *c)
41914268
while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
41924269
flags = PyInt_AS_LONG(v);
41934270

4271+
if (st->st_nested_scopes == 0
4272+
&& (flags & (DEF_FREE | DEF_FREE_CLASS))) {
4273+
if (symtable_check_shadow(st, name, flags) < 0)
4274+
goto fail;
4275+
}
4276+
41944277
if (flags & DEF_FREE_GLOBAL)
41954278
/* undo the original DEF_FREE */
41964279
flags &= ~(DEF_FREE | DEF_FREE_CLASS);
@@ -4340,6 +4423,16 @@ symtable_update_free_vars(struct symtable *st)
43404423
return -1;
43414424
}
43424425
}
4426+
/*
4427+
if (st->st_nested_scopes == 0
4428+
&& list && PyList_GET_SIZE(list) > 0) {
4429+
fprintf(stderr, "function %s has children with "
4430+
"the following free vars:\n%s\n",
4431+
PyString_AS_STRING(ste->ste_name),
4432+
PyObject_REPR(list));
4433+
continue;
4434+
}
4435+
*/
43434436
for (j = 0; list && j < PyList_GET_SIZE(list); j++) {
43444437
name = PyList_GET_ITEM(list, j);
43454438
if (ste->ste_nested) {
@@ -4432,7 +4525,7 @@ symtable_exit_scope(struct symtable *st)
44324525
{
44334526
int end;
44344527

4435-
if (st->st_pass == 1 && st->st_nested_scopes)
4528+
if (st->st_pass == 1)
44364529
symtable_update_free_vars(st);
44374530
Py_DECREF(st->st_cur);
44384531
end = PyList_GET_SIZE(st->st_stack) - 1;

0 commit comments

Comments
 (0)