mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
Fix for SF bug [ #471928 ] global made w/nested list comprehensions
The symbol table pass didn't have an explicit case for the list_iter node which is used only for a nested list comprehension. As a result, the target of the list comprehension was treated as a use instead of an assignment. Fix is to add a case to symtable_node() to handle list_iter. Also, rework and document a couple of the subtler implementation issues in the symbol table pass. The symtable_node() switch statement depends on falling through the last several cases, in order to handle some of the more complicated nodes like atom. Add a comment explaining the behavior before the first fall through case. Add a comment /* fall through */ at the end of case so that it is explicitly marked as such. Move the for_stmt case out of the fall through logic, which simplifies both for_stmt and default. (The default used the local variable start to skip the first three nodes of a for_stmt when it fell through.) Rename the flag argument to symtable_assign() to def_flag and add a comment explaining its use: The third argument to symatble_assign() is a flag to be passed to symtable_add_def() if it is eventually called. The flag is useful to specify the particular type of assignment that should be recorded, e.g. an assignment caused by import.
This commit is contained in:
parent
f76de62f7d
commit
961dfe0d85
1 changed files with 51 additions and 19 deletions
|
@ -4991,7 +4991,7 @@ look_for_yield(node *n)
|
||||||
static void
|
static void
|
||||||
symtable_node(struct symtable *st, node *n)
|
symtable_node(struct symtable *st, node *n)
|
||||||
{
|
{
|
||||||
int i, start = 0;
|
int i;
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
switch (TYPE(n)) {
|
switch (TYPE(n)) {
|
||||||
|
@ -5105,36 +5105,62 @@ symtable_node(struct symtable *st, node *n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto loop;
|
goto loop;
|
||||||
/* watchout for fall-through logic below */
|
case list_iter:
|
||||||
case argument:
|
n = CHILD(n, 0);
|
||||||
|
if (TYPE(n) == list_for) {
|
||||||
|
st->st_tmpname++;
|
||||||
|
symtable_list_comprehension(st, n);
|
||||||
|
st->st_tmpname--;
|
||||||
|
} else {
|
||||||
|
REQ(n, list_if);
|
||||||
|
symtable_node(st, CHILD(n, 1));
|
||||||
if (NCH(n) == 3) {
|
if (NCH(n) == 3) {
|
||||||
n = CHILD(n, 2);
|
n = CHILD(n, 2);
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case for_stmt:
|
||||||
|
symtable_assign(st, CHILD(n, 1), 0);
|
||||||
|
for (i = 3; i < NCH(n); ++i)
|
||||||
|
if (TYPE(CHILD(n, i)) >= single_input)
|
||||||
|
symtable_node(st, CHILD(n, i));
|
||||||
|
break;
|
||||||
|
/* The remaining cases fall through to default except in
|
||||||
|
special circumstances. This requires the individual cases
|
||||||
|
to be coded with great care, even though they look like
|
||||||
|
rather innocuous. Each case must double-check TYPE(n).
|
||||||
|
*/
|
||||||
|
case argument:
|
||||||
|
if (TYPE(n) == argument && NCH(n) == 3) {
|
||||||
|
n = CHILD(n, 2);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
case listmaker:
|
case listmaker:
|
||||||
if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) {
|
if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) {
|
||||||
st->st_tmpname++;
|
st->st_tmpname++;
|
||||||
symtable_list_comprehension(st, CHILD(n, 1));
|
symtable_list_comprehension(st, CHILD(n, 1));
|
||||||
symtable_node(st, CHILD(n, 0));
|
symtable_node(st, CHILD(n, 0));
|
||||||
st->st_tmpname--;
|
st->st_tmpname--;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
/* fall through */
|
||||||
case atom:
|
case atom:
|
||||||
if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) {
|
if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) {
|
||||||
symtable_add_use(st, STR(CHILD(n, 0)));
|
symtable_add_use(st, STR(CHILD(n, 0)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case for_stmt:
|
/* fall through */
|
||||||
if (TYPE(n) == for_stmt) {
|
|
||||||
symtable_assign(st, CHILD(n, 1), 0);
|
|
||||||
start = 3;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
|
/* Walk over every non-token child with a special case
|
||||||
|
for one child.
|
||||||
|
*/
|
||||||
if (NCH(n) == 1) {
|
if (NCH(n) == 1) {
|
||||||
n = CHILD(n, 0);
|
n = CHILD(n, 0);
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
for (i = start; i < NCH(n); ++i)
|
for (i = 0; i < NCH(n); ++i)
|
||||||
if (TYPE(CHILD(n, i)) >= single_input)
|
if (TYPE(CHILD(n, i)) >= single_input)
|
||||||
symtable_node(st, CHILD(n, i));
|
symtable_node(st, CHILD(n, i));
|
||||||
}
|
}
|
||||||
|
@ -5370,8 +5396,14 @@ symtable_import(struct symtable *st, node *n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The third argument to symatble_assign() is a flag to be passed to
|
||||||
|
symtable_add_def() if it is eventually called. The flag is useful
|
||||||
|
to specify the particular type of assignment that should be
|
||||||
|
recorded, e.g. an assignment caused by import.
|
||||||
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
symtable_assign(struct symtable *st, node *n, int flag)
|
symtable_assign(struct symtable *st, node *n, int def_flag)
|
||||||
{
|
{
|
||||||
node *tmp;
|
node *tmp;
|
||||||
int i;
|
int i;
|
||||||
|
@ -5403,7 +5435,7 @@ symtable_assign(struct symtable *st, node *n, int flag)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < NCH(n); i += 2)
|
for (i = 0; i < NCH(n); i += 2)
|
||||||
symtable_assign(st, CHILD(n, i), flag);
|
symtable_assign(st, CHILD(n, i), def_flag);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case exprlist:
|
case exprlist:
|
||||||
|
@ -5415,7 +5447,7 @@ symtable_assign(struct symtable *st, node *n, int flag)
|
||||||
else {
|
else {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < NCH(n); i += 2)
|
for (i = 0; i < NCH(n); i += 2)
|
||||||
symtable_assign(st, CHILD(n, i), flag);
|
symtable_assign(st, CHILD(n, i), def_flag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case atom:
|
case atom:
|
||||||
|
@ -5426,24 +5458,24 @@ symtable_assign(struct symtable *st, node *n, int flag)
|
||||||
} else if (TYPE(tmp) == NAME) {
|
} else if (TYPE(tmp) == NAME) {
|
||||||
if (strcmp(STR(tmp), "__debug__") == 0)
|
if (strcmp(STR(tmp), "__debug__") == 0)
|
||||||
symtable_warn(st, ASSIGN_DEBUG);
|
symtable_warn(st, ASSIGN_DEBUG);
|
||||||
symtable_add_def(st, STR(tmp), DEF_LOCAL | flag);
|
symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case dotted_as_name:
|
case dotted_as_name:
|
||||||
if (NCH(n) == 3)
|
if (NCH(n) == 3)
|
||||||
symtable_add_def(st, STR(CHILD(n, 2)),
|
symtable_add_def(st, STR(CHILD(n, 2)),
|
||||||
DEF_LOCAL | flag);
|
DEF_LOCAL | def_flag);
|
||||||
else
|
else
|
||||||
symtable_add_def(st,
|
symtable_add_def(st,
|
||||||
STR(CHILD(CHILD(n,
|
STR(CHILD(CHILD(n,
|
||||||
0), 0)),
|
0), 0)),
|
||||||
DEF_LOCAL | flag);
|
DEF_LOCAL | def_flag);
|
||||||
return;
|
return;
|
||||||
case dotted_name:
|
case dotted_name:
|
||||||
symtable_add_def(st, STR(CHILD(n, 0)), DEF_LOCAL | flag);
|
symtable_add_def(st, STR(CHILD(n, 0)), DEF_LOCAL | def_flag);
|
||||||
return;
|
return;
|
||||||
case NAME:
|
case NAME:
|
||||||
symtable_add_def(st, STR(n), DEF_LOCAL | flag);
|
symtable_add_def(st, STR(n), DEF_LOCAL | def_flag);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
if (NCH(n) == 0)
|
if (NCH(n) == 0)
|
||||||
|
@ -5456,6 +5488,6 @@ symtable_assign(struct symtable *st, node *n, int flag)
|
||||||
which will be caught in the next pass. */
|
which will be caught in the next pass. */
|
||||||
for (i = 0; i < NCH(n); ++i)
|
for (i = 0; i < NCH(n); ++i)
|
||||||
if (TYPE(CHILD(n, i)) >= single_input)
|
if (TYPE(CHILD(n, i)) >= single_input)
|
||||||
symtable_assign(st, CHILD(n, i), flag);
|
symtable_assign(st, CHILD(n, i), def_flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue