Issue #23722: Initialize __class__ from type.__new__()

The __class__ cell used by zero-argument super() is now initialized
from type.__new__ rather than __build_class__, so class methods
relying on that will now work correctly when called from metaclass
methods during class creation.

Patch by Martin Teichmann.
This commit is contained in:
Nick Coghlan 2016-09-11 14:45:49 +10:00
parent fc3f7d5677
commit 944368e1cc
8 changed files with 1358 additions and 1258 deletions

View file

@ -54,7 +54,7 @@ _Py_IDENTIFIER(stderr);
static PyObject *
builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *func, *name, *bases, *mkw, *meta, *winner, *prep, *ns, *cell;
PyObject *func, *name, *bases, *mkw, *meta, *winner, *prep, *ns, *none;
PyObject *cls = NULL;
Py_ssize_t nargs;
int isclass = 0; /* initialize to prevent gcc warning */
@ -167,15 +167,13 @@ builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
Py_DECREF(bases);
return NULL;
}
cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,
none = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,
NULL, 0, NULL, 0, NULL, 0, NULL,
PyFunction_GET_CLOSURE(func));
if (cell != NULL) {
if (none != NULL) {
PyObject *margs[3] = {name, bases, ns};
cls = _PyObject_FastCallDict(meta, margs, 3, mkw);
if (cls != NULL && PyCell_Check(cell))
PyCell_Set(cell, cls);
Py_DECREF(cell);
Py_DECREF(none);
}
Py_DECREF(ns);
Py_DECREF(meta);

View file

@ -1968,7 +1968,7 @@ compiler_class(struct compiler *c, stmt_ty s)
return 0;
}
if (c->u->u_ste->ste_needs_class_closure) {
/* return the (empty) __class__ cell */
/* store __classcell__ into class namespace */
str = PyUnicode_InternFromString("__class__");
if (str == NULL) {
compiler_exit_scope(c);
@ -1981,15 +1981,20 @@ compiler_class(struct compiler *c, stmt_ty s)
return 0;
}
assert(i == 0);
/* Return the cell where to store __class__ */
ADDOP_I(c, LOAD_CLOSURE, i);
str = PyUnicode_InternFromString("__classcell__");
if (!str || !compiler_nameop(c, str, Store)) {
Py_XDECREF(str);
compiler_exit_scope(c);
return 0;
}
Py_DECREF(str);
}
else {
/* This happens when nobody references the cell. */
assert(PyDict_Size(c->u->u_cellvars) == 0);
/* This happens when nobody references the cell. Return None. */
ADDOP_O(c, LOAD_CONST, Py_None, consts);
}
ADDOP_IN_SCOPE(c, RETURN_VALUE);
/* create the code object */
co = assemble(c, 1);
}

File diff suppressed because it is too large Load diff