(root)/
Python-3.12.0/
Modules/
_testcapi/
heaptype.c
       1  #include "parts.h"
       2  #include "structmember.h"         // PyMemberDef
       3  
       4  static struct PyModuleDef *_testcapimodule = NULL;  // set at initialization
       5  
       6  /* Tests for heap types (PyType_From*) */
       7  
       8  static PyObject *pytype_fromspec_meta(PyObject* self, PyObject *meta)
       9  {
      10      if (!PyType_Check(meta)) {
      11          PyErr_SetString(
      12              PyExc_TypeError,
      13              "pytype_fromspec_meta: must be invoked with a type argument!");
      14          return NULL;
      15      }
      16  
      17      PyType_Slot HeapCTypeViaMetaclass_slots[] = {
      18          {0},
      19      };
      20  
      21      PyType_Spec HeapCTypeViaMetaclass_spec = {
      22          "_testcapi.HeapCTypeViaMetaclass",
      23          sizeof(PyObject),
      24          0,
      25          Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
      26          HeapCTypeViaMetaclass_slots
      27      };
      28  
      29      return PyType_FromMetaclass(
      30          (PyTypeObject *) meta, NULL, &HeapCTypeViaMetaclass_spec, NULL);
      31  }
      32  
      33  
      34  static PyType_Slot empty_type_slots[] = {
      35      {0, 0},
      36  };
      37  
      38  static PyType_Spec MinimalMetaclass_spec = {
      39      .name = "_testcapi.MinimalMetaclass",
      40      .basicsize = sizeof(PyHeapTypeObject),
      41      .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
      42      .slots = empty_type_slots,
      43  };
      44  
      45  static PyType_Spec MinimalType_spec = {
      46      .name = "_testcapi.MinimalSpecType",
      47      .basicsize = 0,  // Updated later
      48      .flags = Py_TPFLAGS_DEFAULT,
      49      .slots = empty_type_slots,
      50  };
      51  
      52  
      53  static PyObject *
      54  test_from_spec_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
      55  {
      56      PyObject *metaclass = NULL;
      57      PyObject *class = NULL;
      58      PyObject *new = NULL;
      59      PyObject *subclasses = NULL;
      60      PyObject *result = NULL;
      61      int r;
      62  
      63      metaclass = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
      64      if (metaclass == NULL) {
      65          goto finally;
      66      }
      67      class = PyObject_CallFunction(metaclass, "s(){}", "TestClass");
      68      if (class == NULL) {
      69          goto finally;
      70      }
      71  
      72      MinimalType_spec.basicsize = (int)(((PyTypeObject*)class)->tp_basicsize);
      73      new = PyType_FromSpecWithBases(&MinimalType_spec, class);
      74      if (new == NULL) {
      75          goto finally;
      76      }
      77      if (Py_TYPE(new) != (PyTypeObject*)metaclass) {
      78          PyErr_SetString(PyExc_AssertionError,
      79                  "Metaclass not set properly!");
      80          goto finally;
      81      }
      82  
      83      /* Assert that __subclasses__ is updated */
      84      subclasses = PyObject_CallMethod(class, "__subclasses__", "");
      85      if (!subclasses) {
      86          goto finally;
      87      }
      88      r = PySequence_Contains(subclasses, new);
      89      if (r < 0) {
      90          goto finally;
      91      }
      92      if (r == 0) {
      93          PyErr_SetString(PyExc_AssertionError,
      94                  "subclasses not set properly!");
      95          goto finally;
      96      }
      97  
      98      result = Py_NewRef(Py_None);
      99  
     100  finally:
     101      Py_XDECREF(metaclass);
     102      Py_XDECREF(class);
     103      Py_XDECREF(new);
     104      Py_XDECREF(subclasses);
     105      return result;
     106  }
     107  
     108  
     109  static PyObject *
     110  test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
     111  {
     112      PyObject *metaclass_a = NULL;
     113      PyObject *metaclass_b = NULL;
     114      PyObject *class_a = NULL;
     115      PyObject *class_b = NULL;
     116      PyObject *bases = NULL;
     117      PyObject *new = NULL;
     118      PyObject *meta_error_string = NULL;
     119      PyObject *exc = NULL;
     120      PyObject *result = NULL;
     121      PyObject *message = NULL;
     122      PyObject *args = NULL;
     123  
     124      metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
     125      if (metaclass_a == NULL) {
     126          goto finally;
     127      }
     128      metaclass_b = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
     129      if (metaclass_b == NULL) {
     130          goto finally;
     131      }
     132      class_a = PyObject_CallFunction(metaclass_a, "s(){}", "TestClassA");
     133      if (class_a == NULL) {
     134          goto finally;
     135      }
     136  
     137      class_b = PyObject_CallFunction(metaclass_b, "s(){}", "TestClassB");
     138      if (class_b == NULL) {
     139          goto finally;
     140      }
     141  
     142      bases = PyTuple_Pack(2, class_a, class_b);
     143      if (bases == NULL) {
     144          goto finally;
     145      }
     146  
     147      /*
     148       * The following should raise a TypeError due to a MetaClass conflict.
     149       */
     150      new = PyType_FromSpecWithBases(&MinimalType_spec, bases);
     151      if (new != NULL) {
     152          PyErr_SetString(PyExc_AssertionError,
     153                  "MetaType conflict not recognized by PyType_FromSpecWithBases");
     154              goto finally;
     155      }
     156  
     157      // Assert that the correct exception was raised
     158      if (PyErr_ExceptionMatches(PyExc_TypeError)) {
     159          exc = PyErr_GetRaisedException();
     160          args = PyException_GetArgs(exc);
     161          if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
     162              PyErr_SetString(PyExc_AssertionError,
     163                      "TypeError args are not a one-tuple");
     164              goto finally;
     165          }
     166          message = Py_NewRef(PyTuple_GET_ITEM(args, 0));
     167          meta_error_string = PyUnicode_FromString("metaclass conflict:");
     168          if (meta_error_string == NULL) {
     169              goto finally;
     170          }
     171          int res = PyUnicode_Contains(message, meta_error_string);
     172          if (res < 0) {
     173              goto finally;
     174          }
     175          if (res == 0) {
     176              PyErr_SetString(PyExc_AssertionError,
     177                      "TypeError did not include expected message.");
     178              goto finally;
     179          }
     180          result = Py_NewRef(Py_None);
     181      }
     182  finally:
     183      Py_XDECREF(metaclass_a);
     184      Py_XDECREF(metaclass_b);
     185      Py_XDECREF(bases);
     186      Py_XDECREF(new);
     187      Py_XDECREF(meta_error_string);
     188      Py_XDECREF(exc);
     189      Py_XDECREF(message);
     190      Py_XDECREF(class_a);
     191      Py_XDECREF(class_b);
     192      Py_XDECREF(args);
     193      return result;
     194  }
     195  
     196  
     197  static PyObject *
     198  simple_str(PyObject *self) {
     199      return PyUnicode_FromString("<test>");
     200  }
     201  
     202  
     203  static PyObject *
     204  test_type_from_ephemeral_spec(PyObject *self, PyObject *Py_UNUSED(ignored))
     205  {
     206      // Test that a heap type can be created from a spec that's later deleted
     207      // (along with all its contents).
     208      // All necessary data must be copied and held by the class
     209      PyType_Spec *spec = NULL;
     210      char *name = NULL;
     211      char *doc = NULL;
     212      PyType_Slot *slots = NULL;
     213      PyObject *class = NULL;
     214      PyObject *instance = NULL;
     215      PyObject *obj = NULL;
     216      PyObject *result = NULL;
     217  
     218      /* create a spec (and all its contents) on the heap */
     219  
     220      const char NAME[] = "testcapi._Test";
     221      const char DOC[] = "a test class";
     222  
     223      spec = PyMem_New(PyType_Spec, 1);
     224      if (spec == NULL) {
     225          PyErr_NoMemory();
     226          goto finally;
     227      }
     228      name = PyMem_New(char, sizeof(NAME));
     229      if (name == NULL) {
     230          PyErr_NoMemory();
     231          goto finally;
     232      }
     233      memcpy(name, NAME, sizeof(NAME));
     234  
     235      doc = PyMem_New(char, sizeof(DOC));
     236      if (doc == NULL) {
     237          PyErr_NoMemory();
     238          goto finally;
     239      }
     240      memcpy(doc, DOC, sizeof(DOC));
     241  
     242      spec->name = name;
     243      spec->basicsize = sizeof(PyObject);
     244      spec->itemsize = 0;
     245      spec->flags = Py_TPFLAGS_DEFAULT;
     246      slots = PyMem_New(PyType_Slot, 3);
     247      if (slots == NULL) {
     248          PyErr_NoMemory();
     249          goto finally;
     250      }
     251      slots[0].slot = Py_tp_str;
     252      slots[0].pfunc = simple_str;
     253      slots[1].slot = Py_tp_doc;
     254      slots[1].pfunc = doc;
     255      slots[2].slot = 0;
     256      slots[2].pfunc = NULL;
     257      spec->slots = slots;
     258  
     259      /* create the class */
     260  
     261      class = PyType_FromSpec(spec);
     262      if (class == NULL) {
     263          goto finally;
     264      }
     265  
     266      /* deallocate the spec (and all contents) */
     267  
     268      // (Explicitly overwrite memory before freeing,
     269      // so bugs show themselves even without the debug allocator's help.)
     270      memset(spec, 0xdd, sizeof(PyType_Spec));
     271      PyMem_Del(spec);
     272      spec = NULL;
     273      memset(name, 0xdd, sizeof(NAME));
     274      PyMem_Del(name);
     275      name = NULL;
     276      memset(doc, 0xdd, sizeof(DOC));
     277      PyMem_Del(doc);
     278      doc = NULL;
     279      memset(slots, 0xdd, 3 * sizeof(PyType_Slot));
     280      PyMem_Del(slots);
     281      slots = NULL;
     282  
     283      /* check that everything works */
     284  
     285      PyTypeObject *class_tp = (PyTypeObject *)class;
     286      PyHeapTypeObject *class_ht = (PyHeapTypeObject *)class;
     287      assert(strcmp(class_tp->tp_name, "testcapi._Test") == 0);
     288      assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_name), "_Test") == 0);
     289      assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_qualname), "_Test") == 0);
     290      assert(strcmp(class_tp->tp_doc, "a test class") == 0);
     291  
     292      // call and check __str__
     293      instance = PyObject_CallNoArgs(class);
     294      if (instance == NULL) {
     295          goto finally;
     296      }
     297      obj = PyObject_Str(instance);
     298      if (obj == NULL) {
     299          goto finally;
     300      }
     301      assert(strcmp(PyUnicode_AsUTF8(obj), "<test>") == 0);
     302      Py_CLEAR(obj);
     303  
     304      result = Py_NewRef(Py_None);
     305    finally:
     306      PyMem_Del(spec);
     307      PyMem_Del(name);
     308      PyMem_Del(doc);
     309      PyMem_Del(slots);
     310      Py_XDECREF(class);
     311      Py_XDECREF(instance);
     312      Py_XDECREF(obj);
     313      return result;
     314  }
     315  
     316  PyType_Slot repeated_doc_slots[] = {
     317      {Py_tp_doc, "A class used for tests·"},
     318      {Py_tp_doc, "A class used for tests"},
     319      {0, 0},
     320  };
     321  
     322  PyType_Spec repeated_doc_slots_spec = {
     323      .name = "RepeatedDocSlotClass",
     324      .basicsize = sizeof(PyObject),
     325      .slots = repeated_doc_slots,
     326  };
     327  
     328  typedef struct {
     329      PyObject_HEAD
     330      int data;
     331  } HeapCTypeWithDataObject;
     332  
     333  
     334  static struct PyMemberDef members_to_repeat[] = {
     335      {"T_INT", T_INT, offsetof(HeapCTypeWithDataObject, data), 0, NULL},
     336      {NULL}
     337  };
     338  
     339  PyType_Slot repeated_members_slots[] = {
     340      {Py_tp_members, members_to_repeat},
     341      {Py_tp_members, members_to_repeat},
     342      {0, 0},
     343  };
     344  
     345  PyType_Spec repeated_members_slots_spec = {
     346      .name = "RepeatedMembersSlotClass",
     347      .basicsize = sizeof(HeapCTypeWithDataObject),
     348      .slots = repeated_members_slots,
     349  };
     350  
     351  static PyObject *
     352  create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj)
     353  {
     354      PyObject *class = NULL;
     355      int variant = PyLong_AsLong(variant_obj);
     356      if (PyErr_Occurred()) {
     357          return NULL;
     358      }
     359      switch (variant) {
     360          case 0:
     361              class = PyType_FromSpec(&repeated_doc_slots_spec);
     362              break;
     363          case 1:
     364              class = PyType_FromSpec(&repeated_members_slots_spec);
     365              break;
     366          default:
     367              PyErr_SetString(PyExc_ValueError, "bad test variant");
     368              break;
     369          }
     370      return class;
     371  }
     372  
     373  
     374  static PyObject *
     375  make_immutable_type_with_base(PyObject *self, PyObject *base)
     376  {
     377      assert(PyType_Check(base));
     378      PyType_Spec ImmutableSubclass_spec = {
     379          .name = "ImmutableSubclass",
     380          .basicsize = (int)((PyTypeObject*)base)->tp_basicsize,
     381          .slots = empty_type_slots,
     382          .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
     383      };
     384      return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base);
     385  }
     386  
     387  static PyObject *
     388  make_type_with_base(PyObject *self, PyObject *base)
     389  {
     390      assert(PyType_Check(base));
     391      PyType_Spec ImmutableSubclass_spec = {
     392          .name = "_testcapi.Subclass",
     393          .basicsize = (int)((PyTypeObject*)base)->tp_basicsize,
     394          .slots = empty_type_slots,
     395          .flags = Py_TPFLAGS_DEFAULT,
     396      };
     397      return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base);
     398  }
     399  
     400  
     401  static PyObject *
     402  pyobject_getitemdata(PyObject *self, PyObject *o)
     403  {
     404      void *pointer = PyObject_GetItemData(o);
     405      if (pointer == NULL) {
     406          return NULL;
     407      }
     408      return PyLong_FromVoidPtr(pointer);
     409  }
     410  
     411  
     412  static PyMethodDef TestMethods[] = {
     413      {"pytype_fromspec_meta",    pytype_fromspec_meta,            METH_O},
     414      {"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS},
     415      {"create_type_from_repeated_slots",
     416          create_type_from_repeated_slots, METH_O},
     417      {"test_from_spec_metatype_inheritance", test_from_spec_metatype_inheritance,
     418       METH_NOARGS},
     419      {"test_from_spec_invalid_metatype_inheritance",
     420       test_from_spec_invalid_metatype_inheritance,
     421       METH_NOARGS},
     422      {"make_immutable_type_with_base", make_immutable_type_with_base, METH_O},
     423      {"make_type_with_base", make_type_with_base, METH_O},
     424      {"pyobject_getitemdata", pyobject_getitemdata, METH_O},
     425      {NULL},
     426  };
     427  
     428  
     429  PyDoc_STRVAR(heapdocctype__doc__,
     430  "HeapDocCType(arg1, arg2)\n"
     431  "--\n"
     432  "\n"
     433  "somedoc");
     434  
     435  typedef struct {
     436      PyObject_HEAD
     437  } HeapDocCTypeObject;
     438  
     439  static PyType_Slot HeapDocCType_slots[] = {
     440      {Py_tp_doc, (char*)heapdocctype__doc__},
     441      {0},
     442  };
     443  
     444  static PyType_Spec HeapDocCType_spec = {
     445      "_testcapi.HeapDocCType",
     446      sizeof(HeapDocCTypeObject),
     447      0,
     448      Py_TPFLAGS_DEFAULT,
     449      HeapDocCType_slots
     450  };
     451  
     452  typedef struct {
     453      PyObject_HEAD
     454  } NullTpDocTypeObject;
     455  
     456  static PyType_Slot NullTpDocType_slots[] = {
     457      {Py_tp_doc, NULL},
     458      {0, 0},
     459  };
     460  
     461  static PyType_Spec NullTpDocType_spec = {
     462      "_testcapi.NullTpDocType",
     463      sizeof(NullTpDocTypeObject),
     464      0,
     465      Py_TPFLAGS_DEFAULT,
     466      NullTpDocType_slots
     467  };
     468  
     469  
     470  PyDoc_STRVAR(heapgctype__doc__,
     471  "A heap type with GC, and with overridden dealloc.\n\n"
     472  "The 'value' attribute is set to 10 in __init__.");
     473  
     474  typedef struct {
     475      PyObject_HEAD
     476      int value;
     477  } HeapCTypeObject;
     478  
     479  static struct PyMemberDef heapctype_members[] = {
     480      {"value", T_INT, offsetof(HeapCTypeObject, value)},
     481      {NULL} /* Sentinel */
     482  };
     483  
     484  static int
     485  heapctype_init(PyObject *self, PyObject *args, PyObject *kwargs)
     486  {
     487      ((HeapCTypeObject *)self)->value = 10;
     488      return 0;
     489  }
     490  
     491  static int
     492  heapgcctype_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
     493  {
     494      Py_VISIT(Py_TYPE(self));
     495      return 0;
     496  }
     497  
     498  static void
     499  heapgcctype_dealloc(HeapCTypeObject *self)
     500  {
     501      PyTypeObject *tp = Py_TYPE(self);
     502      PyObject_GC_UnTrack(self);
     503      PyObject_GC_Del(self);
     504      Py_DECREF(tp);
     505  }
     506  
     507  static PyType_Slot HeapGcCType_slots[] = {
     508      {Py_tp_init, heapctype_init},
     509      {Py_tp_members, heapctype_members},
     510      {Py_tp_dealloc, heapgcctype_dealloc},
     511      {Py_tp_traverse, heapgcctype_traverse},
     512      {Py_tp_doc, (char*)heapgctype__doc__},
     513      {0, 0},
     514  };
     515  
     516  static PyType_Spec HeapGcCType_spec = {
     517      "_testcapi.HeapGcCType",
     518      sizeof(HeapCTypeObject),
     519      0,
     520      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
     521      HeapGcCType_slots
     522  };
     523  
     524  PyDoc_STRVAR(heapctype__doc__,
     525  "A heap type without GC, but with overridden dealloc.\n\n"
     526  "The 'value' attribute is set to 10 in __init__.");
     527  
     528  static void
     529  heapctype_dealloc(HeapCTypeObject *self)
     530  {
     531      PyTypeObject *tp = Py_TYPE(self);
     532      PyObject_Free(self);
     533      Py_DECREF(tp);
     534  }
     535  
     536  static PyType_Slot HeapCType_slots[] = {
     537      {Py_tp_init, heapctype_init},
     538      {Py_tp_members, heapctype_members},
     539      {Py_tp_dealloc, heapctype_dealloc},
     540      {Py_tp_doc, (char*)heapctype__doc__},
     541      {0, 0},
     542  };
     543  
     544  static PyType_Spec HeapCType_spec = {
     545      "_testcapi.HeapCType",
     546      sizeof(HeapCTypeObject),
     547      0,
     548      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     549      HeapCType_slots
     550  };
     551  
     552  PyDoc_STRVAR(heapctypesubclass__doc__,
     553  "Subclass of HeapCType, without GC.\n\n"
     554  "__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
     555  
     556  typedef struct {
     557      HeapCTypeObject base;
     558      int value2;
     559  } HeapCTypeSubclassObject;
     560  
     561  static int
     562  heapctypesubclass_init(PyObject *self, PyObject *args, PyObject *kwargs)
     563  {
     564      /* Call __init__ of the superclass */
     565      if (heapctype_init(self, args, kwargs) < 0) {
     566          return -1;
     567      }
     568      /* Initialize additional element */
     569      ((HeapCTypeSubclassObject *)self)->value2 = 20;
     570      return 0;
     571  }
     572  
     573  static struct PyMemberDef heapctypesubclass_members[] = {
     574      {"value2", T_INT, offsetof(HeapCTypeSubclassObject, value2)},
     575      {NULL} /* Sentinel */
     576  };
     577  
     578  static PyType_Slot HeapCTypeSubclass_slots[] = {
     579      {Py_tp_init, heapctypesubclass_init},
     580      {Py_tp_members, heapctypesubclass_members},
     581      {Py_tp_doc, (char*)heapctypesubclass__doc__},
     582      {0, 0},
     583  };
     584  
     585  static PyType_Spec HeapCTypeSubclass_spec = {
     586      "_testcapi.HeapCTypeSubclass",
     587      sizeof(HeapCTypeSubclassObject),
     588      0,
     589      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     590      HeapCTypeSubclass_slots
     591  };
     592  
     593  PyDoc_STRVAR(heapctypewithbuffer__doc__,
     594  "Heap type with buffer support.\n\n"
     595  "The buffer is set to [b'1', b'2', b'3', b'4']");
     596  
     597  typedef struct {
     598      HeapCTypeObject base;
     599      char buffer[4];
     600  } HeapCTypeWithBufferObject;
     601  
     602  static int
     603  heapctypewithbuffer_getbuffer(HeapCTypeWithBufferObject *self, Py_buffer *view, int flags)
     604  {
     605      self->buffer[0] = '1';
     606      self->buffer[1] = '2';
     607      self->buffer[2] = '3';
     608      self->buffer[3] = '4';
     609      return PyBuffer_FillInfo(
     610          view, (PyObject*)self, (void *)self->buffer, 4, 1, flags);
     611  }
     612  
     613  static void
     614  heapctypewithbuffer_releasebuffer(HeapCTypeWithBufferObject *self, Py_buffer *view)
     615  {
     616      assert(view->obj == (void*) self);
     617  }
     618  
     619  static PyType_Slot HeapCTypeWithBuffer_slots[] = {
     620      {Py_bf_getbuffer, heapctypewithbuffer_getbuffer},
     621      {Py_bf_releasebuffer, heapctypewithbuffer_releasebuffer},
     622      {Py_tp_doc, (char*)heapctypewithbuffer__doc__},
     623      {0, 0},
     624  };
     625  
     626  static PyType_Spec HeapCTypeWithBuffer_spec = {
     627      "_testcapi.HeapCTypeWithBuffer",
     628      sizeof(HeapCTypeWithBufferObject),
     629      0,
     630      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     631      HeapCTypeWithBuffer_slots
     632  };
     633  
     634  PyDoc_STRVAR(heapctypesubclasswithfinalizer__doc__,
     635  "Subclass of HeapCType with a finalizer that reassigns __class__.\n\n"
     636  "__class__ is set to plain HeapCTypeSubclass during finalization.\n"
     637  "__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
     638  
     639  static int
     640  heapctypesubclasswithfinalizer_init(PyObject *self, PyObject *args, PyObject *kwargs)
     641  {
     642      PyTypeObject *base = (PyTypeObject *)PyType_GetSlot(Py_TYPE(self), Py_tp_base);
     643      initproc base_init = PyType_GetSlot(base, Py_tp_init);
     644      base_init(self, args, kwargs);
     645      return 0;
     646  }
     647  
     648  static void
     649  heapctypesubclasswithfinalizer_finalize(PyObject *self)
     650  {
     651      PyObject *oldtype = NULL, *newtype = NULL, *refcnt = NULL;
     652  
     653      /* Save the current exception, if any. */
     654      PyObject *exc = PyErr_GetRaisedException();
     655  
     656      if (_testcapimodule == NULL) {
     657          goto cleanup_finalize;
     658      }
     659      PyObject *m = PyState_FindModule(_testcapimodule);
     660      if (m == NULL) {
     661          goto cleanup_finalize;
     662      }
     663      oldtype = PyObject_GetAttrString(m, "HeapCTypeSubclassWithFinalizer");
     664      if (oldtype == NULL) {
     665          goto cleanup_finalize;
     666      }
     667      newtype = PyObject_GetAttrString(m, "HeapCTypeSubclass");
     668      if (newtype == NULL) {
     669          goto cleanup_finalize;
     670      }
     671  
     672      if (PyObject_SetAttrString(self, "__class__", newtype) < 0) {
     673          goto cleanup_finalize;
     674      }
     675      refcnt = PyLong_FromSsize_t(Py_REFCNT(oldtype));
     676      if (refcnt == NULL) {
     677          goto cleanup_finalize;
     678      }
     679      if (PyObject_SetAttrString(oldtype, "refcnt_in_del", refcnt) < 0) {
     680          goto cleanup_finalize;
     681      }
     682      Py_DECREF(refcnt);
     683      refcnt = PyLong_FromSsize_t(Py_REFCNT(newtype));
     684      if (refcnt == NULL) {
     685          goto cleanup_finalize;
     686      }
     687      if (PyObject_SetAttrString(newtype, "refcnt_in_del", refcnt) < 0) {
     688          goto cleanup_finalize;
     689      }
     690  
     691  cleanup_finalize:
     692      Py_XDECREF(oldtype);
     693      Py_XDECREF(newtype);
     694      Py_XDECREF(refcnt);
     695  
     696      /* Restore the saved exception. */
     697      PyErr_SetRaisedException(exc);
     698  }
     699  
     700  static PyType_Slot HeapCTypeSubclassWithFinalizer_slots[] = {
     701      {Py_tp_init, heapctypesubclasswithfinalizer_init},
     702      {Py_tp_members, heapctypesubclass_members},
     703      {Py_tp_finalize, heapctypesubclasswithfinalizer_finalize},
     704      {Py_tp_doc, (char*)heapctypesubclasswithfinalizer__doc__},
     705      {0, 0},
     706  };
     707  
     708  static PyType_Spec HeapCTypeSubclassWithFinalizer_spec = {
     709      "_testcapi.HeapCTypeSubclassWithFinalizer",
     710      sizeof(HeapCTypeSubclassObject),
     711      0,
     712      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE,
     713      HeapCTypeSubclassWithFinalizer_slots
     714  };
     715  
     716  static PyType_Slot HeapCTypeMetaclass_slots[] = {
     717      {0},
     718  };
     719  
     720  static PyType_Spec HeapCTypeMetaclass_spec = {
     721      "_testcapi.HeapCTypeMetaclass",
     722      sizeof(PyHeapTypeObject),
     723      sizeof(PyMemberDef),
     724      Py_TPFLAGS_DEFAULT,
     725      HeapCTypeMetaclass_slots
     726  };
     727  
     728  static PyObject *
     729  heap_ctype_metaclass_custom_tp_new(PyTypeObject *tp, PyObject *args, PyObject *kwargs)
     730  {
     731      return PyType_Type.tp_new(tp, args, kwargs);
     732  }
     733  
     734  static PyType_Slot HeapCTypeMetaclassCustomNew_slots[] = {
     735      { Py_tp_new, heap_ctype_metaclass_custom_tp_new },
     736      {0},
     737  };
     738  
     739  static PyType_Spec HeapCTypeMetaclassCustomNew_spec = {
     740      "_testcapi.HeapCTypeMetaclassCustomNew",
     741      sizeof(PyHeapTypeObject),
     742      sizeof(PyMemberDef),
     743      Py_TPFLAGS_DEFAULT,
     744      HeapCTypeMetaclassCustomNew_slots
     745  };
     746  
     747  static PyType_Spec HeapCTypeMetaclassNullNew_spec = {
     748      .name = "_testcapi.HeapCTypeMetaclassNullNew",
     749      .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
     750      .slots = empty_type_slots
     751  };
     752  
     753  
     754  typedef struct {
     755      PyObject_HEAD
     756      PyObject *dict;
     757  } HeapCTypeWithDictObject;
     758  
     759  static void
     760  heapctypewithdict_dealloc(HeapCTypeWithDictObject* self)
     761  {
     762  
     763      PyTypeObject *tp = Py_TYPE(self);
     764      Py_XDECREF(self->dict);
     765      PyObject_Free(self);
     766      Py_DECREF(tp);
     767  }
     768  
     769  static PyGetSetDef heapctypewithdict_getsetlist[] = {
     770      {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
     771      {NULL} /* Sentinel */
     772  };
     773  
     774  static struct PyMemberDef heapctypewithdict_members[] = {
     775      {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
     776      {"__dictoffset__", T_PYSSIZET, offsetof(HeapCTypeWithDictObject, dict), READONLY},
     777      {NULL} /* Sentinel */
     778  };
     779  
     780  static PyType_Slot HeapCTypeWithDict_slots[] = {
     781      {Py_tp_members, heapctypewithdict_members},
     782      {Py_tp_getset, heapctypewithdict_getsetlist},
     783      {Py_tp_dealloc, heapctypewithdict_dealloc},
     784      {0, 0},
     785  };
     786  
     787  static PyType_Spec HeapCTypeWithDict_spec = {
     788      "_testcapi.HeapCTypeWithDict",
     789      sizeof(HeapCTypeWithDictObject),
     790      0,
     791      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     792      HeapCTypeWithDict_slots
     793  };
     794  
     795  static PyType_Spec HeapCTypeWithDict2_spec = {
     796      "_testcapi.HeapCTypeWithDict2",
     797      sizeof(HeapCTypeWithDictObject),
     798      0,
     799      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     800      HeapCTypeWithDict_slots
     801  };
     802  
     803  static int
     804  heapmanaged_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
     805  {
     806      Py_VISIT(Py_TYPE(self));
     807      return _PyObject_VisitManagedDict((PyObject *)self, visit, arg);
     808  }
     809  
     810  static int
     811  heapmanaged_clear(HeapCTypeObject *self)
     812  {
     813      _PyObject_ClearManagedDict((PyObject *)self);
     814      return 0;
     815  }
     816  
     817  static void
     818  heapmanaged_dealloc(HeapCTypeObject *self)
     819  {
     820      PyTypeObject *tp = Py_TYPE(self);
     821      _PyObject_ClearManagedDict((PyObject *)self);
     822      PyObject_GC_UnTrack(self);
     823      PyObject_GC_Del(self);
     824      Py_DECREF(tp);
     825  }
     826  
     827  static PyType_Slot HeapCTypeWithManagedDict_slots[] = {
     828      {Py_tp_traverse, heapmanaged_traverse},
     829      {Py_tp_getset, heapctypewithdict_getsetlist},
     830      {Py_tp_clear, heapmanaged_clear},
     831      {Py_tp_dealloc, heapmanaged_dealloc},
     832      {0, 0},
     833  };
     834  
     835  static PyType_Spec  HeapCTypeWithManagedDict_spec = {
     836      "_testcapi.HeapCTypeWithManagedDict",
     837      sizeof(PyObject),
     838      0,
     839      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_DICT,
     840      HeapCTypeWithManagedDict_slots
     841  };
     842  
     843  static void
     844  heapctypewithmanagedweakref_dealloc(PyObject* self)
     845  {
     846  
     847      PyTypeObject *tp = Py_TYPE(self);
     848      PyObject_ClearWeakRefs(self);
     849      PyObject_GC_UnTrack(self);
     850      PyObject_GC_Del(self);
     851      Py_DECREF(tp);
     852  }
     853  
     854  static PyType_Slot HeapCTypeWithManagedWeakref_slots[] = {
     855      {Py_tp_traverse, heapgcctype_traverse},
     856      {Py_tp_getset, heapctypewithdict_getsetlist},
     857      {Py_tp_dealloc, heapctypewithmanagedweakref_dealloc},
     858      {0, 0},
     859  };
     860  
     861  static PyType_Spec  HeapCTypeWithManagedWeakref_spec = {
     862      "_testcapi.HeapCTypeWithManagedWeakref",
     863      sizeof(PyObject),
     864      0,
     865      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_WEAKREF,
     866      HeapCTypeWithManagedWeakref_slots
     867  };
     868  
     869  static struct PyMemberDef heapctypewithnegativedict_members[] = {
     870      {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
     871      {"__dictoffset__", T_PYSSIZET, -(Py_ssize_t)sizeof(void*), READONLY},
     872      {NULL} /* Sentinel */
     873  };
     874  
     875  static PyType_Slot HeapCTypeWithNegativeDict_slots[] = {
     876      {Py_tp_members, heapctypewithnegativedict_members},
     877      {Py_tp_getset, heapctypewithdict_getsetlist},
     878      {Py_tp_dealloc, heapctypewithdict_dealloc},
     879      {0, 0},
     880  };
     881  
     882  static PyType_Spec HeapCTypeWithNegativeDict_spec = {
     883      "_testcapi.HeapCTypeWithNegativeDict",
     884      sizeof(HeapCTypeWithDictObject),
     885      0,
     886      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     887      HeapCTypeWithNegativeDict_slots
     888  };
     889  
     890  typedef struct {
     891      PyObject_HEAD
     892      PyObject *weakreflist;
     893  } HeapCTypeWithWeakrefObject;
     894  
     895  static struct PyMemberDef heapctypewithweakref_members[] = {
     896      {"weakreflist", T_OBJECT, offsetof(HeapCTypeWithWeakrefObject, weakreflist)},
     897      {"__weaklistoffset__", T_PYSSIZET,
     898        offsetof(HeapCTypeWithWeakrefObject, weakreflist), READONLY},
     899      {NULL} /* Sentinel */
     900  };
     901  
     902  static void
     903  heapctypewithweakref_dealloc(HeapCTypeWithWeakrefObject* self)
     904  {
     905  
     906      PyTypeObject *tp = Py_TYPE(self);
     907      if (self->weakreflist != NULL)
     908          PyObject_ClearWeakRefs((PyObject *) self);
     909      Py_XDECREF(self->weakreflist);
     910      PyObject_Free(self);
     911      Py_DECREF(tp);
     912  }
     913  
     914  static PyType_Slot HeapCTypeWithWeakref_slots[] = {
     915      {Py_tp_members, heapctypewithweakref_members},
     916      {Py_tp_dealloc, heapctypewithweakref_dealloc},
     917      {0, 0},
     918  };
     919  
     920  static PyType_Spec HeapCTypeWithWeakref_spec = {
     921      "_testcapi.HeapCTypeWithWeakref",
     922      sizeof(HeapCTypeWithWeakrefObject),
     923      0,
     924      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     925      HeapCTypeWithWeakref_slots
     926  };
     927  
     928  static PyType_Spec HeapCTypeWithWeakref2_spec = {
     929      "_testcapi.HeapCTypeWithWeakref2",
     930      sizeof(HeapCTypeWithWeakrefObject),
     931      0,
     932      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     933      HeapCTypeWithWeakref_slots
     934  };
     935  
     936  PyDoc_STRVAR(heapctypesetattr__doc__,
     937  "A heap type without GC, but with overridden __setattr__.\n\n"
     938  "The 'value' attribute is set to 10 in __init__ and updated via attribute setting.");
     939  
     940  typedef struct {
     941      PyObject_HEAD
     942      long value;
     943  } HeapCTypeSetattrObject;
     944  
     945  static struct PyMemberDef heapctypesetattr_members[] = {
     946      {"pvalue", T_LONG, offsetof(HeapCTypeSetattrObject, value)},
     947      {NULL} /* Sentinel */
     948  };
     949  
     950  static int
     951  heapctypesetattr_init(PyObject *self, PyObject *args, PyObject *kwargs)
     952  {
     953      ((HeapCTypeSetattrObject *)self)->value = 10;
     954      return 0;
     955  }
     956  
     957  static void
     958  heapctypesetattr_dealloc(HeapCTypeSetattrObject *self)
     959  {
     960      PyTypeObject *tp = Py_TYPE(self);
     961      PyObject_Free(self);
     962      Py_DECREF(tp);
     963  }
     964  
     965  static int
     966  heapctypesetattr_setattro(HeapCTypeSetattrObject *self, PyObject *attr, PyObject *value)
     967  {
     968      PyObject *svalue = PyUnicode_FromString("value");
     969      if (svalue == NULL)
     970          return -1;
     971      int eq = PyObject_RichCompareBool(svalue, attr, Py_EQ);
     972      Py_DECREF(svalue);
     973      if (eq < 0)
     974          return -1;
     975      if (!eq) {
     976          return PyObject_GenericSetAttr((PyObject*) self, attr, value);
     977      }
     978      if (value == NULL) {
     979          self->value = 0;
     980          return 0;
     981      }
     982      PyObject *ivalue = PyNumber_Long(value);
     983      if (ivalue == NULL)
     984          return -1;
     985      long v = PyLong_AsLong(ivalue);
     986      Py_DECREF(ivalue);
     987      if (v == -1 && PyErr_Occurred())
     988          return -1;
     989      self->value = v;
     990      return 0;
     991  }
     992  
     993  static PyType_Slot HeapCTypeSetattr_slots[] = {
     994      {Py_tp_init, heapctypesetattr_init},
     995      {Py_tp_members, heapctypesetattr_members},
     996      {Py_tp_setattro, heapctypesetattr_setattro},
     997      {Py_tp_dealloc, heapctypesetattr_dealloc},
     998      {Py_tp_doc, (char*)heapctypesetattr__doc__},
     999      {0, 0},
    1000  };
    1001  
    1002  static PyType_Spec HeapCTypeSetattr_spec = {
    1003      "_testcapi.HeapCTypeSetattr",
    1004      sizeof(HeapCTypeSetattrObject),
    1005      0,
    1006      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    1007      HeapCTypeSetattr_slots
    1008  };
    1009  
    1010  PyDoc_STRVAR(HeapCCollection_doc,
    1011  "Tuple-like heap type that uses PyObject_GetItemData for items.");
    1012  
    1013  static PyObject*
    1014  HeapCCollection_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
    1015  {
    1016      PyObject *self = NULL;
    1017      PyObject *result = NULL;
    1018  
    1019      Py_ssize_t size = PyTuple_GET_SIZE(args);
    1020      self = subtype->tp_alloc(subtype, size);
    1021      if (!self) {
    1022          goto finally;
    1023      }
    1024      PyObject **data = PyObject_GetItemData(self);
    1025      if (!data) {
    1026          goto finally;
    1027      }
    1028  
    1029      for (Py_ssize_t i = 0; i < size; i++) {
    1030          data[i] = Py_NewRef(PyTuple_GET_ITEM(args, i));
    1031      }
    1032  
    1033      result = self;
    1034      self = NULL;
    1035    finally:
    1036      Py_XDECREF(self);
    1037      return result;
    1038  }
    1039  
    1040  static Py_ssize_t
    1041  HeapCCollection_length(PyVarObject *self)
    1042  {
    1043      return Py_SIZE(self);
    1044  }
    1045  
    1046  static PyObject*
    1047  HeapCCollection_item(PyObject *self, Py_ssize_t i)
    1048  {
    1049      if (i < 0 || i >= Py_SIZE(self)) {
    1050          return PyErr_Format(PyExc_IndexError, "index %zd out of range", i);
    1051      }
    1052      PyObject **data = PyObject_GetItemData(self);
    1053      if (!data) {
    1054          return NULL;
    1055      }
    1056      return Py_NewRef(data[i]);
    1057  }
    1058  
    1059  static int
    1060  HeapCCollection_traverse(PyObject *self, visitproc visit, void *arg)
    1061  {
    1062      PyObject **data = PyObject_GetItemData(self);
    1063      if (!data) {
    1064          return -1;
    1065      }
    1066      for (Py_ssize_t i = 0; i < Py_SIZE(self); i++) {
    1067          Py_VISIT(data[i]);
    1068      }
    1069      return 0;
    1070  }
    1071  
    1072  static int
    1073  HeapCCollection_clear(PyObject *self)
    1074  {
    1075      PyObject **data = PyObject_GetItemData(self);
    1076      if (!data) {
    1077          return -1;
    1078      }
    1079      Py_ssize_t size = Py_SIZE(self);
    1080      Py_SET_SIZE(self, 0);
    1081      for (Py_ssize_t i = 0; i < size; i++) {
    1082          Py_CLEAR(data[i]);
    1083      }
    1084      return 0;
    1085  }
    1086  
    1087  static void
    1088  HeapCCollection_dealloc(PyObject *self)
    1089  {
    1090      PyTypeObject *tp = Py_TYPE(self);
    1091      HeapCCollection_clear(self);
    1092      PyObject_GC_UnTrack(self);
    1093      tp->tp_free(self);
    1094      Py_DECREF(tp);
    1095  }
    1096  
    1097  static PyType_Slot HeapCCollection_slots[] = {
    1098      {Py_tp_new, HeapCCollection_new},
    1099      {Py_sq_length, HeapCCollection_length},
    1100      {Py_sq_item, HeapCCollection_item},
    1101      {Py_tp_traverse, HeapCCollection_traverse},
    1102      {Py_tp_clear, HeapCCollection_clear},
    1103      {Py_tp_dealloc, HeapCCollection_dealloc},
    1104      {Py_tp_doc, (void *)HeapCCollection_doc},
    1105      {0, 0},
    1106  };
    1107  
    1108  static PyType_Spec HeapCCollection_spec = {
    1109      .name = "_testcapi.HeapCCollection",
    1110      .basicsize = sizeof(PyVarObject),
    1111      .itemsize = sizeof(PyObject*),
    1112      .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
    1113                Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_ITEMS_AT_END),
    1114      .slots = HeapCCollection_slots,
    1115  };
    1116  
    1117  int
    1118  _PyTestCapi_Init_Heaptype(PyObject *m) {
    1119      _testcapimodule = PyModule_GetDef(m);
    1120  
    1121      if (PyModule_AddFunctions(m, TestMethods) < 0) {
    1122          return -1;
    1123      }
    1124  
    1125      PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
    1126      if (HeapDocCType == NULL) {
    1127          return -1;
    1128      }
    1129      PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
    1130  
    1131      /* bpo-41832: Add a new type to test PyType_FromSpec()
    1132         now can accept a NULL tp_doc slot. */
    1133      PyObject *NullTpDocType = PyType_FromSpec(&NullTpDocType_spec);
    1134      if (NullTpDocType == NULL) {
    1135          return -1;
    1136      }
    1137      PyModule_AddObject(m, "NullTpDocType", NullTpDocType);
    1138  
    1139      PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
    1140      if (HeapGcCType == NULL) {
    1141          return -1;
    1142      }
    1143      PyModule_AddObject(m, "HeapGcCType", HeapGcCType);
    1144  
    1145      PyObject *HeapCType = PyType_FromSpec(&HeapCType_spec);
    1146      if (HeapCType == NULL) {
    1147          return -1;
    1148      }
    1149      PyObject *subclass_bases = PyTuple_Pack(1, HeapCType);
    1150      if (subclass_bases == NULL) {
    1151          return -1;
    1152      }
    1153      PyObject *HeapCTypeSubclass = PyType_FromSpecWithBases(&HeapCTypeSubclass_spec, subclass_bases);
    1154      if (HeapCTypeSubclass == NULL) {
    1155          return -1;
    1156      }
    1157      Py_DECREF(subclass_bases);
    1158      PyModule_AddObject(m, "HeapCTypeSubclass", HeapCTypeSubclass);
    1159  
    1160      PyObject *HeapCTypeWithDict = PyType_FromSpec(&HeapCTypeWithDict_spec);
    1161      if (HeapCTypeWithDict == NULL) {
    1162          return -1;
    1163      }
    1164      PyModule_AddObject(m, "HeapCTypeWithDict", HeapCTypeWithDict);
    1165  
    1166      PyObject *HeapCTypeWithDict2 = PyType_FromSpec(&HeapCTypeWithDict2_spec);
    1167      if (HeapCTypeWithDict2 == NULL) {
    1168          return -1;
    1169      }
    1170      PyModule_AddObject(m, "HeapCTypeWithDict2", HeapCTypeWithDict2);
    1171  
    1172      PyObject *HeapCTypeWithNegativeDict = PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
    1173      if (HeapCTypeWithNegativeDict == NULL) {
    1174          return -1;
    1175      }
    1176      PyModule_AddObject(m, "HeapCTypeWithNegativeDict", HeapCTypeWithNegativeDict);
    1177  
    1178      PyObject *HeapCTypeWithManagedDict = PyType_FromSpec(&HeapCTypeWithManagedDict_spec);
    1179      if (HeapCTypeWithManagedDict == NULL) {
    1180          return -1;
    1181      }
    1182      PyModule_AddObject(m, "HeapCTypeWithManagedDict", HeapCTypeWithManagedDict);
    1183  
    1184      PyObject *HeapCTypeWithManagedWeakref = PyType_FromSpec(&HeapCTypeWithManagedWeakref_spec);
    1185      if (HeapCTypeWithManagedWeakref == NULL) {
    1186          return -1;
    1187      }
    1188      PyModule_AddObject(m, "HeapCTypeWithManagedWeakref", HeapCTypeWithManagedWeakref);
    1189  
    1190      PyObject *HeapCTypeWithWeakref = PyType_FromSpec(&HeapCTypeWithWeakref_spec);
    1191      if (HeapCTypeWithWeakref == NULL) {
    1192          return -1;
    1193      }
    1194      PyModule_AddObject(m, "HeapCTypeWithWeakref", HeapCTypeWithWeakref);
    1195  
    1196      PyObject *HeapCTypeWithWeakref2 = PyType_FromSpec(&HeapCTypeWithWeakref2_spec);
    1197      if (HeapCTypeWithWeakref2 == NULL) {
    1198          return -1;
    1199      }
    1200      PyModule_AddObject(m, "HeapCTypeWithWeakref2", HeapCTypeWithWeakref2);
    1201  
    1202      PyObject *HeapCTypeWithBuffer = PyType_FromSpec(&HeapCTypeWithBuffer_spec);
    1203      if (HeapCTypeWithBuffer == NULL) {
    1204          return -1;
    1205      }
    1206      PyModule_AddObject(m, "HeapCTypeWithBuffer", HeapCTypeWithBuffer);
    1207  
    1208      PyObject *HeapCTypeSetattr = PyType_FromSpec(&HeapCTypeSetattr_spec);
    1209      if (HeapCTypeSetattr == NULL) {
    1210          return -1;
    1211      }
    1212      PyModule_AddObject(m, "HeapCTypeSetattr", HeapCTypeSetattr);
    1213  
    1214      PyObject *subclass_with_finalizer_bases = PyTuple_Pack(1, HeapCTypeSubclass);
    1215      if (subclass_with_finalizer_bases == NULL) {
    1216          return -1;
    1217      }
    1218      PyObject *HeapCTypeSubclassWithFinalizer = PyType_FromSpecWithBases(
    1219          &HeapCTypeSubclassWithFinalizer_spec, subclass_with_finalizer_bases);
    1220      if (HeapCTypeSubclassWithFinalizer == NULL) {
    1221          return -1;
    1222      }
    1223      Py_DECREF(subclass_with_finalizer_bases);
    1224      PyModule_AddObject(m, "HeapCTypeSubclassWithFinalizer", HeapCTypeSubclassWithFinalizer);
    1225  
    1226      PyObject *HeapCTypeMetaclass = PyType_FromMetaclass(
    1227          &PyType_Type, m, &HeapCTypeMetaclass_spec, (PyObject *) &PyType_Type);
    1228      if (HeapCTypeMetaclass == NULL) {
    1229          return -1;
    1230      }
    1231      PyModule_AddObject(m, "HeapCTypeMetaclass", HeapCTypeMetaclass);
    1232  
    1233      PyObject *HeapCTypeMetaclassCustomNew = PyType_FromMetaclass(
    1234          &PyType_Type, m, &HeapCTypeMetaclassCustomNew_spec, (PyObject *) &PyType_Type);
    1235      if (HeapCTypeMetaclassCustomNew == NULL) {
    1236          return -1;
    1237      }
    1238      PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew);
    1239  
    1240      PyObject *HeapCTypeMetaclassNullNew = PyType_FromMetaclass(
    1241          &PyType_Type, m, &HeapCTypeMetaclassNullNew_spec, (PyObject *) &PyType_Type);
    1242      if (HeapCTypeMetaclassNullNew == NULL) {
    1243          return -1;
    1244      }
    1245      PyModule_AddObject(m, "HeapCTypeMetaclassNullNew", HeapCTypeMetaclassNullNew);
    1246  
    1247      PyObject *HeapCCollection = PyType_FromMetaclass(
    1248          NULL, m, &HeapCCollection_spec, NULL);
    1249      if (HeapCCollection == NULL) {
    1250          return -1;
    1251      }
    1252      int rc = PyModule_AddType(m, (PyTypeObject *)HeapCCollection);
    1253      Py_DECREF(HeapCCollection);
    1254      if (rc < 0) {
    1255          return -1;
    1256      }
    1257  
    1258      return 0;
    1259  }