Skip to content

Commit 13d52f0

Browse files
committed
- Big changes to fix SF bug #442833 (a nasty multiple inheritance
problem). inherit_slots() is split in two parts: inherit_special() which inherits the flags and a few very special members from the dominant base; inherit_slots() which inherits only regular slots, and is now called for each base in the MRO in turn. These are now both void functions since they don't have error returns. - Added object.__setitem__() back -- for the same reason as object.__new__(): a subclass of object should be able to call object.__new__(). - add_wrappers() was moved around to be closer to where it is used (it was defined together with add_methods() etc., but has nothing to do with these).
1 parent f24b2f3 commit 13d52f0

File tree

1 file changed

+122
-91
lines changed

1 file changed

+122
-91
lines changed

Objects/typeobject.c

+122-91
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#include "Python.h"
55
#include "structmember.h"
66

7-
staticforward int add_members(PyTypeObject *, struct memberlist *);
8-
97
static struct memberlist type_members[] = {
108
{"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
119
{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
@@ -647,7 +645,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
647645
slotoffset += sizeof(PyObject *);
648646
}
649647
type->tp_basicsize = slotoffset;
650-
add_members(type, et->members);
648+
type->tp_members = et->members;
651649

652650
/* Special case some slots */
653651
if (type->tp_dictoffset != 0 || nslots > 0) {
@@ -882,7 +880,7 @@ PyTypeObject PyBaseObject_Type = {
882880
0, /* tp_call */
883881
0, /* tp_str */
884882
PyObject_GenericGetAttr, /* tp_getattro */
885-
0, /* tp_setattro */
883+
PyObject_GenericSetAttr, /* tp_setattro */
886884
0, /* tp_as_buffer */
887885
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
888886
"The most base type", /* tp_doc */
@@ -928,25 +926,6 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
928926
return 0;
929927
}
930928

931-
static int
932-
add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
933-
{
934-
PyObject *dict = type->tp_defined;
935-
936-
for (; wraps->name != NULL; wraps++) {
937-
PyObject *descr;
938-
if (PyDict_GetItemString(dict, wraps->name))
939-
continue;
940-
descr = PyDescr_NewWrapper(type, wraps, wrapped);
941-
if (descr == NULL)
942-
return -1;
943-
if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
944-
return -1;
945-
Py_DECREF(descr);
946-
}
947-
return 0;
948-
}
949-
950929
static int
951930
add_members(PyTypeObject *type, struct memberlist *memb)
952931
{
@@ -986,27 +965,90 @@ add_getset(PyTypeObject *type, struct getsetlist *gsp)
986965
return 0;
987966
}
988967

989-
staticforward int add_operators(PyTypeObject *);
968+
static void
969+
inherit_special(PyTypeObject *type, PyTypeObject *base)
970+
{
971+
int oldsize, newsize;
990972

991-
static int
973+
/* Special flag magic */
974+
if (!type->tp_as_buffer && base->tp_as_buffer) {
975+
type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
976+
type->tp_flags |=
977+
base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
978+
}
979+
if (!type->tp_as_sequence && base->tp_as_sequence) {
980+
type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
981+
type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
982+
}
983+
if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
984+
(base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
985+
if ((!type->tp_as_number && base->tp_as_number) ||
986+
(!type->tp_as_sequence && base->tp_as_sequence)) {
987+
type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
988+
if (!type->tp_as_number && !type->tp_as_sequence) {
989+
type->tp_flags |= base->tp_flags &
990+
Py_TPFLAGS_HAVE_INPLACEOPS;
991+
}
992+
}
993+
/* Wow */
994+
}
995+
if (!type->tp_as_number && base->tp_as_number) {
996+
type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
997+
type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
998+
}
999+
1000+
/* Copying basicsize is connected to the GC flags */
1001+
oldsize = PyType_BASICSIZE(base);
1002+
newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
1003+
if (!(type->tp_flags & Py_TPFLAGS_GC) &&
1004+
(base->tp_flags & Py_TPFLAGS_GC) &&
1005+
(type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
1006+
(!type->tp_traverse && !type->tp_clear)) {
1007+
type->tp_flags |= Py_TPFLAGS_GC;
1008+
if (type->tp_traverse == NULL)
1009+
type->tp_traverse = base->tp_traverse;
1010+
if (type->tp_clear == NULL)
1011+
type->tp_clear = base->tp_clear;
1012+
}
1013+
if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
1014+
if (base != &PyBaseObject_Type ||
1015+
(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
1016+
if (type->tp_new == NULL)
1017+
type->tp_new = base->tp_new;
1018+
}
1019+
}
1020+
PyType_SET_BASICSIZE(type, newsize);
1021+
}
1022+
1023+
static void
9921024
inherit_slots(PyTypeObject *type, PyTypeObject *base)
9931025
{
994-
int oldsize, newsize;
1026+
PyTypeObject *basebase;
9951027

1028+
#undef SLOTDEFINED
9961029
#undef COPYSLOT
9971030
#undef COPYNUM
9981031
#undef COPYSEQ
9991032
#undef COPYMAP
1033+
1034+
#define SLOTDEFINED(SLOT) \
1035+
(base->SLOT != 0 && \
1036+
(basebase == NULL || base->SLOT != basebase->SLOT))
1037+
10001038
#define COPYSLOT(SLOT) \
1001-
if (!type->SLOT) type->SLOT = base->SLOT
1039+
if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT
10021040

10031041
#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
10041042
#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
10051043
#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
10061044

1007-
if (type->tp_as_number == NULL)
1008-
type->tp_as_number = base->tp_as_number;
1009-
else if (base->tp_as_number) {
1045+
/* This won't inherit indirect slots (from tp_as_number etc.)
1046+
if type doesn't provide the space. */
1047+
1048+
if (type->tp_as_number != NULL && base->tp_as_number != NULL) {
1049+
basebase = base->tp_base;
1050+
if (basebase->tp_as_number == NULL)
1051+
basebase = NULL;
10101052
COPYNUM(nb_add);
10111053
COPYNUM(nb_subtract);
10121054
COPYNUM(nb_multiply);
@@ -1049,9 +1091,10 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
10491091
}
10501092
}
10511093

1052-
if (type->tp_as_sequence == NULL)
1053-
type->tp_as_sequence = base->tp_as_sequence;
1054-
else if (base->tp_as_sequence) {
1094+
if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) {
1095+
basebase = base->tp_base;
1096+
if (basebase->tp_as_sequence == NULL)
1097+
basebase = NULL;
10551098
COPYSEQ(sq_length);
10561099
COPYSEQ(sq_concat);
10571100
COPYSEQ(sq_repeat);
@@ -1064,53 +1107,16 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
10641107
COPYSEQ(sq_inplace_repeat);
10651108
}
10661109

1067-
if (type->tp_as_mapping == NULL)
1068-
type->tp_as_mapping = base->tp_as_mapping;
1069-
else if (base->tp_as_mapping) {
1110+
if (type->tp_as_mapping != NULL && base->tp_as_mapping != NULL) {
1111+
basebase = base->tp_base;
1112+
if (basebase->tp_as_mapping == NULL)
1113+
basebase = NULL;
10701114
COPYMAP(mp_length);
10711115
COPYMAP(mp_subscript);
10721116
COPYMAP(mp_ass_subscript);
10731117
}
10741118

1075-
/* Special flag magic */
1076-
if (!type->tp_as_buffer && base->tp_as_buffer) {
1077-
type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
1078-
type->tp_flags |=
1079-
base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
1080-
}
1081-
if (!type->tp_as_sequence && base->tp_as_sequence) {
1082-
type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
1083-
type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
1084-
}
1085-
if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
1086-
(base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
1087-
if ((!type->tp_as_number && base->tp_as_number) ||
1088-
(!type->tp_as_sequence && base->tp_as_sequence)) {
1089-
type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
1090-
if (!type->tp_as_number && !type->tp_as_sequence) {
1091-
type->tp_flags |= base->tp_flags &
1092-
Py_TPFLAGS_HAVE_INPLACEOPS;
1093-
}
1094-
}
1095-
/* Wow */
1096-
}
1097-
if (!type->tp_as_number && base->tp_as_number) {
1098-
type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
1099-
type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
1100-
}
1101-
1102-
/* Copying basicsize is connected to the GC flags */
1103-
oldsize = PyType_BASICSIZE(base);
1104-
newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
1105-
if (!(type->tp_flags & Py_TPFLAGS_GC) &&
1106-
(base->tp_flags & Py_TPFLAGS_GC) &&
1107-
(type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
1108-
(!type->tp_traverse && !type->tp_clear)) {
1109-
type->tp_flags |= Py_TPFLAGS_GC;
1110-
COPYSLOT(tp_traverse);
1111-
COPYSLOT(tp_clear);
1112-
}
1113-
PyType_SET_BASICSIZE(type, newsize);
1119+
basebase = base->tp_base;
11141120

11151121
COPYSLOT(tp_itemsize);
11161122
COPYSLOT(tp_dealloc);
@@ -1152,16 +1158,12 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
11521158
COPYSLOT(tp_dictoffset);
11531159
COPYSLOT(tp_init);
11541160
COPYSLOT(tp_alloc);
1155-
if (base != &PyBaseObject_Type ||
1156-
(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
1157-
COPYSLOT(tp_new);
1158-
}
11591161
COPYSLOT(tp_free);
11601162
}
1161-
1162-
return 0;
11631163
}
11641164

1165+
staticforward int add_operators(PyTypeObject *);
1166+
11651167
int
11661168
PyType_Ready(PyTypeObject *type)
11671169
{
@@ -1237,34 +1239,44 @@ PyType_Ready(PyTypeObject *type)
12371239
goto error;
12381240
}
12391241

1242+
/* Inherit special flags from dominant base */
1243+
if (type->tp_base != NULL)
1244+
inherit_special(type, type->tp_base);
1245+
12401246
/* Initialize tp_dict properly */
12411247
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
12421248
/* For a static type, tp_dict is the consolidation
1243-
of the tp_defined of its bases in MRO. Earlier
1244-
bases override later bases; since d.update() works
1245-
the other way, we walk the MRO sequence backwards. */
1249+
of the tp_defined of its bases in MRO. */
12461250
Py_DECREF(type->tp_dict);
1247-
type->tp_dict = PyDict_New();
1251+
type->tp_dict = PyDict_Copy(type->tp_defined);
12481252
if (type->tp_dict == NULL)
12491253
goto error;
12501254
bases = type->tp_mro;
12511255
assert(bases != NULL);
12521256
assert(PyTuple_Check(bases));
12531257
n = PyTuple_GET_SIZE(bases);
1254-
for (i = n; --i >= 0; ) {
1258+
for (i = 1; i < n; i++) {
12551259
base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
12561260
assert(PyType_Check(base));
12571261
x = base->tp_defined;
1258-
if (x != NULL && PyDict_Update(type->tp_dict, x) < 0)
1262+
if (x != NULL && PyDict_Merge(type->tp_dict, x, 0) < 0)
12591263
goto error;
1264+
inherit_slots(type, base);
12601265
}
12611266
}
12621267

1263-
/* Inherit slots from direct base */
1264-
if (type->tp_base != NULL)
1265-
if (inherit_slots(type, type->tp_base) < 0)
1266-
goto error;
1268+
/* Some more special stuff */
1269+
base = type->tp_base;
1270+
if (base != NULL) {
1271+
if (type->tp_as_number == NULL)
1272+
type->tp_as_number = base->tp_as_number;
1273+
if (type->tp_as_sequence == NULL)
1274+
type->tp_as_sequence = base->tp_as_sequence;
1275+
if (type->tp_as_mapping == NULL)
1276+
type->tp_as_mapping = base->tp_as_mapping;
1277+
}
12671278

1279+
/* All done -- set the ready flag */
12681280
assert(type->tp_dict != NULL);
12691281
type->tp_flags =
12701282
(type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
@@ -1911,6 +1923,25 @@ add_tp_new_wrapper(PyTypeObject *type)
19111923
return PyDict_SetItemString(type->tp_defined, "__new__", func);
19121924
}
19131925

1926+
static int
1927+
add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
1928+
{
1929+
PyObject *dict = type->tp_defined;
1930+
1931+
for (; wraps->name != NULL; wraps++) {
1932+
PyObject *descr;
1933+
if (PyDict_GetItemString(dict, wraps->name))
1934+
continue;
1935+
descr = PyDescr_NewWrapper(type, wraps, wrapped);
1936+
if (descr == NULL)
1937+
return -1;
1938+
if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
1939+
return -1;
1940+
Py_DECREF(descr);
1941+
}
1942+
return 0;
1943+
}
1944+
19141945
/* This function is called by PyType_Ready() to populate the type's
19151946
dictionary with method descriptors for function slots. For each
19161947
function slot (like tp_repr) that's defined in the type, one or

0 commit comments

Comments
 (0)