]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-93649: Split heaptype tests from _testcapimodule.c (GH-95386)
authorPetr Viktorin <encukou@gmail.com>
Mon, 1 Aug 2022 13:04:14 +0000 (15:04 +0200)
committerGitHub <noreply@github.com>
Mon, 1 Aug 2022 13:04:14 +0000 (15:04 +0200)
This removes the unused negative_dictoffset function:
the type this function would create is available as
    _testcapi.HeapCTypeWithNegativeDict

Modules/Setup.stdlib.in
Modules/_testcapi/heaptype.c [new file with mode: 0644]
Modules/_testcapi/parts.h
Modules/_testcapimodule.c
PCbuild/_testcapi.vcxproj
PCbuild/_testcapi.vcxproj.filters

index 09eca9f980db14df8251212432d22646ae32e8ca..c5dc1e8eb45377fcaca3a22ce9acbcba82f2ace7 100644 (file)
 @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
 @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
 @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c
+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c
 
 # Some testing modules MUST be built as shared libraries.
 *shared*
diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c
new file mode 100644 (file)
index 0000000..9fb0051
--- /dev/null
@@ -0,0 +1,973 @@
+#include "parts.h"
+#include "structmember.h"         // PyMemberDef
+
+static struct PyModuleDef *_testcapimodule = NULL;  // set at initialization
+
+/* Tests for heap types (PyType_From*) */
+
+static PyObject *pytype_fromspec_meta(PyObject* self, PyObject *meta)
+{
+    if (!PyType_Check(meta)) {
+        PyErr_SetString(
+            PyExc_TypeError,
+            "pytype_fromspec_meta: must be invoked with a type argument!");
+        return NULL;
+    }
+
+    PyType_Slot HeapCTypeViaMetaclass_slots[] = {
+        {0},
+    };
+
+    PyType_Spec HeapCTypeViaMetaclass_spec = {
+        "_testcapi.HeapCTypeViaMetaclass",
+        sizeof(PyObject),
+        0,
+        Py_TPFLAGS_DEFAULT,
+        HeapCTypeViaMetaclass_slots
+    };
+
+    return PyType_FromMetaclass(
+        (PyTypeObject *) meta, NULL, &HeapCTypeViaMetaclass_spec, NULL);
+}
+
+
+static PyType_Slot empty_type_slots[] = {
+    {0, 0},
+};
+
+static PyType_Spec MinimalMetaclass_spec = {
+    .name = "_testcapi.MinimalMetaclass",
+    .basicsize = sizeof(PyHeapTypeObject),
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    .slots = empty_type_slots,
+};
+
+static PyType_Spec MinimalType_spec = {
+    .name = "_testcapi.MinimalSpecType",
+    .basicsize = 0,  // Updated later
+    .flags = Py_TPFLAGS_DEFAULT,
+    .slots = empty_type_slots,
+};
+
+
+static PyObject *
+test_from_spec_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *metaclass = NULL;
+    PyObject *class = NULL;
+    PyObject *new = NULL;
+    PyObject *subclasses = NULL;
+    PyObject *result = NULL;
+    int r;
+
+    metaclass = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
+    if (metaclass == NULL) {
+        goto finally;
+    }
+    class = PyObject_CallFunction(metaclass, "s(){}", "TestClass");
+    if (class == NULL) {
+        goto finally;
+    }
+
+    MinimalType_spec.basicsize = (int)(((PyTypeObject*)class)->tp_basicsize);
+    new = PyType_FromSpecWithBases(&MinimalType_spec, class);
+    if (new == NULL) {
+        goto finally;
+    }
+    if (Py_TYPE(new) != (PyTypeObject*)metaclass) {
+        PyErr_SetString(PyExc_AssertionError,
+                "Metaclass not set properly!");
+        goto finally;
+    }
+
+    /* Assert that __subclasses__ is updated */
+    subclasses = PyObject_CallMethod(class, "__subclasses__", "");
+    if (!subclasses) {
+        goto finally;
+    }
+    r = PySequence_Contains(subclasses, new);
+    if (r < 0) {
+        goto finally;
+    }
+    if (r == 0) {
+        PyErr_SetString(PyExc_AssertionError,
+                "subclasses not set properly!");
+        goto finally;
+    }
+
+    result = Py_NewRef(Py_None);
+
+finally:
+    Py_XDECREF(metaclass);
+    Py_XDECREF(class);
+    Py_XDECREF(new);
+    Py_XDECREF(subclasses);
+    return result;
+}
+
+
+static PyObject *
+test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *metaclass_a = NULL;
+    PyObject *metaclass_b = NULL;
+    PyObject *class_a = NULL;
+    PyObject *class_b = NULL;
+    PyObject *bases = NULL;
+    PyObject *new = NULL;
+    PyObject *meta_error_string = NULL;
+    PyObject *exc_type = NULL;
+    PyObject *exc_value = NULL;
+    PyObject *exc_traceback = NULL;
+    PyObject *result = NULL;
+
+    metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
+    if (metaclass_a == NULL) {
+        goto finally;
+    }
+    metaclass_b = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
+    if (metaclass_b == NULL) {
+        goto finally;
+    }
+    class_a = PyObject_CallFunction(metaclass_a, "s(){}", "TestClassA");
+    if (class_a == NULL) {
+        goto finally;
+    }
+
+    class_b = PyObject_CallFunction(metaclass_b, "s(){}", "TestClassB");
+    if (class_b == NULL) {
+        goto finally;
+    }
+
+    bases = PyTuple_Pack(2, class_a, class_b);
+    if (bases == NULL) {
+        goto finally;
+    }
+
+    /*
+     * The following should raise a TypeError due to a MetaClass conflict.
+     */
+    new = PyType_FromSpecWithBases(&MinimalType_spec, bases);
+    if (new != NULL) {
+        PyErr_SetString(PyExc_AssertionError,
+                "MetaType conflict not recognized by PyType_FromSpecWithBases");
+            goto finally;
+    }
+
+    // Assert that the correct exception was raised
+    if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+        PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
+
+        meta_error_string = PyUnicode_FromString("metaclass conflict:");
+        if (meta_error_string == NULL) {
+            goto finally;
+        }
+        int res = PyUnicode_Contains(exc_value, meta_error_string);
+        if (res < 0) {
+            goto finally;
+        }
+        if (res == 0) {
+            PyErr_SetString(PyExc_AssertionError,
+                    "TypeError did not inlclude expected message.");
+            goto finally;
+        }
+        result = Py_NewRef(Py_None);
+    }
+finally:
+    Py_XDECREF(metaclass_a);
+    Py_XDECREF(metaclass_b);
+    Py_XDECREF(bases);
+    Py_XDECREF(new);
+    Py_XDECREF(meta_error_string);
+    Py_XDECREF(exc_type);
+    Py_XDECREF(exc_value);
+    Py_XDECREF(exc_traceback);
+    Py_XDECREF(class_a);
+    Py_XDECREF(class_b);
+    return result;
+}
+
+
+static PyObject *
+simple_str(PyObject *self) {
+    return PyUnicode_FromString("<test>");
+}
+
+
+static PyObject *
+test_type_from_ephemeral_spec(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    // Test that a heap type can be created from a spec that's later deleted
+    // (along with all its contents).
+    // All necessary data must be copied and held by the class
+    PyType_Spec *spec = NULL;
+    char *name = NULL;
+    char *doc = NULL;
+    PyType_Slot *slots = NULL;
+    PyObject *class = NULL;
+    PyObject *instance = NULL;
+    PyObject *obj = NULL;
+    PyObject *result = NULL;
+
+    /* create a spec (and all its contents) on the heap */
+
+    const char NAME[] = "testcapi._Test";
+    const char DOC[] = "a test class";
+
+    spec = PyMem_New(PyType_Spec, 1);
+    if (spec == NULL) {
+        PyErr_NoMemory();
+        goto finally;
+    }
+    name = PyMem_New(char, sizeof(NAME));
+    if (name == NULL) {
+        PyErr_NoMemory();
+        goto finally;
+    }
+    memcpy(name, NAME, sizeof(NAME));
+
+    doc = PyMem_New(char, sizeof(DOC));
+    if (doc == NULL) {
+        PyErr_NoMemory();
+        goto finally;
+    }
+    memcpy(doc, DOC, sizeof(DOC));
+
+    spec->name = name;
+    spec->basicsize = sizeof(PyObject);
+    spec->itemsize = 0;
+    spec->flags = Py_TPFLAGS_DEFAULT;
+    slots = PyMem_New(PyType_Slot, 3);
+    if (slots == NULL) {
+        PyErr_NoMemory();
+        goto finally;
+    }
+    slots[0].slot = Py_tp_str;
+    slots[0].pfunc = simple_str;
+    slots[1].slot = Py_tp_doc;
+    slots[1].pfunc = doc;
+    slots[2].slot = 0;
+    slots[2].pfunc = NULL;
+    spec->slots = slots;
+
+    /* create the class */
+
+    class = PyType_FromSpec(spec);
+    if (class == NULL) {
+        goto finally;
+    }
+
+    /* deallocate the spec (and all contents) */
+
+    // (Explicitly ovewrite memory before freeing,
+    // so bugs show themselves even without the debug allocator's help.)
+    memset(spec, 0xdd, sizeof(PyType_Spec));
+    PyMem_Del(spec);
+    spec = NULL;
+    memset(name, 0xdd, sizeof(NAME));
+    PyMem_Del(name);
+    name = NULL;
+    memset(doc, 0xdd, sizeof(DOC));
+    PyMem_Del(doc);
+    doc = NULL;
+    memset(slots, 0xdd, 3 * sizeof(PyType_Slot));
+    PyMem_Del(slots);
+    slots = NULL;
+
+    /* check that everything works */
+
+    PyTypeObject *class_tp = (PyTypeObject *)class;
+    PyHeapTypeObject *class_ht = (PyHeapTypeObject *)class;
+    assert(strcmp(class_tp->tp_name, "testcapi._Test") == 0);
+    assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_name), "_Test") == 0);
+    assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_qualname), "_Test") == 0);
+    assert(strcmp(class_tp->tp_doc, "a test class") == 0);
+
+    // call and check __str__
+    instance = PyObject_CallNoArgs(class);
+    if (instance == NULL) {
+        goto finally;
+    }
+    obj = PyObject_Str(instance);
+    if (obj == NULL) {
+        goto finally;
+    }
+    assert(strcmp(PyUnicode_AsUTF8(obj), "<test>") == 0);
+    Py_CLEAR(obj);
+
+    result = Py_NewRef(Py_None);
+  finally:
+    PyMem_Del(spec);
+    PyMem_Del(name);
+    PyMem_Del(doc);
+    PyMem_Del(slots);
+    Py_XDECREF(class);
+    Py_XDECREF(instance);
+    Py_XDECREF(obj);
+    return result;
+}
+
+PyType_Slot repeated_doc_slots[] = {
+    {Py_tp_doc, "A class used for testsĀ·"},
+    {Py_tp_doc, "A class used for tests"},
+    {0, 0},
+};
+
+PyType_Spec repeated_doc_slots_spec = {
+    .name = "RepeatedDocSlotClass",
+    .basicsize = sizeof(PyObject),
+    .slots = repeated_doc_slots,
+};
+
+typedef struct {
+    PyObject_HEAD
+    int data;
+} HeapCTypeWithDataObject;
+
+
+static struct PyMemberDef members_to_repeat[] = {
+    {"T_INT", T_INT, offsetof(HeapCTypeWithDataObject, data), 0, NULL},
+    {NULL}
+};
+
+PyType_Slot repeated_members_slots[] = {
+    {Py_tp_members, members_to_repeat},
+    {Py_tp_members, members_to_repeat},
+    {0, 0},
+};
+
+PyType_Spec repeated_members_slots_spec = {
+    .name = "RepeatedMembersSlotClass",
+    .basicsize = sizeof(HeapCTypeWithDataObject),
+    .slots = repeated_members_slots,
+};
+
+static PyObject *
+create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj)
+{
+    PyObject *class = NULL;
+    int variant = PyLong_AsLong(variant_obj);
+    if (PyErr_Occurred()) {
+        return NULL;
+    }
+    switch (variant) {
+        case 0:
+            class = PyType_FromSpec(&repeated_doc_slots_spec);
+            break;
+        case 1:
+            class = PyType_FromSpec(&repeated_members_slots_spec);
+            break;
+        default:
+            PyErr_SetString(PyExc_ValueError, "bad test variant");
+            break;
+        }
+    return class;
+}
+
+
+static PyMethodDef TestMethods[] = {
+    {"pytype_fromspec_meta",    pytype_fromspec_meta,            METH_O},
+    {"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS},
+    {"create_type_from_repeated_slots",
+        create_type_from_repeated_slots, METH_O},
+    {"test_from_spec_metatype_inheritance", test_from_spec_metatype_inheritance,
+     METH_NOARGS},
+    {"test_from_spec_invalid_metatype_inheritance",
+     test_from_spec_invalid_metatype_inheritance,
+     METH_NOARGS},
+    {NULL},
+};
+
+
+PyDoc_STRVAR(heapdocctype__doc__,
+"HeapDocCType(arg1, arg2)\n"
+"--\n"
+"\n"
+"somedoc");
+
+typedef struct {
+    PyObject_HEAD
+} HeapDocCTypeObject;
+
+static PyType_Slot HeapDocCType_slots[] = {
+    {Py_tp_doc, (char*)heapdocctype__doc__},
+    {0},
+};
+
+static PyType_Spec HeapDocCType_spec = {
+    "_testcapi.HeapDocCType",
+    sizeof(HeapDocCTypeObject),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    HeapDocCType_slots
+};
+
+typedef struct {
+    PyObject_HEAD
+} NullTpDocTypeObject;
+
+static PyType_Slot NullTpDocType_slots[] = {
+    {Py_tp_doc, NULL},
+    {0, 0},
+};
+
+static PyType_Spec NullTpDocType_spec = {
+    "_testcapi.NullTpDocType",
+    sizeof(NullTpDocTypeObject),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    NullTpDocType_slots
+};
+
+
+PyDoc_STRVAR(heapgctype__doc__,
+"A heap type with GC, and with overridden dealloc.\n\n"
+"The 'value' attribute is set to 10 in __init__.");
+
+typedef struct {
+    PyObject_HEAD
+    int value;
+} HeapCTypeObject;
+
+static struct PyMemberDef heapctype_members[] = {
+    {"value", T_INT, offsetof(HeapCTypeObject, value)},
+    {NULL} /* Sentinel */
+};
+
+static int
+heapctype_init(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    ((HeapCTypeObject *)self)->value = 10;
+    return 0;
+}
+
+static int
+heapgcctype_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(self));
+    return 0;
+}
+
+static void
+heapgcctype_dealloc(HeapCTypeObject *self)
+{
+    PyTypeObject *tp = Py_TYPE(self);
+    PyObject_GC_UnTrack(self);
+    PyObject_GC_Del(self);
+    Py_DECREF(tp);
+}
+
+static PyType_Slot HeapGcCType_slots[] = {
+    {Py_tp_init, heapctype_init},
+    {Py_tp_members, heapctype_members},
+    {Py_tp_dealloc, heapgcctype_dealloc},
+    {Py_tp_traverse, heapgcctype_traverse},
+    {Py_tp_doc, (char*)heapgctype__doc__},
+    {0, 0},
+};
+
+static PyType_Spec HeapGcCType_spec = {
+    "_testcapi.HeapGcCType",
+    sizeof(HeapCTypeObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+    HeapGcCType_slots
+};
+
+PyDoc_STRVAR(heapctype__doc__,
+"A heap type without GC, but with overridden dealloc.\n\n"
+"The 'value' attribute is set to 10 in __init__.");
+
+static void
+heapctype_dealloc(HeapCTypeObject *self)
+{
+    PyTypeObject *tp = Py_TYPE(self);
+    PyObject_Free(self);
+    Py_DECREF(tp);
+}
+
+static PyType_Slot HeapCType_slots[] = {
+    {Py_tp_init, heapctype_init},
+    {Py_tp_members, heapctype_members},
+    {Py_tp_dealloc, heapctype_dealloc},
+    {Py_tp_doc, (char*)heapctype__doc__},
+    {0, 0},
+};
+
+static PyType_Spec HeapCType_spec = {
+    "_testcapi.HeapCType",
+    sizeof(HeapCTypeObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCType_slots
+};
+
+PyDoc_STRVAR(heapctypesubclass__doc__,
+"Subclass of HeapCType, without GC.\n\n"
+"__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
+
+typedef struct {
+    HeapCTypeObject base;
+    int value2;
+} HeapCTypeSubclassObject;
+
+static int
+heapctypesubclass_init(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    /* Call __init__ of the superclass */
+    if (heapctype_init(self, args, kwargs) < 0) {
+        return -1;
+    }
+    /* Initialize additional element */
+    ((HeapCTypeSubclassObject *)self)->value2 = 20;
+    return 0;
+}
+
+static struct PyMemberDef heapctypesubclass_members[] = {
+    {"value2", T_INT, offsetof(HeapCTypeSubclassObject, value2)},
+    {NULL} /* Sentinel */
+};
+
+static PyType_Slot HeapCTypeSubclass_slots[] = {
+    {Py_tp_init, heapctypesubclass_init},
+    {Py_tp_members, heapctypesubclass_members},
+    {Py_tp_doc, (char*)heapctypesubclass__doc__},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeSubclass_spec = {
+    "_testcapi.HeapCTypeSubclass",
+    sizeof(HeapCTypeSubclassObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCTypeSubclass_slots
+};
+
+PyDoc_STRVAR(heapctypewithbuffer__doc__,
+"Heap type with buffer support.\n\n"
+"The buffer is set to [b'1', b'2', b'3', b'4']");
+
+typedef struct {
+    HeapCTypeObject base;
+    char buffer[4];
+} HeapCTypeWithBufferObject;
+
+static int
+heapctypewithbuffer_getbuffer(HeapCTypeWithBufferObject *self, Py_buffer *view, int flags)
+{
+    self->buffer[0] = '1';
+    self->buffer[1] = '2';
+    self->buffer[2] = '3';
+    self->buffer[3] = '4';
+    return PyBuffer_FillInfo(
+        view, (PyObject*)self, (void *)self->buffer, 4, 1, flags);
+}
+
+static void
+heapctypewithbuffer_releasebuffer(HeapCTypeWithBufferObject *self, Py_buffer *view)
+{
+    assert(view->obj == (void*) self);
+}
+
+static PyType_Slot HeapCTypeWithBuffer_slots[] = {
+    {Py_bf_getbuffer, heapctypewithbuffer_getbuffer},
+    {Py_bf_releasebuffer, heapctypewithbuffer_releasebuffer},
+    {Py_tp_doc, (char*)heapctypewithbuffer__doc__},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeWithBuffer_spec = {
+    "_testcapi.HeapCTypeWithBuffer",
+    sizeof(HeapCTypeWithBufferObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCTypeWithBuffer_slots
+};
+
+PyDoc_STRVAR(heapctypesubclasswithfinalizer__doc__,
+"Subclass of HeapCType with a finalizer that reassigns __class__.\n\n"
+"__class__ is set to plain HeapCTypeSubclass during finalization.\n"
+"__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
+
+static int
+heapctypesubclasswithfinalizer_init(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    PyTypeObject *base = (PyTypeObject *)PyType_GetSlot(Py_TYPE(self), Py_tp_base);
+    initproc base_init = PyType_GetSlot(base, Py_tp_init);
+    base_init(self, args, kwargs);
+    return 0;
+}
+
+static void
+heapctypesubclasswithfinalizer_finalize(PyObject *self)
+{
+    PyObject *error_type, *error_value, *error_traceback, *m;
+    PyObject *oldtype = NULL, *newtype = NULL, *refcnt = NULL;
+
+    /* Save the current exception, if any. */
+    PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+    if (_testcapimodule == NULL) {
+        goto cleanup_finalize;
+    }
+    m = PyState_FindModule(_testcapimodule);
+    if (m == NULL) {
+        goto cleanup_finalize;
+    }
+    oldtype = PyObject_GetAttrString(m, "HeapCTypeSubclassWithFinalizer");
+    newtype = PyObject_GetAttrString(m, "HeapCTypeSubclass");
+    if (oldtype == NULL || newtype == NULL) {
+        goto cleanup_finalize;
+    }
+
+    if (PyObject_SetAttrString(self, "__class__", newtype) < 0) {
+        goto cleanup_finalize;
+    }
+    refcnt = PyLong_FromSsize_t(Py_REFCNT(oldtype));
+    if (refcnt == NULL) {
+        goto cleanup_finalize;
+    }
+    if (PyObject_SetAttrString(oldtype, "refcnt_in_del", refcnt) < 0) {
+        goto cleanup_finalize;
+    }
+    Py_DECREF(refcnt);
+    refcnt = PyLong_FromSsize_t(Py_REFCNT(newtype));
+    if (refcnt == NULL) {
+        goto cleanup_finalize;
+    }
+    if (PyObject_SetAttrString(newtype, "refcnt_in_del", refcnt) < 0) {
+        goto cleanup_finalize;
+    }
+
+cleanup_finalize:
+    Py_XDECREF(oldtype);
+    Py_XDECREF(newtype);
+    Py_XDECREF(refcnt);
+
+    /* Restore the saved exception. */
+    PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+static PyType_Slot HeapCTypeSubclassWithFinalizer_slots[] = {
+    {Py_tp_init, heapctypesubclasswithfinalizer_init},
+    {Py_tp_members, heapctypesubclass_members},
+    {Py_tp_finalize, heapctypesubclasswithfinalizer_finalize},
+    {Py_tp_doc, (char*)heapctypesubclasswithfinalizer__doc__},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeSubclassWithFinalizer_spec = {
+    "_testcapi.HeapCTypeSubclassWithFinalizer",
+    sizeof(HeapCTypeSubclassObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE,
+    HeapCTypeSubclassWithFinalizer_slots
+};
+
+static PyType_Slot HeapCTypeMetaclass_slots[] = {
+    {0},
+};
+
+static PyType_Spec HeapCTypeMetaclass_spec = {
+    "_testcapi.HeapCTypeMetaclass",
+    sizeof(PyHeapTypeObject),
+    sizeof(PyMemberDef),
+    Py_TPFLAGS_DEFAULT,
+    HeapCTypeMetaclass_slots
+};
+
+static PyObject *
+heap_ctype_metaclass_custom_tp_new(PyTypeObject *tp, PyObject *args, PyObject *kwargs)
+{
+    return PyType_Type.tp_new(tp, args, kwargs);
+}
+
+static PyType_Slot HeapCTypeMetaclassCustomNew_slots[] = {
+    { Py_tp_new, heap_ctype_metaclass_custom_tp_new },
+    {0},
+};
+
+static PyType_Spec HeapCTypeMetaclassCustomNew_spec = {
+    "_testcapi.HeapCTypeMetaclassCustomNew",
+    sizeof(PyHeapTypeObject),
+    sizeof(PyMemberDef),
+    Py_TPFLAGS_DEFAULT,
+    HeapCTypeMetaclassCustomNew_slots
+};
+
+
+typedef struct {
+    PyObject_HEAD
+    PyObject *dict;
+} HeapCTypeWithDictObject;
+
+static void
+heapctypewithdict_dealloc(HeapCTypeWithDictObject* self)
+{
+
+    PyTypeObject *tp = Py_TYPE(self);
+    Py_XDECREF(self->dict);
+    PyObject_Free(self);
+    Py_DECREF(tp);
+}
+
+static PyGetSetDef heapctypewithdict_getsetlist[] = {
+    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
+    {NULL} /* Sentinel */
+};
+
+static struct PyMemberDef heapctypewithdict_members[] = {
+    {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
+    {"__dictoffset__", T_PYSSIZET, offsetof(HeapCTypeWithDictObject, dict), READONLY},
+    {NULL} /* Sentinel */
+};
+
+static PyType_Slot HeapCTypeWithDict_slots[] = {
+    {Py_tp_members, heapctypewithdict_members},
+    {Py_tp_getset, heapctypewithdict_getsetlist},
+    {Py_tp_dealloc, heapctypewithdict_dealloc},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeWithDict_spec = {
+    "_testcapi.HeapCTypeWithDict",
+    sizeof(HeapCTypeWithDictObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCTypeWithDict_slots
+};
+
+static struct PyMemberDef heapctypewithnegativedict_members[] = {
+    {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
+    {"__dictoffset__", T_PYSSIZET, -(Py_ssize_t)sizeof(void*), READONLY},
+    {NULL} /* Sentinel */
+};
+
+static PyType_Slot HeapCTypeWithNegativeDict_slots[] = {
+    {Py_tp_members, heapctypewithnegativedict_members},
+    {Py_tp_getset, heapctypewithdict_getsetlist},
+    {Py_tp_dealloc, heapctypewithdict_dealloc},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeWithNegativeDict_spec = {
+    "_testcapi.HeapCTypeWithNegativeDict",
+    sizeof(HeapCTypeWithDictObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCTypeWithNegativeDict_slots
+};
+
+typedef struct {
+    PyObject_HEAD
+    PyObject *weakreflist;
+} HeapCTypeWithWeakrefObject;
+
+static struct PyMemberDef heapctypewithweakref_members[] = {
+    {"weakreflist", T_OBJECT, offsetof(HeapCTypeWithWeakrefObject, weakreflist)},
+    {"__weaklistoffset__", T_PYSSIZET,
+      offsetof(HeapCTypeWithWeakrefObject, weakreflist), READONLY},
+    {NULL} /* Sentinel */
+};
+
+static void
+heapctypewithweakref_dealloc(HeapCTypeWithWeakrefObject* self)
+{
+
+    PyTypeObject *tp = Py_TYPE(self);
+    if (self->weakreflist != NULL)
+        PyObject_ClearWeakRefs((PyObject *) self);
+    Py_XDECREF(self->weakreflist);
+    PyObject_Free(self);
+    Py_DECREF(tp);
+}
+
+static PyType_Slot HeapCTypeWithWeakref_slots[] = {
+    {Py_tp_members, heapctypewithweakref_members},
+    {Py_tp_dealloc, heapctypewithweakref_dealloc},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeWithWeakref_spec = {
+    "_testcapi.HeapCTypeWithWeakref",
+    sizeof(HeapCTypeWithWeakrefObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCTypeWithWeakref_slots
+};
+
+PyDoc_STRVAR(heapctypesetattr__doc__,
+"A heap type without GC, but with overridden __setattr__.\n\n"
+"The 'value' attribute is set to 10 in __init__ and updated via attribute setting.");
+
+typedef struct {
+    PyObject_HEAD
+    long value;
+} HeapCTypeSetattrObject;
+
+static struct PyMemberDef heapctypesetattr_members[] = {
+    {"pvalue", T_LONG, offsetof(HeapCTypeSetattrObject, value)},
+    {NULL} /* Sentinel */
+};
+
+static int
+heapctypesetattr_init(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    ((HeapCTypeSetattrObject *)self)->value = 10;
+    return 0;
+}
+
+static void
+heapctypesetattr_dealloc(HeapCTypeSetattrObject *self)
+{
+    PyTypeObject *tp = Py_TYPE(self);
+    PyObject_Free(self);
+    Py_DECREF(tp);
+}
+
+static int
+heapctypesetattr_setattro(HeapCTypeSetattrObject *self, PyObject *attr, PyObject *value)
+{
+    PyObject *svalue = PyUnicode_FromString("value");
+    if (svalue == NULL)
+        return -1;
+    int eq = PyObject_RichCompareBool(svalue, attr, Py_EQ);
+    Py_DECREF(svalue);
+    if (eq < 0)
+        return -1;
+    if (!eq) {
+        return PyObject_GenericSetAttr((PyObject*) self, attr, value);
+    }
+    if (value == NULL) {
+        self->value = 0;
+        return 0;
+    }
+    PyObject *ivalue = PyNumber_Long(value);
+    if (ivalue == NULL)
+        return -1;
+    long v = PyLong_AsLong(ivalue);
+    Py_DECREF(ivalue);
+    if (v == -1 && PyErr_Occurred())
+        return -1;
+    self->value = v;
+    return 0;
+}
+
+static PyType_Slot HeapCTypeSetattr_slots[] = {
+    {Py_tp_init, heapctypesetattr_init},
+    {Py_tp_members, heapctypesetattr_members},
+    {Py_tp_setattro, heapctypesetattr_setattro},
+    {Py_tp_dealloc, heapctypesetattr_dealloc},
+    {Py_tp_doc, (char*)heapctypesetattr__doc__},
+    {0, 0},
+};
+
+static PyType_Spec HeapCTypeSetattr_spec = {
+    "_testcapi.HeapCTypeSetattr",
+    sizeof(HeapCTypeSetattrObject),
+    0,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    HeapCTypeSetattr_slots
+};
+
+int
+_PyTestCapi_Init_Heaptype(PyObject *m) {
+    _testcapimodule = PyModule_GetDef(m);
+
+    if (PyModule_AddFunctions(m, TestMethods) < 0) {
+        return -1;
+    }
+
+    PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
+    if (HeapDocCType == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
+
+    /* bpo-41832: Add a new type to test PyType_FromSpec()
+       now can accept a NULL tp_doc slot. */
+    PyObject *NullTpDocType = PyType_FromSpec(&NullTpDocType_spec);
+    if (NullTpDocType == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "NullTpDocType", NullTpDocType);
+
+    PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
+    if (HeapGcCType == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapGcCType", HeapGcCType);
+
+    PyObject *HeapCType = PyType_FromSpec(&HeapCType_spec);
+    if (HeapCType == NULL) {
+        return -1;
+    }
+    PyObject *subclass_bases = PyTuple_Pack(1, HeapCType);
+    if (subclass_bases == NULL) {
+        return -1;
+    }
+    PyObject *HeapCTypeSubclass = PyType_FromSpecWithBases(&HeapCTypeSubclass_spec, subclass_bases);
+    if (HeapCTypeSubclass == NULL) {
+        return -1;
+    }
+    Py_DECREF(subclass_bases);
+    PyModule_AddObject(m, "HeapCTypeSubclass", HeapCTypeSubclass);
+
+    PyObject *HeapCTypeWithDict = PyType_FromSpec(&HeapCTypeWithDict_spec);
+    if (HeapCTypeWithDict == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeWithDict", HeapCTypeWithDict);
+
+    PyObject *HeapCTypeWithNegativeDict = PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
+    if (HeapCTypeWithNegativeDict == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeWithNegativeDict", HeapCTypeWithNegativeDict);
+
+    PyObject *HeapCTypeWithWeakref = PyType_FromSpec(&HeapCTypeWithWeakref_spec);
+    if (HeapCTypeWithWeakref == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeWithWeakref", HeapCTypeWithWeakref);
+
+    PyObject *HeapCTypeWithBuffer = PyType_FromSpec(&HeapCTypeWithBuffer_spec);
+    if (HeapCTypeWithBuffer == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeWithBuffer", HeapCTypeWithBuffer);
+
+    PyObject *HeapCTypeSetattr = PyType_FromSpec(&HeapCTypeSetattr_spec);
+    if (HeapCTypeSetattr == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeSetattr", HeapCTypeSetattr);
+
+    PyObject *subclass_with_finalizer_bases = PyTuple_Pack(1, HeapCTypeSubclass);
+    if (subclass_with_finalizer_bases == NULL) {
+        return -1;
+    }
+    PyObject *HeapCTypeSubclassWithFinalizer = PyType_FromSpecWithBases(
+        &HeapCTypeSubclassWithFinalizer_spec, subclass_with_finalizer_bases);
+    if (HeapCTypeSubclassWithFinalizer == NULL) {
+        return -1;
+    }
+    Py_DECREF(subclass_with_finalizer_bases);
+    PyModule_AddObject(m, "HeapCTypeSubclassWithFinalizer", HeapCTypeSubclassWithFinalizer);
+
+    PyObject *HeapCTypeMetaclass = PyType_FromMetaclass(
+        &PyType_Type, m, &HeapCTypeMetaclass_spec, (PyObject *) &PyType_Type);
+    if (HeapCTypeMetaclass == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeMetaclass", HeapCTypeMetaclass);
+
+    PyObject *HeapCTypeMetaclassCustomNew = PyType_FromMetaclass(
+        &PyType_Type, m, &HeapCTypeMetaclassCustomNew_spec, (PyObject *) &PyType_Type);
+    if (HeapCTypeMetaclassCustomNew == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew);
+
+    return 0;
+}
index 54cddf4b0929f215a7a2835ac14de7efd484a259..e6d2ed23cb18e7d27d3c146ac133c19443fbfc1b 100644 (file)
@@ -1,3 +1,4 @@
 #include "Python.h"
 
 int _PyTestCapi_Init_Vectorcall(PyObject *module);
+int _PyTestCapi_Init_Heaptype(PyObject *module);
index b9f75d154ee5c05e4a06e356eedf7d31b815010c..f56b36a15e7940d8a53707a6bb42ff8586699296 100644 (file)
@@ -49,7 +49,6 @@
 
 // Forward declarations
 static struct PyModuleDef _testcapimodule;
-static PyType_Spec HeapTypeNameType_Spec;
 static PyObject *TestError;     /* set to exception object in init */
 
 
@@ -311,30 +310,6 @@ test_dict_inner(int count)
     }
 }
 
-static PyObject *pytype_fromspec_meta(PyObject* self, PyObject *meta)
-{
-    if (!PyType_Check(meta)) {
-        PyErr_SetString(
-            TestError,
-            "pytype_fromspec_meta: must be invoked with a type argument!");
-        return NULL;
-    }
-
-    PyType_Slot HeapCTypeViaMetaclass_slots[] = {
-        {0},
-    };
-
-    PyType_Spec HeapCTypeViaMetaclass_spec = {
-        "_testcapi.HeapCTypeViaMetaclass",
-        sizeof(PyObject),
-        0,
-        Py_TPFLAGS_DEFAULT,
-        HeapCTypeViaMetaclass_slots
-    };
-
-    return PyType_FromMetaclass(
-        (PyTypeObject *) meta, NULL, &HeapCTypeViaMetaclass_spec, NULL);
-}
 
 
 static PyObject*
@@ -1173,6 +1148,17 @@ test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored))
 }
 
 
+static PyType_Slot HeapTypeNameType_slots[] = {
+    {0},
+};
+
+static PyType_Spec HeapTypeNameType_Spec = {
+    .name = "_testcapi.HeapTypeNameType",
+    .basicsize = sizeof(PyObject),
+    .flags = Py_TPFLAGS_DEFAULT,
+    .slots = HeapTypeNameType_slots,
+};
+
 static PyObject *
 test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
@@ -1211,339 +1197,6 @@ test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored))
 }
 
 
-static PyType_Slot empty_type_slots[] = {
-    {0, 0},
-};
-
-static PyType_Spec MinimalMetaclass_spec = {
-    .name = "_testcapi.MinimalMetaclass",
-    .basicsize = sizeof(PyHeapTypeObject),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    .slots = empty_type_slots,
-};
-
-static PyType_Spec MinimalType_spec = {
-    .name = "_testcapi.MinimalSpecType",
-    .basicsize = 0,  // Updated later
-    .flags = Py_TPFLAGS_DEFAULT,
-    .slots = empty_type_slots,
-};
-
-static PyObject *
-test_from_spec_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
-    PyObject *metaclass = NULL;
-    PyObject *class = NULL;
-    PyObject *new = NULL;
-    PyObject *subclasses = NULL;
-    PyObject *result = NULL;
-    int r;
-
-    metaclass = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
-    if (metaclass == NULL) {
-        goto finally;
-    }
-    class = PyObject_CallFunction(metaclass, "s(){}", "TestClass");
-    if (class == NULL) {
-        goto finally;
-    }
-
-    MinimalType_spec.basicsize = (int)(((PyTypeObject*)class)->tp_basicsize);
-    new = PyType_FromSpecWithBases(&MinimalType_spec, class);
-    if (new == NULL) {
-        goto finally;
-    }
-    if (Py_TYPE(new) != (PyTypeObject*)metaclass) {
-        PyErr_SetString(PyExc_AssertionError,
-                "Metaclass not set properly!");
-        goto finally;
-    }
-
-    /* Assert that __subclasses__ is updated */
-    subclasses = PyObject_CallMethod(class, "__subclasses__", "");
-    if (!subclasses) {
-        goto finally;
-    }
-    r = PySequence_Contains(subclasses, new);
-    if (r < 0) {
-        goto finally;
-    }
-    if (r == 0) {
-        PyErr_SetString(PyExc_AssertionError,
-                "subclasses not set properly!");
-        goto finally;
-    }
-
-    result = Py_NewRef(Py_None);
-
-finally:
-    Py_XDECREF(metaclass);
-    Py_XDECREF(class);
-    Py_XDECREF(new);
-    Py_XDECREF(subclasses);
-    return result;
-}
-
-
-static PyObject *
-test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
-    PyObject *metaclass_a = NULL;
-    PyObject *metaclass_b = NULL;
-    PyObject *class_a = NULL;
-    PyObject *class_b = NULL;
-    PyObject *bases = NULL;
-    PyObject *new = NULL;
-    PyObject *meta_error_string = NULL;
-    PyObject *exc_type = NULL;
-    PyObject *exc_value = NULL;
-    PyObject *exc_traceback = NULL;
-    PyObject *result = NULL;
-
-    metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
-    if (metaclass_a == NULL) {
-        goto finally;
-    }
-    metaclass_b = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
-    if (metaclass_b == NULL) {
-        goto finally;
-    }
-    class_a = PyObject_CallFunction(metaclass_a, "s(){}", "TestClassA");
-    if (class_a == NULL) {
-        goto finally;
-    }
-
-    class_b = PyObject_CallFunction(metaclass_b, "s(){}", "TestClassB");
-    if (class_b == NULL) {
-        goto finally;
-    }
-
-    bases = PyTuple_Pack(2, class_a, class_b);
-    if (bases == NULL) {
-        goto finally;
-    }
-
-    /*
-     * The following should raise a TypeError due to a MetaClass conflict.
-     */
-    new = PyType_FromSpecWithBases(&MinimalType_spec, bases);
-    if (new != NULL) {
-        PyErr_SetString(PyExc_AssertionError,
-                "MetaType conflict not recognized by PyType_FromSpecWithBases");
-            goto finally;
-    }
-
-    // Assert that the correct exception was raised
-    if (PyErr_ExceptionMatches(PyExc_TypeError)) {
-        PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
-
-        meta_error_string = PyUnicode_FromString("metaclass conflict:");
-        if (meta_error_string == NULL) {
-            goto finally;
-        }
-        int res = PyUnicode_Contains(exc_value, meta_error_string);
-        if (res < 0) {
-            goto finally;
-        }
-        if (res == 0) {
-            PyErr_SetString(PyExc_AssertionError,
-                    "TypeError did not inlclude expected message.");
-            goto finally;
-        }
-        result = Py_NewRef(Py_None);
-    }
-finally:
-    Py_XDECREF(metaclass_a);
-    Py_XDECREF(metaclass_b);
-    Py_XDECREF(bases);
-    Py_XDECREF(new);
-    Py_XDECREF(meta_error_string);
-    Py_XDECREF(exc_type);
-    Py_XDECREF(exc_value);
-    Py_XDECREF(exc_traceback);
-    Py_XDECREF(class_a);
-    Py_XDECREF(class_b);
-    return result;
-}
-
-
-static PyObject *
-simple_str(PyObject *self) {
-    return PyUnicode_FromString("<test>");
-}
-
-
-static PyObject *
-test_type_from_ephemeral_spec(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
-    // Test that a heap type can be created from a spec that's later deleted
-    // (along with all its contents).
-    // All necessary data must be copied and held by the class
-    PyType_Spec *spec = NULL;
-    char *name = NULL;
-    char *doc = NULL;
-    PyType_Slot *slots = NULL;
-    PyObject *class = NULL;
-    PyObject *instance = NULL;
-    PyObject *obj = NULL;
-    PyObject *result = NULL;
-
-    /* create a spec (and all its contents) on the heap */
-
-    const char NAME[] = "testcapi._Test";
-    const char DOC[] = "a test class";
-
-    spec = PyMem_New(PyType_Spec, 1);
-    if (spec == NULL) {
-        PyErr_NoMemory();
-        goto finally;
-    }
-    name = PyMem_New(char, sizeof(NAME));
-    if (name == NULL) {
-        PyErr_NoMemory();
-        goto finally;
-    }
-    memcpy(name, NAME, sizeof(NAME));
-
-    doc = PyMem_New(char, sizeof(DOC));
-    if (doc == NULL) {
-        PyErr_NoMemory();
-        goto finally;
-    }
-    memcpy(doc, DOC, sizeof(DOC));
-
-    spec->name = name;
-    spec->basicsize = sizeof(PyObject);
-    spec->itemsize = 0;
-    spec->flags = Py_TPFLAGS_DEFAULT;
-    slots = PyMem_New(PyType_Slot, 3);
-    if (slots == NULL) {
-        PyErr_NoMemory();
-        goto finally;
-    }
-    slots[0].slot = Py_tp_str;
-    slots[0].pfunc = simple_str;
-    slots[1].slot = Py_tp_doc;
-    slots[1].pfunc = doc;
-    slots[2].slot = 0;
-    slots[2].pfunc = NULL;
-    spec->slots = slots;
-
-    /* create the class */
-
-    class = PyType_FromSpec(spec);
-    if (class == NULL) {
-        goto finally;
-    }
-
-    /* deallocate the spec (and all contents) */
-
-    // (Explicitly ovewrite memory before freeing,
-    // so bugs show themselves even without the debug allocator's help.)
-    memset(spec, 0xdd, sizeof(PyType_Spec));
-    PyMem_Del(spec);
-    spec = NULL;
-    memset(name, 0xdd, sizeof(NAME));
-    PyMem_Del(name);
-    name = NULL;
-    memset(doc, 0xdd, sizeof(DOC));
-    PyMem_Del(doc);
-    doc = NULL;
-    memset(slots, 0xdd, 3 * sizeof(PyType_Slot));
-    PyMem_Del(slots);
-    slots = NULL;
-
-    /* check that everything works */
-
-    PyTypeObject *class_tp = (PyTypeObject *)class;
-    PyHeapTypeObject *class_ht = (PyHeapTypeObject *)class;
-    assert(strcmp(class_tp->tp_name, "testcapi._Test") == 0);
-    assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_name), "_Test") == 0);
-    assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_qualname), "_Test") == 0);
-    assert(strcmp(class_tp->tp_doc, "a test class") == 0);
-
-    // call and check __str__
-    instance = PyObject_CallNoArgs(class);
-    if (instance == NULL) {
-        goto finally;
-    }
-    obj = PyObject_Str(instance);
-    if (obj == NULL) {
-        goto finally;
-    }
-    assert(strcmp(PyUnicode_AsUTF8(obj), "<test>") == 0);
-    Py_CLEAR(obj);
-
-    result = Py_NewRef(Py_None);
-  finally:
-    PyMem_Del(spec);
-    PyMem_Del(name);
-    PyMem_Del(doc);
-    PyMem_Del(slots);
-    Py_XDECREF(class);
-    Py_XDECREF(instance);
-    Py_XDECREF(obj);
-    return result;
-}
-
-PyType_Slot repeated_doc_slots[] = {
-    {Py_tp_doc, "A class used for testsĀ·"},
-    {Py_tp_doc, "A class used for tests"},
-    {0, 0},
-};
-
-PyType_Spec repeated_doc_slots_spec = {
-    .name = "RepeatedDocSlotClass",
-    .basicsize = sizeof(PyObject),
-    .slots = repeated_doc_slots,
-};
-
-typedef struct {
-    PyObject_HEAD
-    int data;
-} HeapCTypeWithDataObject;
-
-
-static struct PyMemberDef members_to_repeat[] = {
-    {"T_INT", T_INT, offsetof(HeapCTypeWithDataObject, data), 0, NULL},
-    {NULL}
-};
-
-PyType_Slot repeated_members_slots[] = {
-    {Py_tp_members, members_to_repeat},
-    {Py_tp_members, members_to_repeat},
-    {0, 0},
-};
-
-PyType_Spec repeated_members_slots_spec = {
-    .name = "RepeatedMembersSlotClass",
-    .basicsize = sizeof(HeapCTypeWithDataObject),
-    .slots = repeated_members_slots,
-};
-
-static PyObject *
-create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj)
-{
-    PyObject *class = NULL;
-    int variant = PyLong_AsLong(variant_obj);
-    if (PyErr_Occurred()) {
-        return NULL;
-    }
-    switch (variant) {
-        case 0:
-            class = PyType_FromSpec(&repeated_doc_slots_spec);
-            break;
-        case 1:
-            class = PyType_FromSpec(&repeated_members_slots_spec);
-            break;
-        default:
-            PyErr_SetString(PyExc_ValueError, "bad test variant");
-            break;
-        }
-    return class;
-}
-
-
 static PyObject *
 test_get_type_qualname(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
@@ -6054,7 +5707,6 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
 }
 
 
-static PyObject *negative_dictoffset(PyObject *, PyObject *);
 static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
 static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*);
 static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*);
@@ -6109,7 +5761,6 @@ static PyMethodDef TestMethods[] = {
     {"test_long_numbits",       test_long_numbits,               METH_NOARGS},
     {"test_k_code",             test_k_code,                     METH_NOARGS},
     {"test_empty_argparse",     test_empty_argparse,             METH_NOARGS},
-    {"pytype_fromspec_meta",    pytype_fromspec_meta,            METH_O},
     {"parse_tuple_and_keywords", parse_tuple_and_keywords, METH_VARARGS},
     {"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS},
     {"pyobject_str_from_null",  pyobject_str_from_null, METH_NOARGS},
@@ -6128,20 +5779,11 @@ static PyMethodDef TestMethods[] = {
     {"getbuffer_with_null_view", getbuffer_with_null_view,       METH_O},
     {"PyBuffer_SizeFromFormat",  test_PyBuffer_SizeFromFormat,   METH_VARARGS},
     {"test_buildvalue_N",        test_buildvalue_N,              METH_NOARGS},
-    {"negative_dictoffset",      negative_dictoffset,            METH_NOARGS},
     {"test_buildvalue_issue38913", test_buildvalue_issue38913,   METH_NOARGS},
     {"get_args",                  get_args,                      METH_VARARGS},
     {"test_get_statictype_slots", test_get_statictype_slots,     METH_NOARGS},
     {"test_get_type_name",        test_get_type_name,            METH_NOARGS},
     {"test_get_type_qualname",    test_get_type_qualname,        METH_NOARGS},
-    {"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS},
-    {"create_type_from_repeated_slots",
-        create_type_from_repeated_slots, METH_O},
-    {"test_from_spec_metatype_inheritance", test_from_spec_metatype_inheritance,
-     METH_NOARGS},
-    {"test_from_spec_invalid_metatype_inheritance",
-     test_from_spec_invalid_metatype_inheritance,
-     METH_NOARGS},
     {"get_kwargs", _PyCFunction_CAST(get_kwargs),
       METH_VARARGS|METH_KEYWORDS},
     {"getargs_tuple",           getargs_tuple,                   METH_VARARGS},
@@ -6914,509 +6556,6 @@ static PyTypeObject Generic_Type = {
     .tp_methods = generic_methods,
 };
 
-PyDoc_STRVAR(heapdocctype__doc__,
-"HeapDocCType(arg1, arg2)\n"
-"--\n"
-"\n"
-"somedoc");
-
-typedef struct {
-    PyObject_HEAD
-} HeapDocCTypeObject;
-
-static PyType_Slot HeapDocCType_slots[] = {
-    {Py_tp_doc, (char*)heapdocctype__doc__},
-    {0},
-};
-
-static PyType_Spec HeapDocCType_spec = {
-    "_testcapi.HeapDocCType",
-    sizeof(HeapDocCTypeObject),
-    0,
-    Py_TPFLAGS_DEFAULT,
-    HeapDocCType_slots
-};
-
-typedef struct {
-    PyObject_HEAD
-} HeapTypeNameObject;
-
-static PyType_Slot HeapTypeNameType_slots[] = {
-    {0},
-};
-
-static PyType_Spec HeapTypeNameType_Spec = {
-    .name = "_testcapi.HeapTypeNameType",
-    .basicsize = sizeof(HeapTypeNameObject),
-    .flags = Py_TPFLAGS_DEFAULT,
-    .slots = HeapTypeNameType_slots,
-};
-
-typedef struct {
-    PyObject_HEAD
-} NullTpDocTypeObject;
-
-static PyType_Slot NullTpDocType_slots[] = {
-    {Py_tp_doc, NULL},
-    {0, 0},
-};
-
-static PyType_Spec NullTpDocType_spec = {
-    "_testcapi.NullTpDocType",
-    sizeof(NullTpDocTypeObject),
-    0,
-    Py_TPFLAGS_DEFAULT,
-    NullTpDocType_slots
-};
-
-
-PyDoc_STRVAR(heapgctype__doc__,
-"A heap type with GC, and with overridden dealloc.\n\n"
-"The 'value' attribute is set to 10 in __init__.");
-
-typedef struct {
-    PyObject_HEAD
-    int value;
-} HeapCTypeObject;
-
-static struct PyMemberDef heapctype_members[] = {
-    {"value", T_INT, offsetof(HeapCTypeObject, value)},
-    {NULL} /* Sentinel */
-};
-
-static int
-heapctype_init(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    ((HeapCTypeObject *)self)->value = 10;
-    return 0;
-}
-
-static int
-heapgcctype_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
-{
-    Py_VISIT(Py_TYPE(self));
-    return 0;
-}
-
-static void
-heapgcctype_dealloc(HeapCTypeObject *self)
-{
-    PyTypeObject *tp = Py_TYPE(self);
-    PyObject_GC_UnTrack(self);
-    PyObject_GC_Del(self);
-    Py_DECREF(tp);
-}
-
-static PyType_Slot HeapGcCType_slots[] = {
-    {Py_tp_init, heapctype_init},
-    {Py_tp_members, heapctype_members},
-    {Py_tp_dealloc, heapgcctype_dealloc},
-    {Py_tp_traverse, heapgcctype_traverse},
-    {Py_tp_doc, (char*)heapgctype__doc__},
-    {0, 0},
-};
-
-static PyType_Spec HeapGcCType_spec = {
-    "_testcapi.HeapGcCType",
-    sizeof(HeapCTypeObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
-    HeapGcCType_slots
-};
-
-PyDoc_STRVAR(heapctype__doc__,
-"A heap type without GC, but with overridden dealloc.\n\n"
-"The 'value' attribute is set to 10 in __init__.");
-
-static void
-heapctype_dealloc(HeapCTypeObject *self)
-{
-    PyTypeObject *tp = Py_TYPE(self);
-    PyObject_Free(self);
-    Py_DECREF(tp);
-}
-
-static PyType_Slot HeapCType_slots[] = {
-    {Py_tp_init, heapctype_init},
-    {Py_tp_members, heapctype_members},
-    {Py_tp_dealloc, heapctype_dealloc},
-    {Py_tp_doc, (char*)heapctype__doc__},
-    {0, 0},
-};
-
-static PyType_Spec HeapCType_spec = {
-    "_testcapi.HeapCType",
-    sizeof(HeapCTypeObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCType_slots
-};
-
-PyDoc_STRVAR(heapctypesubclass__doc__,
-"Subclass of HeapCType, without GC.\n\n"
-"__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
-
-typedef struct {
-    HeapCTypeObject base;
-    int value2;
-} HeapCTypeSubclassObject;
-
-static int
-heapctypesubclass_init(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    /* Call __init__ of the superclass */
-    if (heapctype_init(self, args, kwargs) < 0) {
-        return -1;
-    }
-    /* Initialize additional element */
-    ((HeapCTypeSubclassObject *)self)->value2 = 20;
-    return 0;
-}
-
-static struct PyMemberDef heapctypesubclass_members[] = {
-    {"value2", T_INT, offsetof(HeapCTypeSubclassObject, value2)},
-    {NULL} /* Sentinel */
-};
-
-static PyType_Slot HeapCTypeSubclass_slots[] = {
-    {Py_tp_init, heapctypesubclass_init},
-    {Py_tp_members, heapctypesubclass_members},
-    {Py_tp_doc, (char*)heapctypesubclass__doc__},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeSubclass_spec = {
-    "_testcapi.HeapCTypeSubclass",
-    sizeof(HeapCTypeSubclassObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCTypeSubclass_slots
-};
-
-PyDoc_STRVAR(heapctypewithbuffer__doc__,
-"Heap type with buffer support.\n\n"
-"The buffer is set to [b'1', b'2', b'3', b'4']");
-
-typedef struct {
-    HeapCTypeObject base;
-    char buffer[4];
-} HeapCTypeWithBufferObject;
-
-static int
-heapctypewithbuffer_getbuffer(HeapCTypeWithBufferObject *self, Py_buffer *view, int flags)
-{
-    self->buffer[0] = '1';
-    self->buffer[1] = '2';
-    self->buffer[2] = '3';
-    self->buffer[3] = '4';
-    return PyBuffer_FillInfo(
-        view, (PyObject*)self, (void *)self->buffer, 4, 1, flags);
-}
-
-static void
-heapctypewithbuffer_releasebuffer(HeapCTypeWithBufferObject *self, Py_buffer *view)
-{
-    assert(view->obj == (void*) self);
-}
-
-static PyType_Slot HeapCTypeWithBuffer_slots[] = {
-    {Py_bf_getbuffer, heapctypewithbuffer_getbuffer},
-    {Py_bf_releasebuffer, heapctypewithbuffer_releasebuffer},
-    {Py_tp_doc, (char*)heapctypewithbuffer__doc__},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeWithBuffer_spec = {
-    "_testcapi.HeapCTypeWithBuffer",
-    sizeof(HeapCTypeWithBufferObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCTypeWithBuffer_slots
-};
-
-PyDoc_STRVAR(heapctypesubclasswithfinalizer__doc__,
-"Subclass of HeapCType with a finalizer that reassigns __class__.\n\n"
-"__class__ is set to plain HeapCTypeSubclass during finalization.\n"
-"__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
-
-static int
-heapctypesubclasswithfinalizer_init(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    PyTypeObject *base = (PyTypeObject *)PyType_GetSlot(Py_TYPE(self), Py_tp_base);
-    initproc base_init = PyType_GetSlot(base, Py_tp_init);
-    base_init(self, args, kwargs);
-    return 0;
-}
-
-static void
-heapctypesubclasswithfinalizer_finalize(PyObject *self)
-{
-    PyObject *error_type, *error_value, *error_traceback, *m;
-    PyObject *oldtype = NULL, *newtype = NULL, *refcnt = NULL;
-
-    /* Save the current exception, if any. */
-    PyErr_Fetch(&error_type, &error_value, &error_traceback);
-
-    m = PyState_FindModule(&_testcapimodule);
-    if (m == NULL) {
-        goto cleanup_finalize;
-    }
-    oldtype = PyObject_GetAttrString(m, "HeapCTypeSubclassWithFinalizer");
-    newtype = PyObject_GetAttrString(m, "HeapCTypeSubclass");
-    if (oldtype == NULL || newtype == NULL) {
-        goto cleanup_finalize;
-    }
-
-    if (PyObject_SetAttrString(self, "__class__", newtype) < 0) {
-        goto cleanup_finalize;
-    }
-    refcnt = PyLong_FromSsize_t(Py_REFCNT(oldtype));
-    if (refcnt == NULL) {
-        goto cleanup_finalize;
-    }
-    if (PyObject_SetAttrString(oldtype, "refcnt_in_del", refcnt) < 0) {
-        goto cleanup_finalize;
-    }
-    Py_DECREF(refcnt);
-    refcnt = PyLong_FromSsize_t(Py_REFCNT(newtype));
-    if (refcnt == NULL) {
-        goto cleanup_finalize;
-    }
-    if (PyObject_SetAttrString(newtype, "refcnt_in_del", refcnt) < 0) {
-        goto cleanup_finalize;
-    }
-
-cleanup_finalize:
-    Py_XDECREF(oldtype);
-    Py_XDECREF(newtype);
-    Py_XDECREF(refcnt);
-
-    /* Restore the saved exception. */
-    PyErr_Restore(error_type, error_value, error_traceback);
-}
-
-static PyType_Slot HeapCTypeSubclassWithFinalizer_slots[] = {
-    {Py_tp_init, heapctypesubclasswithfinalizer_init},
-    {Py_tp_members, heapctypesubclass_members},
-    {Py_tp_finalize, heapctypesubclasswithfinalizer_finalize},
-    {Py_tp_doc, (char*)heapctypesubclasswithfinalizer__doc__},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeSubclassWithFinalizer_spec = {
-    "_testcapi.HeapCTypeSubclassWithFinalizer",
-    sizeof(HeapCTypeSubclassObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE,
-    HeapCTypeSubclassWithFinalizer_slots
-};
-
-static PyType_Slot HeapCTypeMetaclass_slots[] = {
-    {0},
-};
-
-static PyType_Spec HeapCTypeMetaclass_spec = {
-    "_testcapi.HeapCTypeMetaclass",
-    sizeof(PyHeapTypeObject),
-    sizeof(PyMemberDef),
-    Py_TPFLAGS_DEFAULT,
-    HeapCTypeMetaclass_slots
-};
-
-static PyObject *
-heap_ctype_metaclass_custom_tp_new(PyTypeObject *tp, PyObject *args, PyObject *kwargs)
-{
-    return PyType_Type.tp_new(tp, args, kwargs);
-}
-
-static PyType_Slot HeapCTypeMetaclassCustomNew_slots[] = {
-    { Py_tp_new, heap_ctype_metaclass_custom_tp_new },
-    {0},
-};
-
-static PyType_Spec HeapCTypeMetaclassCustomNew_spec = {
-    "_testcapi.HeapCTypeMetaclassCustomNew",
-    sizeof(PyHeapTypeObject),
-    sizeof(PyMemberDef),
-    Py_TPFLAGS_DEFAULT,
-    HeapCTypeMetaclassCustomNew_slots
-};
-
-
-typedef struct {
-    PyObject_HEAD
-    PyObject *dict;
-} HeapCTypeWithDictObject;
-
-static void
-heapctypewithdict_dealloc(HeapCTypeWithDictObject* self)
-{
-
-    PyTypeObject *tp = Py_TYPE(self);
-    Py_XDECREF(self->dict);
-    PyObject_Free(self);
-    Py_DECREF(tp);
-}
-
-static PyGetSetDef heapctypewithdict_getsetlist[] = {
-    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
-    {NULL} /* Sentinel */
-};
-
-static struct PyMemberDef heapctypewithdict_members[] = {
-    {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
-    {"__dictoffset__", T_PYSSIZET, offsetof(HeapCTypeWithDictObject, dict), READONLY},
-    {NULL} /* Sentinel */
-};
-
-static PyType_Slot HeapCTypeWithDict_slots[] = {
-    {Py_tp_members, heapctypewithdict_members},
-    {Py_tp_getset, heapctypewithdict_getsetlist},
-    {Py_tp_dealloc, heapctypewithdict_dealloc},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeWithDict_spec = {
-    "_testcapi.HeapCTypeWithDict",
-    sizeof(HeapCTypeWithDictObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCTypeWithDict_slots
-};
-
-static struct PyMemberDef heapctypewithnegativedict_members[] = {
-    {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
-    {"__dictoffset__", T_PYSSIZET, -(Py_ssize_t)sizeof(void*), READONLY},
-    {NULL} /* Sentinel */
-};
-
-static PyType_Slot HeapCTypeWithNegativeDict_slots[] = {
-    {Py_tp_members, heapctypewithnegativedict_members},
-    {Py_tp_getset, heapctypewithdict_getsetlist},
-    {Py_tp_dealloc, heapctypewithdict_dealloc},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeWithNegativeDict_spec = {
-    "_testcapi.HeapCTypeWithNegativeDict",
-    sizeof(HeapCTypeWithDictObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCTypeWithNegativeDict_slots
-};
-
-typedef struct {
-    PyObject_HEAD
-    PyObject *weakreflist;
-} HeapCTypeWithWeakrefObject;
-
-static struct PyMemberDef heapctypewithweakref_members[] = {
-    {"weakreflist", T_OBJECT, offsetof(HeapCTypeWithWeakrefObject, weakreflist)},
-    {"__weaklistoffset__", T_PYSSIZET,
-      offsetof(HeapCTypeWithWeakrefObject, weakreflist), READONLY},
-    {NULL} /* Sentinel */
-};
-
-static void
-heapctypewithweakref_dealloc(HeapCTypeWithWeakrefObject* self)
-{
-
-    PyTypeObject *tp = Py_TYPE(self);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *) self);
-    Py_XDECREF(self->weakreflist);
-    PyObject_Free(self);
-    Py_DECREF(tp);
-}
-
-static PyType_Slot HeapCTypeWithWeakref_slots[] = {
-    {Py_tp_members, heapctypewithweakref_members},
-    {Py_tp_dealloc, heapctypewithweakref_dealloc},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeWithWeakref_spec = {
-    "_testcapi.HeapCTypeWithWeakref",
-    sizeof(HeapCTypeWithWeakrefObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCTypeWithWeakref_slots
-};
-
-PyDoc_STRVAR(heapctypesetattr__doc__,
-"A heap type without GC, but with overridden __setattr__.\n\n"
-"The 'value' attribute is set to 10 in __init__ and updated via attribute setting.");
-
-typedef struct {
-    PyObject_HEAD
-    long value;
-} HeapCTypeSetattrObject;
-
-static struct PyMemberDef heapctypesetattr_members[] = {
-    {"pvalue", T_LONG, offsetof(HeapCTypeSetattrObject, value)},
-    {NULL} /* Sentinel */
-};
-
-static int
-heapctypesetattr_init(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-    ((HeapCTypeSetattrObject *)self)->value = 10;
-    return 0;
-}
-
-static void
-heapctypesetattr_dealloc(HeapCTypeSetattrObject *self)
-{
-    PyTypeObject *tp = Py_TYPE(self);
-    PyObject_Free(self);
-    Py_DECREF(tp);
-}
-
-static int
-heapctypesetattr_setattro(HeapCTypeSetattrObject *self, PyObject *attr, PyObject *value)
-{
-    PyObject *svalue = PyUnicode_FromString("value");
-    if (svalue == NULL)
-        return -1;
-    int eq = PyObject_RichCompareBool(svalue, attr, Py_EQ);
-    Py_DECREF(svalue);
-    if (eq < 0)
-        return -1;
-    if (!eq) {
-        return PyObject_GenericSetAttr((PyObject*) self, attr, value);
-    }
-    if (value == NULL) {
-        self->value = 0;
-        return 0;
-    }
-    PyObject *ivalue = PyNumber_Long(value);
-    if (ivalue == NULL)
-        return -1;
-    long v = PyLong_AsLong(ivalue);
-    Py_DECREF(ivalue);
-    if (v == -1 && PyErr_Occurred())
-        return -1;
-    self->value = v;
-    return 0;
-}
-
-static PyType_Slot HeapCTypeSetattr_slots[] = {
-    {Py_tp_init, heapctypesetattr_init},
-    {Py_tp_members, heapctypesetattr_members},
-    {Py_tp_setattro, heapctypesetattr_setattro},
-    {Py_tp_dealloc, heapctypesetattr_dealloc},
-    {Py_tp_doc, (char*)heapctypesetattr__doc__},
-    {0, 0},
-};
-
-static PyType_Spec HeapCTypeSetattr_spec = {
-    "_testcapi.HeapCTypeSetattr",
-    sizeof(HeapCTypeSetattrObject),
-    0,
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-    HeapCTypeSetattr_slots
-};
-
 static PyMethodDef meth_instance_methods[] = {
     {"meth_varargs", meth_varargs, METH_VARARGS},
     {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS},
@@ -7656,97 +6795,6 @@ PyInit__testcapi(void)
     Py_INCREF(TestError);
     PyModule_AddObject(m, "error", TestError);
 
-    PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
-    if (HeapDocCType == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
-
-    /* bpo-41832: Add a new type to test PyType_FromSpec()
-       now can accept a NULL tp_doc slot. */
-    PyObject *NullTpDocType = PyType_FromSpec(&NullTpDocType_spec);
-    if (NullTpDocType == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "NullTpDocType", NullTpDocType);
-
-    PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
-    if (HeapGcCType == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapGcCType", HeapGcCType);
-
-    PyObject *HeapCType = PyType_FromSpec(&HeapCType_spec);
-    if (HeapCType == NULL) {
-        return NULL;
-    }
-    PyObject *subclass_bases = PyTuple_Pack(1, HeapCType);
-    if (subclass_bases == NULL) {
-        return NULL;
-    }
-    PyObject *HeapCTypeSubclass = PyType_FromSpecWithBases(&HeapCTypeSubclass_spec, subclass_bases);
-    if (HeapCTypeSubclass == NULL) {
-        return NULL;
-    }
-    Py_DECREF(subclass_bases);
-    PyModule_AddObject(m, "HeapCTypeSubclass", HeapCTypeSubclass);
-
-    PyObject *HeapCTypeWithDict = PyType_FromSpec(&HeapCTypeWithDict_spec);
-    if (HeapCTypeWithDict == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeWithDict", HeapCTypeWithDict);
-
-    PyObject *HeapCTypeWithNegativeDict = PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
-    if (HeapCTypeWithNegativeDict == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeWithNegativeDict", HeapCTypeWithNegativeDict);
-
-    PyObject *HeapCTypeWithWeakref = PyType_FromSpec(&HeapCTypeWithWeakref_spec);
-    if (HeapCTypeWithWeakref == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeWithWeakref", HeapCTypeWithWeakref);
-
-    PyObject *HeapCTypeWithBuffer = PyType_FromSpec(&HeapCTypeWithBuffer_spec);
-    if (HeapCTypeWithBuffer == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeWithBuffer", HeapCTypeWithBuffer);
-
-    PyObject *HeapCTypeSetattr = PyType_FromSpec(&HeapCTypeSetattr_spec);
-    if (HeapCTypeSetattr == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeSetattr", HeapCTypeSetattr);
-
-    PyObject *subclass_with_finalizer_bases = PyTuple_Pack(1, HeapCTypeSubclass);
-    if (subclass_with_finalizer_bases == NULL) {
-        return NULL;
-    }
-    PyObject *HeapCTypeSubclassWithFinalizer = PyType_FromSpecWithBases(
-        &HeapCTypeSubclassWithFinalizer_spec, subclass_with_finalizer_bases);
-    if (HeapCTypeSubclassWithFinalizer == NULL) {
-        return NULL;
-    }
-    Py_DECREF(subclass_with_finalizer_bases);
-    PyModule_AddObject(m, "HeapCTypeSubclassWithFinalizer", HeapCTypeSubclassWithFinalizer);
-
-    PyObject *HeapCTypeMetaclass = PyType_FromMetaclass(
-        &PyType_Type, m, &HeapCTypeMetaclass_spec, (PyObject *) &PyType_Type);
-    if (HeapCTypeMetaclass == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeMetaclass", HeapCTypeMetaclass);
-
-    PyObject *HeapCTypeMetaclassCustomNew = PyType_FromMetaclass(
-        &PyType_Type, m, &HeapCTypeMetaclassCustomNew_spec, (PyObject *) &PyType_Type);
-    if (HeapCTypeMetaclassCustomNew == NULL) {
-        return NULL;
-    }
-    PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew);
-
     if (PyType_Ready(&ContainerNoGC_type) < 0) {
         return NULL;
     }
@@ -7759,17 +6807,14 @@ PyInit__testcapi(void)
     if (_PyTestCapi_Init_Vectorcall(m) < 0) {
         return NULL;
     }
+    if (_PyTestCapi_Init_Heaptype(m) < 0) {
+        return NULL;
+    }
 
     PyState_AddModule(m, &_testcapimodule);
     return m;
 }
 
-static PyObject *
-negative_dictoffset(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
-    return PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
-}
-
 /* Test the C API exposed when PY_SSIZE_T_CLEAN is not defined */
 
 #undef Py_BuildValue
index 07e23557e1dba38be7ad7eee5557fee8330f788b..a88540cab19f9a3b2cf88c25af3fe4e124950e70 100644 (file)
@@ -95,6 +95,7 @@
   <ItemGroup>
     <ClCompile Include="..\Modules\_testcapimodule.c" />
     <ClCompile Include="..\Modules\_testcapi\vectorcall.c" />
+    <ClCompile Include="..\Modules\_testcapi\heaptype.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc" />
index 82fce057e2e27b6463fd7447c3f9be4bdfe7895e..a43ab5ea0ff9416102b4f1260520a3b0dddc5694 100644 (file)
@@ -15,6 +15,9 @@
     <ClCompile Include="..\Modules\_testcapi\vectorcall.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\Modules\_testcapi\heaptype.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\PC\python_nt.rc">