diff options
author | Victor Stinner <vstinner@python.org> | 2024-10-25 09:12:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-25 09:12:48 (GMT) |
commit | db96327203b09ada45f2214567f92fe4d837f82a (patch) | |
tree | 29febc64dbeff2a1ce81080519fca0437c2e54f8 /Objects | |
parent | da8673da362a2135cd621ac619d3aced6bb55100 (diff) | |
download | cpython-db96327203b09ada45f2214567f92fe4d837f82a.zip cpython-db96327203b09ada45f2214567f92fe4d837f82a.tar.gz cpython-db96327203b09ada45f2214567f92fe4d837f82a.tar.bz2 |
gh-121654: Add PyType_Freeze() function (#122457)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4d84382..b4a1119 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4637,6 +4637,32 @@ check_basicsize_includes_size_and_offsets(PyTypeObject* type) return 1; } +static int +check_immutable_bases(const char *type_name, PyObject *bases, int skip_first) +{ + Py_ssize_t i = 0; + if (skip_first) { + // When testing the MRO, skip the type itself + i = 1; + } + for (; i<PyTuple_GET_SIZE(bases); i++) { + PyTypeObject *b = (PyTypeObject*)PyTuple_GET_ITEM(bases, i); + if (!b) { + return -1; + } + if (!_PyType_HasFeature(b, Py_TPFLAGS_IMMUTABLETYPE)) { + PyErr_Format( + PyExc_TypeError, + "Creating immutable type %s from mutable base %N", + type_name, b + ); + return -1; + } + } + return 0; +} + + /* Set *dest to the offset specified by a special "__*offset__" member. * Return 0 on success, -1 on failure. */ @@ -4820,19 +4846,8 @@ PyType_FromMetaclass( * and only heap types can be mutable.) */ if (spec->flags & Py_TPFLAGS_IMMUTABLETYPE) { - for (int i=0; i<PyTuple_GET_SIZE(bases); i++) { - PyTypeObject *b = (PyTypeObject*)PyTuple_GET_ITEM(bases, i); - if (!b) { - goto finally; - } - if (!_PyType_HasFeature(b, Py_TPFLAGS_IMMUTABLETYPE)) { - PyErr_Format( - PyExc_TypeError, - "Creating immutable type %s from mutable base %N", - spec->name, b - ); - goto finally; - } + if (check_immutable_bases(spec->name, bases, 0) < 0) { + goto finally; } } @@ -11319,6 +11334,30 @@ add_operators(PyTypeObject *type) } +int +PyType_Freeze(PyTypeObject *type) +{ + // gh-121654: Check the __mro__ instead of __bases__ + PyObject *mro = type_get_mro(type, NULL); + if (!PyTuple_Check(mro)) { + Py_DECREF(mro); + PyErr_SetString(PyExc_TypeError, "unable to get the type MRO"); + return -1; + } + + int check = check_immutable_bases(type->tp_name, mro, 1); + Py_DECREF(mro); + if (check < 0) { + return -1; + } + + type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; + PyType_Modified(type); + + return 0; +} + + /* Cooperative 'super' */ typedef struct { |