diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 61646a0e3..84035eb3f 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -297,7 +297,6 @@ inline std::string error_string(); template struct instance_essentials { PyObject_HEAD type *value; - PyObject *dict; PyObject *weakrefs; bool owned : 1; bool constructed : 1; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 4836ca735..9cc57c121 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -574,24 +574,24 @@ public: NAMESPACE_BEGIN(detail) extern "C" inline PyObject *get_dict(PyObject *op, void *) { - auto *self = (instance *) op; - if (!self->dict) { - self->dict = PyDict_New(); + PyObject *&dict = *_PyObject_GetDictPtr(op); + if (!dict) { + dict = PyDict_New(); } - Py_XINCREF(self->dict); - return self->dict; + Py_XINCREF(dict); + return dict; } -extern "C" inline int set_dict(PyObject *op, PyObject *dict, void *) { - if (!PyDict_Check(dict)) { +extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) { + if (!PyDict_Check(new_dict)) { PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", - Py_TYPE(dict)->tp_name); + Py_TYPE(new_dict)->tp_name); return -1; } - auto *self = (instance *) op; - Py_INCREF(dict); - Py_CLEAR(self->dict); - self->dict = dict; + PyObject *&dict = *_PyObject_GetDictPtr(op); + Py_INCREF(new_dict); + Py_CLEAR(dict); + dict = new_dict; return 0; } @@ -714,7 +714,8 @@ protected: /* Support dynamic attributes */ if (rec->dynamic_attr) { type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC; - type->ht_type.tp_dictoffset = offsetof(instance_essentials, dict); + type->ht_type.tp_dictoffset = type->ht_type.tp_basicsize; // place the dict at the end + type->ht_type.tp_basicsize += sizeof(PyObject *); // and allocate enough space for it type->ht_type.tp_getset = generic_getset; type->ht_type.tp_traverse = traverse; type->ht_type.tp_clear = clear; @@ -822,20 +823,23 @@ protected: if (self->weakrefs) PyObject_ClearWeakRefs((PyObject *) self); - Py_CLEAR(self->dict); + PyObject **dict_ptr = _PyObject_GetDictPtr((PyObject *) self); + if (dict_ptr) { + Py_CLEAR(*dict_ptr); + } } Py_TYPE(self)->tp_free((PyObject*) self); } static int traverse(PyObject *op, visitproc visit, void *arg) { - auto *self = (instance *) op; - Py_VISIT(self->dict); + PyObject *&dict = *_PyObject_GetDictPtr(op); + Py_VISIT(dict); return 0; } static int clear(PyObject *op) { - auto *self = (instance *) op; - Py_CLEAR(self->dict); + PyObject *&dict = *_PyObject_GetDictPtr(op); + Py_CLEAR(dict); return 0; }