diff Python/symtable.c @ 83783:3d858f1eef54

hide the __class__ closure from the class body (#12370)
author Benjamin Peterson <benjamin@python.org>
date Wed, 15 May 2013 15:26:42 -0500
parents 7c5c678e4164
children e74f4d6c0c81
line wrap: on
line diff
--- a/Python/symtable.c	Wed May 15 19:43:15 2013 +0200
+++ b/Python/symtable.c	Wed May 15 15:26:42 2013 -0500
@@ -77,6 +77,7 @@
     ste->ste_child_free = 0;
     ste->ste_generator = 0;
     ste->ste_returns_value = 0;
+    ste->ste_needs_class_closure = 0;
 
     if (PyDict_SetItem(st->st_blocks, ste->ste_id, (PyObject *)ste) < 0)
         goto fail;
@@ -514,13 +515,10 @@
 
    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 'restricted' 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, const char *restricted)
+analyze_cells(PyObject *scopes, PyObject *free)
 {
     PyObject *name, *v, *v_cell;
     int success = 0;
@@ -537,9 +535,6 @@
             continue;
         if (!PySet_Contains(free, name))
             continue;
-        if (restricted != NULL &&
-            PyUnicode_CompareWithASCIIString(name, restricted))
-            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.
@@ -555,6 +550,20 @@
     return success;
 }
 
+static int
+drop_class_free(PySTEntryObject *ste, PyObject *free)
+{
+    int res;
+    if (!GET_IDENTIFIER(__class__))
+        return 0;
+    res = PySet_Discard(free, __class__);
+    if (res < 0)
+        return 0;
+    if (res)
+        ste->ste_needs_class_closure = 1;
+    return 1;
+}
+
 /* Check for illegal statements in unoptimized namespaces */
 static int
 check_unoptimized(const PySTEntryObject* ste) {
@@ -785,7 +794,6 @@
         /* Special-case __class__ */
         if (!GET_IDENTIFIER(__class__))
             goto error;
-        assert(PySet_Contains(local, __class__) == 1);
         if (PySet_Add(newbound, __class__) < 0)
             goto error;
     }
@@ -818,11 +826,9 @@
     Py_DECREF(temp);
 
     /* Check if any local variables must be converted to cell variables */
-    if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree,
-                                                         NULL))
+    if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree))
         goto error;
-    else if (ste->ste_type == ClassBlock && !analyze_cells(scopes, newfree,
-                                                           "__class__"))
+    else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree))
         goto error;
     /* Records the results of the analysis in the symbol table entry */
     if (!update_symbols(ste->ste_symbols, scopes, bound, newfree,
@@ -1179,9 +1185,7 @@
         if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
                                   (void *)s, s->lineno, s->col_offset))
             VISIT_QUIT(st, 0);
-        if (!GET_IDENTIFIER(__class__) ||
-            !symtable_add_def(st, __class__, DEF_LOCAL) ||
-            !GET_IDENTIFIER(__locals__) ||
+        if (!GET_IDENTIFIER(__locals__) ||
             !symtable_add_def(st, __locals__, DEF_PARAM)) {
             symtable_exit_block(st, s);
             VISIT_QUIT(st, 0);