summaryrefslogtreecommitdiffstats
path: root/Python/symtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/symtable.c')
-rw-r--r--Python/symtable.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/Python/symtable.c b/Python/symtable.c
index 68c1821..30e97d6 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -183,7 +183,7 @@ static int symtable_visit_annotations(struct symtable *st, stmt_ty s);
static identifier top = NULL, lambda = NULL, genexpr = NULL,
- listcomp = NULL, setcomp = NULL;
+ listcomp = NULL, setcomp = NULL, __class__ = NULL;
#define GET_IDENTIFIER(VAR) \
((VAR) ? (VAR) : ((VAR) = PyUnicode_InternFromString(# VAR)))
@@ -317,7 +317,7 @@ PyST_GetScope(PySTEntryObject *ste, PyObject *name)
/* Analyze raw symbol information to determine scope of each name.
- The next several functions are helpers for PySymtable_Analyze(),
+ The next several functions are helpers for symtable_analyze(),
which determines whether a name is local, global, or free. In addition,
it determines which local variables are cell variables; they provide
bindings that are used for free variables in enclosed blocks.
@@ -464,10 +464,13 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
Note that the current block's free variables are included in free.
That's safe because no name can be free and local in the same scope.
+
+ The 'restrict' argument may be set to a string to restrict the analysis
+ to the one variable whose name equals that string (e.g. "__class__").
*/
static int
-analyze_cells(PyObject *scopes, PyObject *free)
+analyze_cells(PyObject *scopes, PyObject *free, const char *restrict)
{
PyObject *name, *v, *v_cell;
int success = 0;
@@ -484,6 +487,9 @@ analyze_cells(PyObject *scopes, PyObject *free)
continue;
if (!PySet_Contains(free, name))
continue;
+ if (restrict != NULL &&
+ PyUnicode_CompareWithASCIIString(name, restrict))
+ continue;
/* Replace LOCAL with CELL for this name, and remove
from free. It is safe to replace the value of name
in the dict, because it will not cause a resize.
@@ -589,7 +595,7 @@ update_symbols(PyObject *symbols, PyObject *scopes,
}
Py_DECREF(v_new);
}
- /* It's a cell, or already a free variable in this scope */
+ /* It's a cell, or already free in this scope */
Py_DECREF(name);
continue;
}
@@ -675,8 +681,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
goto error;
}
- /* Populate global and bound sets to be passed to children.
- */
+ /* Populate global and bound sets to be passed to children. */
if (ste->ste_type != ClassBlock) {
/* Add function locals to bound set */
if (ste->ste_type == FunctionBlock) {
@@ -695,6 +700,14 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
goto error;
Py_DECREF(newglobal);
}
+ else {
+ /* Special-case __class__ */
+ if (!GET_IDENTIFIER(__class__))
+ goto error;
+ assert(PySet_Contains(local, __class__) == 1);
+ if (PySet_Add(newbound, __class__) < 0)
+ goto error;
+ }
/* Recursively call analyze_block() on each child block */
for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
@@ -709,8 +722,12 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
ste->ste_child_free = 1;
}
- /* Check if any local variables need to be converted to cell variables */
- if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree))
+ /* Check if any local variables must be converted to cell variables */
+ if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree,
+ NULL))
+ goto error;
+ else if (ste->ste_type == ClassBlock && !analyze_cells(scopes, newfree,
+ "__class__"))
goto error;
/* Records the results of the analysis in the symbol table entry */
if (!update_symbols(ste->ste_symbols, scopes, bound, newfree,
@@ -1027,6 +1044,11 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
(void *)s, s->lineno))
return 0;
+ if (!GET_IDENTIFIER(__class__) ||
+ !symtable_add_def(st, __class__, DEF_LOCAL)) {
+ symtable_exit_block(st, s);
+ return 0;
+ }
tmp = st->st_private;
st->st_private = s->v.ClassDef.name;
VISIT_SEQ_IN_BLOCK(st, stmt, s->v.ClassDef.body, s);
@@ -1294,6 +1316,14 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
if (!symtable_add_def(st, e->v.Name.id,
e->v.Name.ctx == Load ? USE : DEF_LOCAL))
return 0;
+ /* Special-case super: it counts as a use of __class__ */
+ if (e->v.Name.ctx == Load &&
+ st->st_cur->ste_type == FunctionBlock &&
+ !PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
+ if (!GET_IDENTIFIER(__class__) ||
+ !symtable_add_def(st, __class__, USE))
+ return 0;
+ }
break;
/* child nodes of List and Tuple will have expr_context set */
case List_kind: