mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
gh-124153: Implement PyType_GetBaseByToken() and Py_tp_token slot (GH-124163)
This commit is contained in:
parent
79a7410236
commit
646f16bdee
18 changed files with 443 additions and 13 deletions
|
|
@ -410,6 +410,118 @@ pyobject_getitemdata(PyObject *self, PyObject *o)
|
|||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
create_type_with_token(PyObject *module, PyObject *args)
|
||||
{
|
||||
const char *name;
|
||||
PyObject *py_token;
|
||||
if (!PyArg_ParseTuple(args, "sO", &name, &py_token)) {
|
||||
return NULL;
|
||||
}
|
||||
void *token = PyLong_AsVoidPtr(py_token);
|
||||
if (token == Py_TP_USE_SPEC) {
|
||||
// Py_TP_USE_SPEC requires the spec that at least outlives the class
|
||||
static PyType_Slot slots[] = {
|
||||
{Py_tp_token, Py_TP_USE_SPEC},
|
||||
{0},
|
||||
};
|
||||
static PyType_Spec spec = {
|
||||
.name = "_testcapi.DefaultTokenTest",
|
||||
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.slots = slots,
|
||||
};
|
||||
PyObject *type = PyType_FromMetaclass(NULL, NULL, &spec, NULL);
|
||||
if (!type) {
|
||||
return NULL;
|
||||
}
|
||||
token = PyType_GetSlot((PyTypeObject *)type, Py_tp_token);
|
||||
assert(!PyErr_Occurred());
|
||||
Py_DECREF(type);
|
||||
if (token != &spec) {
|
||||
PyErr_SetString(PyExc_AssertionError,
|
||||
"failed to convert token from Py_TP_USE_SPEC");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// Test non-NULL token that must also outlive the class
|
||||
PyType_Slot slots[] = {
|
||||
{Py_tp_token, token},
|
||||
{0},
|
||||
};
|
||||
PyType_Spec spec = {
|
||||
.name = name,
|
||||
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.slots = slots,
|
||||
};
|
||||
return PyType_FromMetaclass(NULL, module, &spec, NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_tp_token(PyObject *self, PyObject *type)
|
||||
{
|
||||
void *token = PyType_GetSlot((PyTypeObject *)type, Py_tp_token);
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
return PyLong_FromVoidPtr(token);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pytype_getbasebytoken(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyTypeObject *type;
|
||||
PyObject *py_token, *use_mro, *need_result;
|
||||
if (!PyArg_ParseTuple(args, "OOOO",
|
||||
&type, &py_token, &use_mro, &need_result)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *mro_save = NULL;
|
||||
if (use_mro != Py_True) {
|
||||
// Test internal detail: PyType_GetBaseByToken works even with
|
||||
// types that are only partially initialized (or torn down):
|
||||
// if tp_mro=NULL we fall back to tp_bases.
|
||||
assert(PyType_Check(type));
|
||||
mro_save = type->tp_mro;
|
||||
type->tp_mro = NULL;
|
||||
}
|
||||
|
||||
void *token = PyLong_AsVoidPtr(py_token);
|
||||
PyObject *result;
|
||||
int ret;
|
||||
if (need_result == Py_True) {
|
||||
ret = PyType_GetBaseByToken(type, token, (PyTypeObject **)&result);
|
||||
}
|
||||
else {
|
||||
result = NULL;
|
||||
ret = PyType_GetBaseByToken(type, token, NULL);
|
||||
}
|
||||
|
||||
if (use_mro != Py_True) {
|
||||
type->tp_mro = mro_save;
|
||||
}
|
||||
if (ret < 0) {
|
||||
assert(result == NULL);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *py_ret = PyLong_FromLong(ret);
|
||||
if (py_ret == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *tuple = PyTuple_New(2);
|
||||
if (tuple == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyTuple_SET_ITEM(tuple, 0, py_ret);
|
||||
PyTuple_SET_ITEM(tuple, 1, result ? result : Py_None);
|
||||
return tuple;
|
||||
error:
|
||||
Py_XDECREF(py_ret);
|
||||
Py_XDECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef TestMethods[] = {
|
||||
{"pytype_fromspec_meta", pytype_fromspec_meta, METH_O},
|
||||
{"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS},
|
||||
|
|
@ -423,6 +535,9 @@ static PyMethodDef TestMethods[] = {
|
|||
{"make_immutable_type_with_base", make_immutable_type_with_base, METH_O},
|
||||
{"make_type_with_base", make_type_with_base, METH_O},
|
||||
{"pyobject_getitemdata", pyobject_getitemdata, METH_O},
|
||||
{"create_type_with_token", create_type_with_token, METH_VARARGS},
|
||||
{"get_tp_token", get_tp_token, METH_O},
|
||||
{"pytype_getbasebytoken", pytype_getbasebytoken, METH_VARARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
@ -1287,6 +1402,8 @@ _PyTestCapi_Init_Heaptype(PyObject *m) {
|
|||
&PyType_Type, m, &HeapCTypeMetaclassNullNew_spec, (PyObject *) &PyType_Type);
|
||||
ADD("HeapCTypeMetaclassNullNew", HeapCTypeMetaclassNullNew);
|
||||
|
||||
ADD("Py_TP_USE_SPEC", PyLong_FromVoidPtr(Py_TP_USE_SPEC));
|
||||
|
||||
PyObject *HeapCCollection = PyType_FromMetaclass(
|
||||
NULL, m, &HeapCCollection_spec, NULL);
|
||||
if (HeapCCollection == NULL) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue