diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 8bd3144f88aa71..e9609dfaab59f3 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1260,7 +1260,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) This bit indicates that instances of the class have a :attr:`~object.__dict__` attribute, and that the space for the dictionary is managed by the VM. - If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set. + If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set. The type traverse function must call :c:func:`PyObject_VisitManagedDict` and its clear function must call :c:func:`PyObject_ClearManagedDict`. @@ -1278,6 +1278,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) This bit indicates that instances of the class should be weakly referenceable. + If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set. + .. versionadded:: 3.12 **Inheritance:** diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index e3612f3a1875ca..26085b5cebd3ad 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -560,6 +560,8 @@ For an object to be weakly referenceable, the extension type must set the field. The legacy :c:member:`~PyTypeObject.tp_weaklistoffset` field should be left as zero. +If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set. + Concretely, here is how the statically declared type object would look:: static PyTypeObject TrivialType = { diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index fc5519286e2264..b03017f17d64df 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -803,6 +803,14 @@ New features (Contributed by Victor Stinner in :gh:`129813`.) +Changed C APIs +-------------- + +* If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` + flags are set then :c:macro:`Py_TPFLAGS_HAVE_GC` must be set too. + (Contributed by Sergey Miryanov in :gh:`134786`) + + Porting to Python 3.15 ---------------------- diff --git a/Include/object.h b/Include/object.h index 9585f4a1d67a52..117d057a18178f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -529,7 +529,7 @@ given type object has a specified feature. #define Py_TPFLAGS_INLINE_VALUES (1 << 2) /* Placement of weakref pointers are managed by the VM, not by the type. - * The VM will automatically set tp_weaklistoffset. + * The VM will automatically set tp_weaklistoffset. Implies Py_TPFLAGS_HAVE_GC. */ #define Py_TPFLAGS_MANAGED_WEAKREF (1 << 3) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-13-12-58.gh-issue-134786.MF0VVk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-13-12-58.gh-issue-134786.MF0VVk.rst new file mode 100644 index 00000000000000..664e4d2db384ad --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-13-12-58.gh-issue-134786.MF0VVk.rst @@ -0,0 +1,2 @@ +If :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` +are used, then :c:macro:`Py_TPFLAGS_HAVE_GC` must be used as well. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7d03655e77a0bb..9e1b428422f0dc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8893,6 +8893,13 @@ type_ready_preheader(PyTypeObject *type) type->tp_name); return -1; } + if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) { + PyErr_Format(PyExc_SystemError, + "type %s has the Py_TPFLAGS_MANAGED_DICT flag " + "but not Py_TPFLAGS_HAVE_GC flag", + type->tp_name); + return -1; + } type->tp_dictoffset = -1; } if (type->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF) { @@ -8905,6 +8912,13 @@ type_ready_preheader(PyTypeObject *type) type->tp_name); return -1; } + if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) { + PyErr_Format(PyExc_SystemError, + "type %s has the Py_TPFLAGS_MANAGED_WEAKREF flag " + "but not Py_TPFLAGS_HAVE_GC flag", + type->tp_name); + return -1; + } type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET; } return 0;