bpo-32388: Remove cross-version binary compatibility requirement in tp_flags (GH-4944)
It is now allowed to add new fields at the end of the PyTypeObject struct without having to allocate a dedicated compatibility flag in tp_flags. This will reduce the risk of running out of bits in the 32-bit tp_flags value.
This commit is contained in:
parent
43fdbd2729
commit
ada319bb6d
|
@ -1099,6 +1099,11 @@ and :c:type:`PyType_Type` effectively act as defaults.)
|
|||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. deprecated:: 3.8
|
||||
This flag isn't necessary anymore, as the interpreter assumes the
|
||||
:c:member:`~PyTypeObject.tp_finalize` slot is always present in the
|
||||
type structure.
|
||||
|
||||
|
||||
.. c:member:: const char* PyTypeObject.tp_doc
|
||||
|
||||
|
|
|
@ -1265,6 +1265,15 @@ Changes in the C API
|
|||
|
||||
(Contributed by Zackery Spytz in :issue:`33407`.)
|
||||
|
||||
* The interpreter does not pretend to support binary compatibility of
|
||||
extension types accross feature releases, anymore. A :c:type:`PyTypeObject`
|
||||
exported by a third-party extension module is supposed to have all the
|
||||
slots expected in the current Python version, including
|
||||
:c:member:`~PyTypeObject.tp_finalize` (:const:`Py_TPFLAGS_HAVE_FINALIZE`
|
||||
is not checked anymore before reading :c:member:`~PyTypeObject.tp_finalize`).
|
||||
|
||||
(Contributed by Antoine Pitrou in :issue:`32388`.)
|
||||
|
||||
|
||||
CPython bytecode changes
|
||||
------------------------
|
||||
|
|
|
@ -263,17 +263,14 @@ PyAPI_FUNC(void) Py_ReprLeave(PyObject *);
|
|||
#define Py_PRINT_RAW 1 /* No string quotes etc. */
|
||||
|
||||
/*
|
||||
`Type flags (tp_flags)
|
||||
Type flags (tp_flags)
|
||||
|
||||
These flags are used to extend the type structure in a backwards-compatible
|
||||
fashion. Extensions can use the flags to indicate (and test) when a given
|
||||
type structure contains a new feature. The Python core will use these when
|
||||
introducing new functionality between major revisions (to avoid mid-version
|
||||
changes in the PYTHON_API_VERSION).
|
||||
These flags are used to change expected features and behavior for a
|
||||
particular type.
|
||||
|
||||
Arbitration of the flag bit positions will need to be coordinated among
|
||||
all extension writers who publicly release their extensions (this will
|
||||
be fewer than you might expect!)..
|
||||
be fewer than you might expect!).
|
||||
|
||||
Most flags were removed as of Python 3.0 to make room for new flags. (Some
|
||||
flags are not for backwards compatibility but to indicate the presence of an
|
||||
|
@ -302,7 +299,7 @@ given type object has a specified feature.
|
|||
/* Set while the type is being 'readied', to prevent recursive ready calls */
|
||||
#define Py_TPFLAGS_READYING (1UL << 13)
|
||||
|
||||
/* Objects support garbage collection (see objimp.h) */
|
||||
/* Objects support garbage collection (see objimpl.h) */
|
||||
#define Py_TPFLAGS_HAVE_GC (1UL << 14)
|
||||
|
||||
/* These two bits are preserved for Stackless Python, next after this is 17 */
|
||||
|
@ -340,6 +337,11 @@ given type object has a specified feature.
|
|||
/* NOTE: The following flags reuse lower bits (removed as part of the
|
||||
* Python 3.0 transition). */
|
||||
|
||||
/* The following flag is kept for compatibility. Starting with 3.8,
|
||||
* binary compatibility of C extensions accross feature releases of
|
||||
* Python is not supported anymore, except when using the stable ABI.
|
||||
*/
|
||||
|
||||
/* Type structure has tp_finalize member (3.4) */
|
||||
#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 0)
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Remove cross-version binary compatibility requirement in tp_flags.
|
|
@ -1430,8 +1430,7 @@ static PyTypeObject FutureType = {
|
|||
.tp_dealloc = FutureObj_dealloc,
|
||||
.tp_as_async = &FutureType_as_async,
|
||||
.tp_repr = (reprfunc)FutureObj_repr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_FINALIZE,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
|
||||
.tp_doc = _asyncio_Future___init____doc__,
|
||||
.tp_traverse = (traverseproc)FutureObj_traverse,
|
||||
.tp_clear = (inquiry)FutureObj_clear,
|
||||
|
@ -2461,8 +2460,7 @@ static PyTypeObject TaskType = {
|
|||
.tp_dealloc = TaskObj_dealloc,
|
||||
.tp_as_async = &FutureType_as_async,
|
||||
.tp_repr = (reprfunc)FutureObj_repr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_FINALIZE,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
|
||||
.tp_doc = _asyncio_Task___init____doc__,
|
||||
.tp_traverse = (traverseproc)TaskObj_traverse,
|
||||
.tp_clear = (inquiry)TaskObj_clear,
|
||||
|
|
|
@ -2342,8 +2342,7 @@ PyTypeObject PyBufferedIOBase_Type = {
|
|||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
bufferediobase_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
@ -2434,7 +2433,7 @@ PyTypeObject PyBufferedReader_Type = {
|
|||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
_io_BufferedReader___init____doc__, /* tp_doc */
|
||||
(traverseproc)buffered_traverse, /* tp_traverse */
|
||||
(inquiry)buffered_clear, /* tp_clear */
|
||||
|
@ -2520,7 +2519,7 @@ PyTypeObject PyBufferedWriter_Type = {
|
|||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
_io_BufferedWriter___init____doc__, /* tp_doc */
|
||||
(traverseproc)buffered_traverse, /* tp_traverse */
|
||||
(inquiry)buffered_clear, /* tp_clear */
|
||||
|
@ -2597,7 +2596,7 @@ PyTypeObject PyBufferedRWPair_Type = {
|
|||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
_io_BufferedRWPair___init____doc__, /* tp_doc */
|
||||
(traverseproc)bufferedrwpair_traverse, /* tp_traverse */
|
||||
(inquiry)bufferedrwpair_clear, /* tp_clear */
|
||||
|
@ -2691,7 +2690,7 @@ PyTypeObject PyBufferedRandom_Type = {
|
|||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
_io_BufferedRandom___init____doc__, /* tp_doc */
|
||||
(traverseproc)buffered_traverse, /* tp_traverse */
|
||||
(inquiry)buffered_clear, /* tp_clear */
|
||||
|
|
|
@ -1200,12 +1200,12 @@ PyTypeObject PyFileIO_Type = {
|
|||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
_io_FileIO___init____doc__, /* tp_doc */
|
||||
(traverseproc)fileio_traverse, /* tp_traverse */
|
||||
(inquiry)fileio_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(fileio, weakreflist), /* tp_weaklistoffset */
|
||||
offsetof(fileio, weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
fileio_methods, /* tp_methods */
|
||||
|
@ -1215,7 +1215,7 @@ PyTypeObject PyFileIO_Type = {
|
|||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(fileio, dict), /* tp_dictoffset */
|
||||
offsetof(fileio, dict), /* tp_dictoffset */
|
||||
_io_FileIO___init__, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
fileio_new, /* tp_new */
|
||||
|
|
|
@ -856,7 +856,7 @@ PyTypeObject PyIOBase_Type = {
|
|||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
iobase_doc, /* tp_doc */
|
||||
(traverseproc)iobase_traverse, /* tp_traverse */
|
||||
(inquiry)iobase_clear, /* tp_clear */
|
||||
|
@ -1051,7 +1051,7 @@ PyTypeObject PyRawIOBase_Type = {
|
|||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
rawiobase_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
|
|
@ -183,8 +183,7 @@ PyTypeObject PyTextIOBase_Type = {
|
|||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
textiobase_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
@ -3258,7 +3257,7 @@ PyTypeObject PyTextIOWrapper_Type = {
|
|||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
|
||||
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
||||
_io_TextIOWrapper___init____doc__, /* tp_doc */
|
||||
(traverseproc)textiowrapper_traverse, /* tp_traverse */
|
||||
(inquiry)textiowrapper_clear, /* tp_clear */
|
||||
|
|
|
@ -1133,7 +1133,7 @@ PyTypeObject PyWindowsConsoleIO_Type = {
|
|||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
_io__WindowsConsoleIO___init____doc__, /* tp_doc */
|
||||
(traverseproc)winconsoleio_traverse, /* tp_traverse */
|
||||
(inquiry)winconsoleio_clear, /* tp_clear */
|
||||
|
|
|
@ -98,7 +98,7 @@ static PyType_Spec Example_Type_spec = {
|
|||
"_testimportexec.Example",
|
||||
sizeof(ExampleObject),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
Example_Type_slots
|
||||
};
|
||||
|
||||
|
|
|
@ -858,7 +858,6 @@ finalize_garbage(PyGC_Head *collectable)
|
|||
PyObject *op = FROM_GC(gc);
|
||||
gc_list_move(gc, &seen);
|
||||
if (!_PyGCHead_FINALIZED(gc) &&
|
||||
PyType_HasFeature(Py_TYPE(op), Py_TPFLAGS_HAVE_FINALIZE) &&
|
||||
(finalize = Py_TYPE(op)->tp_finalize) != NULL) {
|
||||
_PyGCHead_SET_FINALIZED(gc);
|
||||
Py_INCREF(op);
|
||||
|
|
|
@ -13032,8 +13032,7 @@ static PyTypeObject ScandirIteratorType = {
|
|||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT
|
||||
| Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
|
|
@ -5286,8 +5286,7 @@ static PyTypeObject sock_type = {
|
|||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
sock_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
|
|
@ -123,7 +123,7 @@ static PyType_Spec Xxo_Type_spec = {
|
|||
"xxlimited.Xxo",
|
||||
sizeof(XxoObject),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
Xxo_Type_slots
|
||||
};
|
||||
|
||||
|
|
|
@ -742,8 +742,7 @@ PyTypeObject PyGen_Type = {
|
|||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)gen_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
@ -997,8 +996,7 @@ PyTypeObject PyCoro_Type = {
|
|||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)gen_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
@ -1394,8 +1392,7 @@ PyTypeObject PyAsyncGen_Type = {
|
|||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)async_gen_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
|
|
|
@ -298,10 +298,7 @@ PyObject_CallFinalizer(PyObject *self)
|
|||
{
|
||||
PyTypeObject *tp = Py_TYPE(self);
|
||||
|
||||
/* The former could happen on heaptypes created from the C API, e.g.
|
||||
PyType_FromSpec(). */
|
||||
if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_FINALIZE) ||
|
||||
tp->tp_finalize == NULL)
|
||||
if (tp->tp_finalize == NULL)
|
||||
return;
|
||||
/* tp_finalize should only be called once. */
|
||||
if (PyType_IS_GC(tp) && _PyGC_FINALIZED(self))
|
||||
|
|
|
@ -248,8 +248,8 @@ PyType_Modified(PyTypeObject *type)
|
|||
Invariants:
|
||||
|
||||
- Py_TPFLAGS_VALID_VERSION_TAG is never set if
|
||||
Py_TPFLAGS_HAVE_VERSION_TAG is not set (e.g. on type
|
||||
objects coming from non-recompiled extension modules)
|
||||
Py_TPFLAGS_HAVE_VERSION_TAG is not set (in case of a
|
||||
bizarre MRO, see type_mro_modified()).
|
||||
|
||||
- before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type,
|
||||
it must first be set on all super types.
|
||||
|
@ -2571,7 +2571,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
|||
|
||||
/* Initialize tp_flags */
|
||||
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
|
||||
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE;
|
||||
Py_TPFLAGS_BASETYPE;
|
||||
if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
|
||||
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||
|
||||
|
@ -5179,10 +5179,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
|||
COPYSLOT(tp_init);
|
||||
COPYSLOT(tp_alloc);
|
||||
COPYSLOT(tp_is_gc);
|
||||
if ((type->tp_flags & Py_TPFLAGS_HAVE_FINALIZE) &&
|
||||
(base->tp_flags & Py_TPFLAGS_HAVE_FINALIZE)) {
|
||||
COPYSLOT(tp_finalize);
|
||||
}
|
||||
COPYSLOT(tp_finalize);
|
||||
if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) ==
|
||||
(base->tp_flags & Py_TPFLAGS_HAVE_GC)) {
|
||||
/* They agree about gc. */
|
||||
|
|
Loading…
Reference in New Issue