summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorBrandt Bucher <brandt@python.org>2021-06-25 15:20:43 (GMT)
committerGitHub <noreply@github.com>2021-06-25 15:20:43 (GMT)
commitca2009d72a52a98bf43aafa9ad270a4fcfabfc89 (patch)
tree0a3292c93a7eaa2085df03431ec9ccc65fd55fa4 /Modules
parent22e7effad571f8e524d2f71ff55bbf2a25306753 (diff)
downloadcpython-ca2009d72a52a98bf43aafa9ad270a4fcfabfc89.zip
cpython-ca2009d72a52a98bf43aafa9ad270a4fcfabfc89.tar.gz
cpython-ca2009d72a52a98bf43aafa9ad270a4fcfabfc89.tar.bz2
bpo-43977: Properly update the tp_flags of existing subclasses when their parents are registered (GH-26864)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_abc.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/Modules/_abc.c b/Modules/_abc.c
index 7720d40..8aa6835 100644
--- a/Modules/_abc.c
+++ b/Modules/_abc.c
@@ -481,6 +481,32 @@ _abc__abc_init(PyObject *module, PyObject *self)
Py_RETURN_NONE;
}
+static void
+set_collection_flag_recursive(PyTypeObject *child, unsigned long flag)
+{
+ assert(flag == Py_TPFLAGS_MAPPING || flag == Py_TPFLAGS_SEQUENCE);
+ if (PyType_HasFeature(child, Py_TPFLAGS_IMMUTABLETYPE) ||
+ (child->tp_flags & COLLECTION_FLAGS) == flag)
+ {
+ return;
+ }
+ child->tp_flags &= ~COLLECTION_FLAGS;
+ child->tp_flags |= flag;
+ PyObject *grandchildren = child->tp_subclasses;
+ if (grandchildren == NULL) {
+ return;
+ }
+ assert(PyDict_CheckExact(grandchildren));
+ Py_ssize_t i = 0;
+ while (PyDict_Next(grandchildren, &i, NULL, &grandchildren)) {
+ assert(PyWeakref_CheckRef(grandchildren));
+ PyObject *grandchild = PyWeakref_GET_OBJECT(grandchildren);
+ if (PyType_Check(grandchild)) {
+ set_collection_flag_recursive((PyTypeObject *)grandchild, flag);
+ }
+ }
+}
+
/*[clinic input]
_abc._abc_register
@@ -532,12 +558,11 @@ _abc__abc_register_impl(PyObject *module, PyObject *self, PyObject *subclass)
get_abc_state(module)->abc_invalidation_counter++;
/* Set Py_TPFLAGS_SEQUENCE or Py_TPFLAGS_MAPPING flag */
- if (PyType_Check(self) &&
- !PyType_HasFeature((PyTypeObject *)subclass, Py_TPFLAGS_IMMUTABLETYPE) &&
- ((PyTypeObject *)self)->tp_flags & COLLECTION_FLAGS)
- {
- ((PyTypeObject *)subclass)->tp_flags &= ~COLLECTION_FLAGS;
- ((PyTypeObject *)subclass)->tp_flags |= (((PyTypeObject *)self)->tp_flags & COLLECTION_FLAGS);
+ if (PyType_Check(self)) {
+ unsigned long collection_flag = ((PyTypeObject *)self)->tp_flags & COLLECTION_FLAGS;
+ if (collection_flag) {
+ set_collection_flag_recursive((PyTypeObject *)subclass, collection_flag);
+ }
}
Py_INCREF(subclass);
return subclass;