diff options
author | Guido van Rossum <guido@python.org> | 2007-03-18 15:41:51 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2007-03-18 15:41:51 (GMT) |
commit | 52cc1d838f4fee573e57b5b182d8e5f5db63240f (patch) | |
tree | 0ea50468d2b04ee12131c155c5918e8a70dafe1c /Python | |
parent | ef17c16b366b09a78dfe5fc5171fe2b0b29f60e5 (diff) | |
download | cpython-52cc1d838f4fee573e57b5b182d8e5f5db63240f.zip cpython-52cc1d838f4fee573e57b5b182d8e5f5db63240f.tar.gz cpython-52cc1d838f4fee573e57b5b182d8e5f5db63240f.tar.bz2 |
Implement PEP 3115 -- new metaclass syntax and semantics.
The compiler package hasn't been updated yet; test_compiler.py fails.
Otherwise all tests seem to be passing now. There are no occurrences
of __metaclass__ left in the standard library.
Docs have not been updated.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/Python-ast.c | 28 | ||||
-rw-r--r-- | Python/ast.c | 59 | ||||
-rw-r--r-- | Python/bltinmodule.c | 109 | ||||
-rw-r--r-- | Python/ceval.c | 89 | ||||
-rw-r--r-- | Python/compile.c | 174 | ||||
-rw-r--r-- | Python/graminit.c | 2 | ||||
-rw-r--r-- | Python/import.c | 3 | ||||
-rw-r--r-- | Python/symtable.c | 5 |
8 files changed, 303 insertions, 166 deletions
diff --git a/Python/Python-ast.c b/Python/Python-ast.c index c024a62..76c86c1 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -49,6 +49,9 @@ static PyTypeObject *ClassDef_type; static char *ClassDef_fields[]={ "name", "bases", + "keywords", + "starargs", + "kwargs", "body", }; static PyTypeObject *Return_type; @@ -477,7 +480,7 @@ static int init_types(void) FunctionDef_type = make_type("FunctionDef", stmt_type, FunctionDef_fields, 5); if (!FunctionDef_type) return 0; - ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 3); + ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 6); if (!ClassDef_type) return 0; Return_type = make_type("Return", stmt_type, Return_fields, 1); if (!Return_type) return 0; @@ -835,8 +838,9 @@ FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq * } stmt_ty -ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int lineno, int - col_offset, PyArena *arena) +ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, expr_ty + starargs, expr_ty kwargs, asdl_seq * body, int lineno, int col_offset, + PyArena *arena) { stmt_ty p; if (!name) { @@ -850,6 +854,9 @@ ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int lineno, int p->kind = ClassDef_kind; p->v.ClassDef.name = name; p->v.ClassDef.bases = bases; + p->v.ClassDef.keywords = keywords; + p->v.ClassDef.starargs = starargs; + p->v.ClassDef.kwargs = kwargs; p->v.ClassDef.body = body; p->lineno = lineno; p->col_offset = col_offset; @@ -1974,6 +1981,21 @@ ast2obj_stmt(void* _o) if (PyObject_SetAttrString(result, "bases", value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "keywords", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.starargs); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "starargs", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.kwargs); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "kwargs", value) == -1) + goto failed; + Py_DECREF(value); value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttrString(result, "body", value) == -1) diff --git a/Python/ast.c b/Python/ast.c index c8357b1..d4c8967 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -2092,28 +2092,6 @@ ast_for_testlist_gexp(struct compiling *c, const node* n) return ast_for_testlist(c, n); } -/* like ast_for_testlist() but returns a sequence */ -static asdl_seq* -ast_for_class_bases(struct compiling *c, const node* n) -{ - /* testlist: test (',' test)* [','] */ - assert(NCH(n) > 0); - REQ(n, testlist); - if (NCH(n) == 1) { - expr_ty base; - asdl_seq *bases = asdl_seq_new(1, c->c_arena); - if (!bases) - return NULL; - base = ast_for_expr(c, CHILD(n, 0)); - if (!base) - return NULL; - asdl_seq_SET(bases, 0, base); - return bases; - } - - return seq_for_testlist(c, n); -} - static stmt_ty ast_for_expr_stmt(struct compiling *c, const node *n) { @@ -3032,9 +3010,10 @@ ast_for_with_stmt(struct compiling *c, const node *n) static stmt_ty ast_for_classdef(struct compiling *c, const node *n) { - /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */ - asdl_seq *bases, *s; - + /* classdef: 'class' NAME ['(' arglist ')'] ':' suite */ + asdl_seq *s; + expr_ty call, dummy; + REQ(n, classdef); if (!strcmp(STR(CHILD(n, 1)), "None")) { @@ -3042,32 +3021,36 @@ ast_for_classdef(struct compiling *c, const node *n) return NULL; } - if (NCH(n) == 4) { + if (NCH(n) == 4) { /* class NAME ':' suite */ s = ast_for_suite(c, CHILD(n, 3)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), - n->n_col_offset, c->c_arena); + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s, + LINENO(n), n->n_col_offset, c->c_arena); } - /* check for empty base list */ - if (TYPE(CHILD(n,3)) == RPAR) { + + if (TYPE(CHILD(n, 3)) == RPAR) { /* class NAME '(' ')' ':' suite */ s = ast_for_suite(c, CHILD(n,5)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), - n->n_col_offset, c->c_arena); + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s, + LINENO(n), n->n_col_offset, c->c_arena); } - /* else handle the base class list */ - bases = ast_for_class_bases(c, CHILD(n, 3)); - if (!bases) + /* class NAME '(' arglist ')' ':' suite */ + /* build up a fake Call node so we can extract its pieces */ + dummy = Name(NEW_IDENTIFIER(CHILD(n, 1)), Load, LINENO(n), n->n_col_offset, c->c_arena); + call = ast_for_call(c, CHILD(n, 3), dummy); + if (!call) return NULL; - s = ast_for_suite(c, CHILD(n, 6)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), bases, s, LINENO(n), - n->n_col_offset, c->c_arena); + + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), + call->v.Call.args, call->v.Call.keywords, + call->v.Call.starargs, call->v.Call.kwargs, s, + LINENO(n), n->n_col_offset, c->c_arena); } static stmt_ty diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 5d87744..4aa9c62 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -31,6 +31,113 @@ static PyObject *filterunicode(PyObject *, PyObject *); static PyObject *filtertuple (PyObject *, PyObject *); static PyObject * +builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *func, *name, *bases, *mkw, *meta, *prep, *ns, *res; + Py_ssize_t nargs, nbases; + + assert(args != NULL); + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "__build_class__: args is not a tuple"); + return NULL; + } + nargs = PyTuple_GET_SIZE(args); + if (nargs < 2) { + PyErr_SetString(PyExc_TypeError, + "__build_class__: not enough arguments"); + return NULL; + } + func = PyTuple_GET_ITEM(args, 0); /* Better be callable */ + name = PyTuple_GET_ITEM(args, 1); + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "__build_class__: name is not a string"); + return NULL; + } + bases = PyTuple_GetSlice(args, 2, nargs); + if (bases == NULL) + return NULL; + nbases = nargs - 2; + + if (kwds == NULL) { + meta = NULL; + mkw = NULL; + } + else { + mkw = PyDict_Copy(kwds); /* Don't modify kwds passed in! */ + if (mkw == NULL) { + Py_DECREF(bases); + return NULL; + } + meta = PyDict_GetItemString(mkw, "metaclass"); + if (meta != NULL) { + Py_INCREF(meta); + if (PyDict_DelItemString(mkw, "metaclass") < 0) { + Py_DECREF(meta); + Py_DECREF(mkw); + Py_DECREF(bases); + return NULL; + } + } + } + if (meta == NULL) { + if (PyTuple_GET_SIZE(bases) == 0) + meta = (PyObject *) (&PyType_Type); + else { + PyObject *base0 = PyTuple_GET_ITEM(bases, 0); + meta = (PyObject *) (base0->ob_type); + } + Py_INCREF(meta); + } + prep = PyObject_GetAttrString(meta, "__prepare__"); + if (prep == NULL) { + PyErr_Clear(); + ns = PyDict_New(); + } + else { + PyObject *pargs = Py_BuildValue("OO", name, bases); + if (pargs == NULL) { + Py_DECREF(prep); + Py_DECREF(meta); + Py_XDECREF(mkw); + Py_DECREF(bases); + return NULL; + } + ns = PyEval_CallObjectWithKeywords(prep, pargs, mkw); + Py_DECREF(pargs); + Py_DECREF(prep); + if (ns == NULL) { + Py_DECREF(meta); + Py_XDECREF(mkw); + Py_DECREF(bases); + return NULL; + } + } + res = PyObject_CallFunctionObjArgs(func, ns, NULL); + if (res != NULL) { + PyObject *margs; + Py_DECREF(res); + res = NULL; + margs = Py_BuildValue("OOO", name, bases, ns); + if (margs != NULL) { + res = PyEval_CallObjectWithKeywords(meta, margs, mkw); + Py_DECREF(margs); + } + } + Py_DECREF(ns); + Py_DECREF(meta); + Py_XDECREF(mkw); + Py_DECREF(bases); + return res; +} + +PyDoc_STRVAR(build_class_doc, +"__build_class__(func, name, *bases, metaclass=None, **kwds) -> class\n\ +\n\ +Internal helper function used by the class statement."); + +static PyObject * builtin___import__(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"name", "globals", "locals", "fromlist", @@ -2103,6 +2210,8 @@ NOTE: This is implemented using itertools.izip()."); static PyMethodDef builtin_methods[] = { + {"__build_class__", (PyCFunction)builtin___build_class__, + METH_VARARGS | METH_KEYWORDS, build_class_doc}, {"__import__", (PyCFunction)builtin___import__, METH_VARARGS | METH_KEYWORDS, import_doc}, {"abs", builtin_abs, METH_O, abs_doc}, {"all", builtin_all, METH_O, all_doc}, diff --git a/Python/ceval.c b/Python/ceval.c index 5cad632..5a3fc59 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -117,7 +117,6 @@ static int assign_slice(PyObject *, PyObject *, static PyObject * cmp_outcome(int, PyObject *, PyObject *); static PyObject * import_from(PyObject *, PyObject *); static int import_all_from(PyObject *, PyObject *); -static PyObject * build_class(PyObject *, PyObject *, PyObject *); static void set_exc_info(PyThreadState *, PyObject *, PyObject *, PyObject *); static void reset_exc_info(PyThreadState *); static void format_exc_check_arg(PyObject *, char *, PyObject *); @@ -1532,14 +1531,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } break; - case LOAD_LOCALS: - if ((x = f->f_locals) != NULL) { - Py_INCREF(x); - PUSH(x); - continue; - } - PyErr_SetString(PyExc_SystemError, "no locals"); - break; + case STORE_LOCALS: + x = POP(); + v = f->f_locals; + Py_XDECREF(v); + f->f_locals = x; + continue; case RETURN_VALUE: retval = POP(); @@ -1586,16 +1583,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) Py_DECREF(v); break; - case BUILD_CLASS: - u = TOP(); - v = SECOND(); - w = THIRD(); - STACKADJ(-2); - x = build_class(u, v, w); - SET_TOP(x); - Py_DECREF(u); - Py_DECREF(v); - Py_DECREF(w); + case LOAD_BUILD_CLASS: + x = PyDict_GetItemString(f->f_builtins, + "__build_class__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__build_class__ not found"); + break; + } + Py_INCREF(x); + PUSH(x); break; case STORE_NAME: @@ -4023,60 +4020,6 @@ import_all_from(PyObject *locals, PyObject *v) return err; } -static PyObject * -build_class(PyObject *methods, PyObject *bases, PyObject *name) -{ - PyObject *metaclass = NULL, *result, *base; - - if (PyDict_Check(methods)) - metaclass = PyDict_GetItemString(methods, "__metaclass__"); - if (metaclass != NULL) - Py_INCREF(metaclass); - else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { - base = PyTuple_GET_ITEM(bases, 0); - metaclass = PyObject_GetAttrString(base, "__class__"); - if (metaclass == NULL) { - PyErr_Clear(); - metaclass = (PyObject *)base->ob_type; - Py_INCREF(metaclass); - } - } - else { - PyObject *g = PyEval_GetGlobals(); - if (g != NULL && PyDict_Check(g)) - metaclass = PyDict_GetItemString(g, "__metaclass__"); - if (metaclass == NULL) - metaclass = (PyObject *) &PyType_Type; - Py_INCREF(metaclass); - } - result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, - NULL); - Py_DECREF(metaclass); - if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { - /* A type error here likely means that the user passed - in a base that was not a class (such the random module - instead of the random.random type). Help them out with - by augmenting the error message with more information.*/ - - PyObject *ptype, *pvalue, *ptraceback; - - PyErr_Fetch(&ptype, &pvalue, &ptraceback); - if (PyString_Check(pvalue)) { - PyObject *newmsg; - newmsg = PyString_FromFormat( - "Error when calling the metaclass bases\n" - " %s", - PyString_AS_STRING(pvalue)); - if (newmsg != NULL) { - Py_DECREF(pvalue); - pvalue = newmsg; - } - } - PyErr_Restore(ptype, pvalue, ptraceback); - } - return result; -} - static void format_exc_check_arg(PyObject *exc, char *format_str, PyObject *obj) { diff --git a/Python/compile.c b/Python/compile.c index 1e4dddf..4c22441 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -176,6 +176,11 @@ static int inplace_binop(struct compiler *, operator_ty); static int expr_constant(expr_ty e); static int compiler_with(struct compiler *, stmt_ty); +static int compiler_call_helper(struct compiler *c, int n, + asdl_seq *args, + asdl_seq *keywords, + expr_ty starargs, + expr_ty kwargs); static PyCodeObject *assemble(struct compiler *, int addNone); static PyObject *__doc__; @@ -734,6 +739,8 @@ opcode_stack_effect(int opcode, int oparg) case PRINT_EXPR: return -1; + case LOAD_BUILD_CLASS: + return 1; case INPLACE_LSHIFT: case INPLACE_RSHIFT: case INPLACE_AND: @@ -744,8 +751,8 @@ opcode_stack_effect(int opcode, int oparg) return 0; case WITH_CLEANUP: return -1; /* XXX Sometimes more */ - case LOAD_LOCALS: - return 1; + case STORE_LOCALS: + return -1; case RETURN_VALUE: return -1; case IMPORT_STAR: @@ -757,8 +764,6 @@ opcode_stack_effect(int opcode, int oparg) return 0; case END_FINALLY: return -1; /* or -2 or -3 if exception occurred */ - case BUILD_CLASS: - return -2; case STORE_NAME: return -1; @@ -1509,54 +1514,107 @@ compiler_function(struct compiler *c, stmt_ty s) static int compiler_class(struct compiler *c, stmt_ty s) { - int n; + static PyObject *build_class = NULL; + static PyObject *locals = NULL; PyCodeObject *co; PyObject *str; - /* push class name on stack, needed by BUILD_CLASS */ - ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts); - /* push the tuple of base classes on the stack */ - n = asdl_seq_LEN(s->v.ClassDef.bases); - if (n > 0) - VISIT_SEQ(c, expr, s->v.ClassDef.bases); - ADDOP_I(c, BUILD_TUPLE, n); - if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, - s->lineno)) - return 0; - c->u->u_private = s->v.ClassDef.name; - Py_INCREF(c->u->u_private); - str = PyString_InternFromString("__name__"); - if (!str || !compiler_nameop(c, str, Load)) { - Py_XDECREF(str); - compiler_exit_scope(c); - return 0; + PySTEntryObject *ste; + + /* initialize statics */ + if (build_class == NULL) { + build_class = PyString_FromString("__build_class__"); + if (build_class == NULL) + return 0; } - - Py_DECREF(str); - str = PyString_InternFromString("__module__"); - if (!str || !compiler_nameop(c, str, Store)) { - Py_XDECREF(str); - compiler_exit_scope(c); - return 0; + if (locals == NULL) { + locals = PyString_FromString("__locals__"); + if (locals == NULL) + return 0; } - Py_DECREF(str); - if (!compiler_body(c, s->v.ClassDef.body)) { - compiler_exit_scope(c); + /* ultimately generate code for: + <name> = __build_class__(<func>, <name>, *<bases>, **<keywords>) + where: + <func> is a function/closure created from the class body + <name> is the class name + <bases> is the positional arguments and *varargs argument + <keywords> is the keyword arguments and **kwds argument + This borrows from compiler_call. + */ + + /* 0. Create a fake variable named __locals__ */ + ste = PySymtable_Lookup(c->c_st, s); + if (ste == NULL) + return 0; + assert(PyList_Check(ste->ste_varnames)); + if (PyList_Append(ste->ste_varnames, locals) < 0) return 0; - } - ADDOP_IN_SCOPE(c, LOAD_LOCALS); - ADDOP_IN_SCOPE(c, RETURN_VALUE); - co = assemble(c, 1); + /* 1. compile the class body into a code object */ + if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, s->lineno)) + return 0; + /* this block represents what we do in the new scope */ + { + /* use the class name for name mangling */ + Py_INCREF(s->v.ClassDef.name); + c->u->u_private = s->v.ClassDef.name; + /* force it to have one mandatory argument */ + c->u->u_argcount = 1; + /* load the first argument ... */ + ADDOP_I(c, LOAD_FAST, 0); + /* ... and store it into f_locals */ + ADDOP_IN_SCOPE(c, STORE_LOCALS); + /* load __name__ ... */ + str = PyString_InternFromString("__name__"); + if (!str || !compiler_nameop(c, str, Load)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + Py_DECREF(str); + /* ... and store it as __module__ */ + str = PyString_InternFromString("__module__"); + if (!str || !compiler_nameop(c, str, Store)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + Py_DECREF(str); + /* compile the body proper */ + if (!compiler_body(c, s->v.ClassDef.body)) { + compiler_exit_scope(c); + return 0; + } + /* return None */ + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP_IN_SCOPE(c, RETURN_VALUE); + /* create the code object */ + co = assemble(c, 1); + } + /* leave the new scope */ compiler_exit_scope(c); if (co == NULL) return 0; + /* 2. load the 'build_class' function */ + ADDOP(c, LOAD_BUILD_CLASS); + + /* 3. load a function (or closure) made from the code object */ compiler_make_closure(c, co, 0); Py_DECREF(co); - ADDOP_I(c, CALL_FUNCTION, 0); - ADDOP(c, BUILD_CLASS); + /* 4. load class name */ + ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts); + + /* 5. generate the rest of the code for the call */ + if (!compiler_call_helper(c, 2, + s->v.ClassDef.bases, + s->v.ClassDef.keywords, + s->v.ClassDef.starargs, + s->v.ClassDef.kwargs)) + return 0; + + /* 6. store into <name> */ if (!compiler_nameop(c, s->v.ClassDef.name, Store)) return 0; return 1; @@ -2613,21 +2671,37 @@ compiler_compare(struct compiler *c, expr_ty e) static int compiler_call(struct compiler *c, expr_ty e) { - int n, code = 0; - VISIT(c, expr, e->v.Call.func); - n = asdl_seq_LEN(e->v.Call.args); - VISIT_SEQ(c, expr, e->v.Call.args); - if (e->v.Call.keywords) { - VISIT_SEQ(c, keyword, e->v.Call.keywords); - n |= asdl_seq_LEN(e->v.Call.keywords) << 8; - } - if (e->v.Call.starargs) { - VISIT(c, expr, e->v.Call.starargs); + return compiler_call_helper(c, 0, + e->v.Call.args, + e->v.Call.keywords, + e->v.Call.starargs, + e->v.Call.kwargs); +} + +/* shared code between compiler_call and compiler_class */ +static int +compiler_call_helper(struct compiler *c, + int n, /* Args already pushed */ + asdl_seq *args, + asdl_seq *keywords, + expr_ty starargs, + expr_ty kwargs) +{ + int code = 0; + + n += asdl_seq_LEN(args); + VISIT_SEQ(c, expr, args); + if (keywords) { + VISIT_SEQ(c, keyword, keywords); + n |= asdl_seq_LEN(keywords) << 8; + } + if (starargs) { + VISIT(c, expr, starargs); code |= 1; } - if (e->v.Call.kwargs) { - VISIT(c, expr, e->v.Call.kwargs); + if (kwargs) { + VISIT(c, expr, kwargs); code |= 2; } switch (code) { diff --git a/Python/graminit.c b/Python/graminit.c index 5c7fb6a..1287219 100644 --- a/Python/graminit.c +++ b/Python/graminit.c @@ -1635,7 +1635,7 @@ static arc arcs_76_2[2] = { {23, 4}, }; static arc arcs_76_3[2] = { - {9, 5}, + {14, 5}, {15, 6}, }; static arc arcs_76_4[1] = { diff --git a/Python/import.c b/Python/import.c index fae60cf..33953c7 100644 --- a/Python/import.c +++ b/Python/import.c @@ -72,9 +72,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *); 3030 (added keyword-only parameters) 3040 (added signature annotations) 3050 (print becomes a function) + 3060 (PEP 3115 metaclass syntax) . */ -#define MAGIC (3050 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (3060 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the diff --git a/Python/symtable.c b/Python/symtable.c index 5bac2a2..e9c9391 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -983,6 +983,11 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL)) return 0; VISIT_SEQ(st, expr, s->v.ClassDef.bases); + VISIT_SEQ(st, keyword, s->v.ClassDef.keywords); + if (s->v.ClassDef.starargs) + VISIT(st, expr, s->v.ClassDef.starargs); + if (s->v.ClassDef.kwargs) + VISIT(st, expr, s->v.ClassDef.kwargs); if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, (void *)s, s->lineno)) return 0; |