@@ -117,17 +117,6 @@ static_builtin_index_clear(PyTypeObject *self)
117
117
}
118
118
119
119
120
- /* In 3.13+ this is stored in _PyRuntimeState. */
121
- static PyTypeObject static_type_defs [_Py_MAX_STATIC_BUILTIN_TYPES ];
122
-
123
- static inline PyTypeObject *
124
- static_builtin_get_def (PyTypeObject * type )
125
- {
126
- size_t index = static_builtin_index_get (type );
127
- return & static_type_defs [index ];
128
- }
129
-
130
-
131
120
static inline static_builtin_state *
132
121
static_builtin_state_get (PyInterpreterState * interp , PyTypeObject * self )
133
122
{
@@ -6994,7 +6983,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
6994
6983
return 0 ;
6995
6984
}
6996
6985
6997
- static int add_operators (PyTypeObject * , PyTypeObject * );
6986
+ static int add_operators (PyTypeObject * );
6998
6987
static int add_tp_new_wrapper (PyTypeObject * type );
6999
6988
7000
6989
#define COLLECTION_FLAGS (Py_TPFLAGS_SEQUENCE | Py_TPFLAGS_MAPPING)
@@ -7159,10 +7148,10 @@ type_dict_set_doc(PyTypeObject *type)
7159
7148
7160
7149
7161
7150
static int
7162
- type_ready_fill_dict (PyTypeObject * type , PyTypeObject * def )
7151
+ type_ready_fill_dict (PyTypeObject * type )
7163
7152
{
7164
7153
/* Add type-specific descriptors to tp_dict */
7165
- if (add_operators (type , def ) < 0 ) {
7154
+ if (add_operators (type ) < 0 ) {
7166
7155
return -1 ;
7167
7156
}
7168
7157
if (type_add_methods (type ) < 0 ) {
@@ -7474,7 +7463,7 @@ type_ready_post_checks(PyTypeObject *type)
7474
7463
7475
7464
7476
7465
static int
7477
- type_ready (PyTypeObject * type , PyTypeObject * def , int rerunbuiltin )
7466
+ type_ready (PyTypeObject * type , int rerunbuiltin )
7478
7467
{
7479
7468
_PyObject_ASSERT ((PyObject * )type , !is_readying (type ));
7480
7469
start_readying (type );
@@ -7511,7 +7500,7 @@ type_ready(PyTypeObject *type, PyTypeObject *def, int rerunbuiltin)
7511
7500
if (type_ready_set_new (type , rerunbuiltin ) < 0 ) {
7512
7501
goto error ;
7513
7502
}
7514
- if (type_ready_fill_dict (type , def ) < 0 ) {
7503
+ if (type_ready_fill_dict (type ) < 0 ) {
7515
7504
goto error ;
7516
7505
}
7517
7506
if (!rerunbuiltin ) {
@@ -7563,7 +7552,7 @@ PyType_Ready(PyTypeObject *type)
7563
7552
type -> tp_flags |= Py_TPFLAGS_IMMUTABLETYPE ;
7564
7553
}
7565
7554
7566
- return type_ready (type , NULL , 0 );
7555
+ return type_ready (type , 0 );
7567
7556
}
7568
7557
7569
7558
int
@@ -7593,12 +7582,7 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
7593
7582
7594
7583
static_builtin_state_init (interp , self );
7595
7584
7596
- PyTypeObject * def = static_builtin_get_def (self );
7597
- if (ismain ) {
7598
- memcpy (def , self , sizeof (PyTypeObject ));
7599
- }
7600
-
7601
- int res = type_ready (self , def , !ismain );
7585
+ int res = type_ready (self , !ismain );
7602
7586
if (res < 0 ) {
7603
7587
static_builtin_state_clear (interp , self );
7604
7588
}
@@ -10095,6 +10079,69 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
10095
10079
return 0 ;
10096
10080
}
10097
10081
10082
+ static int
10083
+ expect_manually_inherited (PyTypeObject * type , void * * slot )
10084
+ {
10085
+ PyObject * typeobj = (PyObject * )type ;
10086
+ if (slot == (void * )& type -> tp_init ) {
10087
+ /* This is a best-effort list of builtin exception types
10088
+ that have their own tp_init function. */
10089
+ if (typeobj != PyExc_BaseException
10090
+ && typeobj != PyExc_BaseExceptionGroup
10091
+ && typeobj != PyExc_ImportError
10092
+ && typeobj != PyExc_NameError
10093
+ && typeobj != PyExc_OSError
10094
+ && typeobj != PyExc_StopIteration
10095
+ && typeobj != PyExc_SyntaxError
10096
+ && typeobj != PyExc_UnicodeDecodeError
10097
+ && typeobj != PyExc_UnicodeEncodeError )
10098
+ {
10099
+ return 1 ;
10100
+ }
10101
+ }
10102
+ else if (slot == (void * )& type -> tp_str ) {
10103
+ /* This is a best-effort list of builtin exception types
10104
+ that have their own tp_str function. */
10105
+ if (typeobj == PyExc_AttributeError || typeobj == PyExc_NameError ) {
10106
+ return 1 ;
10107
+ }
10108
+ }
10109
+ else if (slot == (void * )& type -> tp_getattr
10110
+ || slot == (void * )& type -> tp_getattro )
10111
+ {
10112
+ /* This is a best-effort list of builtin types
10113
+ that have their own tp_getattr function. */
10114
+ if (typeobj == PyExc_BaseException
10115
+ || type == & PyBool_Type
10116
+ || type == & PyByteArray_Type
10117
+ || type == & PyBytes_Type
10118
+ || type == & PyClassMethod_Type
10119
+ || type == & PyComplex_Type
10120
+ || type == & PyDict_Type
10121
+ || type == & PyEnum_Type
10122
+ || type == & PyFilter_Type
10123
+ || type == & PyLong_Type
10124
+ || type == & PyList_Type
10125
+ || type == & PyMap_Type
10126
+ || type == & PyMemoryView_Type
10127
+ || type == & PyProperty_Type
10128
+ || type == & PyRange_Type
10129
+ || type == & PyReversed_Type
10130
+ || type == & PySet_Type
10131
+ || type == & PySlice_Type
10132
+ || type == & PyStaticMethod_Type
10133
+ || type == & PySuper_Type
10134
+ || type == & PyTuple_Type
10135
+ || type == & PyZip_Type )
10136
+ {
10137
+ return 1 ;
10138
+ }
10139
+ }
10140
+
10141
+ /* It must be inherited (see type_ready_inherit()).. */
10142
+ return 0 ;
10143
+ }
10144
+
10098
10145
/* This function is called by PyType_Ready() to populate the type's
10099
10146
dictionary with method descriptors for function slots. For each
10100
10147
function slot (like tp_repr) that's defined in the type, one or more
@@ -10126,24 +10173,39 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
10126
10173
infinite recursion here.) */
10127
10174
10128
10175
static int
10129
- add_operators (PyTypeObject * type , PyTypeObject * def )
10176
+ add_operators (PyTypeObject * type )
10130
10177
{
10131
10178
PyObject * dict = lookup_tp_dict (type );
10132
10179
pytype_slotdef * p ;
10133
10180
PyObject * descr ;
10134
10181
void * * ptr ;
10135
10182
10136
- assert (def == NULL || (type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
10137
- if (def == NULL ) {
10138
- def = type ;
10139
- }
10140
-
10141
10183
for (p = slotdefs ; p -> name ; p ++ ) {
10142
10184
if (p -> wrapper == NULL )
10143
10185
continue ;
10144
- ptr = slotptr (def , p -> offset );
10186
+ ptr = slotptr (type , p -> offset );
10145
10187
if (!ptr || !* ptr )
10146
10188
continue ;
10189
+ if (type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN
10190
+ && type -> tp_base != NULL )
10191
+ {
10192
+ /* Also ignore when the type slot has been inherited. */
10193
+ void * * ptr_base = slotptr (type -> tp_base , p -> offset );
10194
+ if (ptr_base && * ptr == * ptr_base ) {
10195
+ /* Ideally we would always ignore any manually inherited
10196
+ slots, Which would mean inheriting the slot wrapper
10197
+ using normal attribute lookup rather than keeping
10198
+ a distinct copy. However, that would introduce
10199
+ a slight change in behavior that could break
10200
+ existing code.
10201
+
10202
+ In the meantime, look the other way when the definition
10203
+ explicitly inherits the slot. */
10204
+ if (!expect_manually_inherited (type , ptr )) {
10205
+ continue ;
10206
+ }
10207
+ }
10208
+ }
10147
10209
int r = PyDict_Contains (dict , p -> name_strobj );
10148
10210
if (r > 0 )
10149
10211
continue ;
0 commit comments