@@ -264,6 +264,24 @@ Type Objects
264264
265265 .. versionadded:: 3.11
266266
267+ .. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
268+
269+ Find the first superclass in *type *'s :term: `method resolution order ` whose
270+ :c:macro: `Py_tp_token ` token is equal to the given one.
271+
272+ * If found, set *\* result * to a new :term: `strong reference `
273+ to it and return ``1 ``.
274+ * If not found, set *\* result * to ``NULL `` and return ``0 ``.
275+ * On error, set *\* result * to ``NULL `` and return ``-1 `` with an
276+ exception set.
277+
278+ The *result * argument may be ``NULL ``, in which case *\* result * is not set.
279+ Use this if you need only the return value.
280+
281+ The *token * argument may not be ``NULL ``.
282+
283+ .. versionadded :: 3.14
284+
267285.. c :function :: int PyUnstable_Type_AssignVersionTag (PyTypeObject *type)
268286
269287 Attempt to assign a version tag to the given type.
@@ -488,6 +506,11 @@ The following functions and structs are used to create
488506 * ``Py_nb_add `` to set :c:member: `PyNumberMethods.nb_add `
489507 * ``Py_sq_length `` to set :c:member: `PySequenceMethods.sq_length `
490508
509+ An additional slot is supported that does not correspond to a
510+ :c:type: `!PyTypeObject ` struct field:
511+
512+ * :c:data: `Py_tp_token `
513+
491514 The following “offset” fields cannot be set using :c:type: `PyType_Slot `:
492515
493516 * :c:member: `~PyTypeObject.tp_weaklistoffset `
@@ -538,4 +561,47 @@ The following functions and structs are used to create
538561 The desired value of the slot. In most cases, this is a pointer
539562 to a function.
540563
541- Slots other than ``Py_tp_doc`` may not be ``NULL``.
564+ *pfunc* values may not be ``NULL``, except for the following slots:
565+
566+ * ``Py_tp_doc``
567+ * :c:data:`Py_tp_token` (for clarity, prefer :c:data: `Py_TP_USE_SPEC `
568+ rather than ``NULL ``)
569+
570+ .. c:macro:: Py_tp_token
571+
572+ A :c:member:`~PyType_Slot.slot` that records a static memory layout ID
573+ for a class.
574+
575+ If the :c:type:`PyType_Spec` of the class is statically
576+ allocated, the token can be set to the spec using the special value
577+ :c:data:`Py_TP_USE_SPEC`:
578+
579+ .. code-block:: c
580+
581+ static PyType_Slot foo_slots[] = {
582+ {Py_tp_token, Py_TP_USE_SPEC},
583+
584+ It can also be set to an arbitrary pointer, but you must ensure that:
585+
586+ * The pointer outlives the class, so it's not reused for something else
587+ while the class exists.
588+ * It "belongs" to the extension module where the class lives, so it will not
589+ clash with other extensions.
590+
591+ Use :c:func: `PyType_GetBaseByToken ` to check if a class's superclass has
592+ a given token -- that is, check whether the memory layout is compatible.
593+
594+ To get the token for a given class (without considering superclasses),
595+ use :c:func: `PyType_GetSlot ` with ``Py_tp_token ``.
596+
597+ .. versionadded :: 3.14
598+
599+ .. c :namespace :: NULL
600+
601+ .. c :macro :: Py_TP_USE_SPEC
602+
603+ Used as a value with :c:data: `Py_tp_token ` to set the token to the
604+ class's :c:type: `PyType_Spec `.
605+ Expands to ``NULL ``.
606+
607+ .. versionadded :: 3.14
0 commit comments