66#include " ProxyWrappers.h"
77#include " PyStrings.h"
88
9+ // As of Python 3.12, we can't use the PyMethod_GET_FUNCTION and
10+ // PyMethod_GET_SELF macros anymore, as the contain asserts that check if the
11+ // Python type is actually PyMethod_Type. If the Python type is
12+ // CustomInstanceMethod_Type, we need our own macros. Technically they do they
13+ // same, because the actual C++ type of the PyObject is PyMethodObject anyway.
14+ #define CustomInstanceMethod_GET_SELF (meth ) reinterpret_cast <PyMethodObject *>(meth)->im_self
15+ #define CustomInstanceMethod_GET_FUNCTION (meth ) reinterpret_cast <PyMethodObject *>(meth)->im_func
916#if PY_VERSION_HEX >= 0x03000000
1017// TODO: this will break functionality
11- #define PyMethod_GET_CLASS (meth ) Py_None
18+ #define CustomInstanceMethod_GET_CLASS (meth ) Py_None
19+ #else
20+ #define CustomInstanceMethod_GET_CLASS (meth ) PyMethod_GET_CLASS(meth)
1221#endif
1322
14-
1523namespace CPyCppyy {
1624
1725#if PY_VERSION_HEX < 0x03000000
@@ -156,6 +164,12 @@ PyTypeObject TypedefPointerToClass_Type = {
156164#if PY_VERSION_HEX >= 0x03040000
157165 , 0 // tp_finalize
158166#endif
167+ #if PY_VERSION_HEX >= 0x03080000
168+ , 0 // tp_vectorcall
169+ #endif
170+ #if PY_VERSION_HEX >= 0x030c0000
171+ , 0 // tp_watched
172+ #endif
159173};
160174
161175// = instancemethod object with a more efficient call function ================
@@ -237,13 +251,13 @@ static PyObject* im_call(PyObject* meth, PyObject* args, PyObject* kw)
237251// into the list of arguments. However, the pythonized methods will then have
238252// to undo that shuffling, which is inefficient. This method is the same as
239253// the one for the instancemethod object, except for the shuffling.
240- PyObject* self = PyMethod_GET_SELF (meth);
254+ PyObject* self = CustomInstanceMethod_GET_SELF (meth);
241255
242256 if (!self) {
243257 // unbound methods must be called with an instance of the class (or a
244258 // derived class) as first argument
245259 Py_ssize_t argc = PyTuple_GET_SIZE (args);
246- PyObject* pyclass = PyMethod_GET_CLASS (meth);
260+ PyObject* pyclass = CustomInstanceMethod_GET_CLASS (meth);
247261 if (1 <= argc && PyObject_IsInstance (PyTuple_GET_ITEM (args, 0 ), pyclass) == 1 ) {
248262 self = PyTuple_GET_ITEM (args, 0 );
249263
@@ -262,7 +276,7 @@ static PyObject* im_call(PyObject* meth, PyObject* args, PyObject* kw)
262276 } else
263277 Py_INCREF (args);
264278
265- PyCFunctionObject* func = (PyCFunctionObject*)PyMethod_GET_FUNCTION (meth);
279+ PyCFunctionObject* func = (PyCFunctionObject*)CustomInstanceMethod_GET_FUNCTION (meth);
266280
267281// the function is globally shared, so set and reset its "self" (ok, b/c of GIL)
268282 Py_INCREF (self);
@@ -279,10 +293,10 @@ static PyObject* im_descr_get(PyObject* meth, PyObject* obj, PyObject* pyclass)
279293{
280294// from instancemethod: don't rebind an already bound method, or an unbound method
281295// of a class that's not a base class of pyclass
282- if (PyMethod_GET_SELF (meth)
296+ if (CustomInstanceMethod_GET_SELF (meth)
283297#if PY_VERSION_HEX < 0x03000000
284- || (PyMethod_GET_CLASS (meth) &&
285- !PyObject_IsSubclass (pyclass, PyMethod_GET_CLASS (meth)))
298+ || (CustomInstanceMethod_GET_CLASS (meth) &&
299+ !PyObject_IsSubclass (pyclass, CustomInstanceMethod_GET_CLASS (meth)))
286300#endif
287301 ) {
288302 Py_INCREF (meth);
@@ -292,7 +306,7 @@ static PyObject* im_descr_get(PyObject* meth, PyObject* obj, PyObject* pyclass)
292306 if (obj == Py_None)
293307 obj = nullptr ;
294308
295- return CustomInstanceMethod_New (PyMethod_GET_FUNCTION (meth), obj, pyclass);
309+ return CustomInstanceMethod_New (CustomInstanceMethod_GET_FUNCTION (meth), obj, pyclass);
296310}
297311
298312// = CPyCppyy custom instance method type =====================================
@@ -321,6 +335,12 @@ PyTypeObject CustomInstanceMethod_Type = {
321335#if PY_VERSION_HEX >= 0x03040000
322336 , 0 // tp_finalize
323337#endif
338+ #if PY_VERSION_HEX >= 0x03080000
339+ , 0 // tp_vectorcall
340+ #endif
341+ #if PY_VERSION_HEX >= 0x030c0000
342+ , 0 // tp_watched
343+ #endif
324344};
325345
326346
@@ -372,6 +392,12 @@ PyTypeObject IndexIter_Type = {
372392#if PY_VERSION_HEX >= 0x03040000
373393 , 0 // tp_finalize
374394#endif
395+ #if PY_VERSION_HEX >= 0x03080000
396+ , 0 // tp_vectorcall
397+ #endif
398+ #if PY_VERSION_HEX >= 0x030c0000
399+ , 0 // tp_watched
400+ #endif
375401};
376402
377403
@@ -394,7 +420,10 @@ static PyObject* vectoriter_iternext(vectoriterobject* vi) {
394420 // that objects in vectors are simple and thus do not need to maintain object identity
395421 // (or at least not during the loop anyway). This gains 2x in performance.
396422 Cppyy::TCppObject_t cppobj = (Cppyy::TCppObject_t)((ptrdiff_t )vi->vi_data + vi->vi_stride * vi->ii_pos );
397- result = CPyCppyy::BindCppObjectNoCast (cppobj, vi->vi_klass , CPyCppyy::CPPInstance::kNoMemReg );
423+ if (vi->vi_flags & vectoriterobject::kIsPolymorphic )
424+ result = CPyCppyy::BindCppObject (*(void **)cppobj, vi->vi_klass , CPyCppyy::CPPInstance::kNoMemReg );
425+ else
426+ result = CPyCppyy::BindCppObjectNoCast (cppobj, vi->vi_klass , CPyCppyy::CPPInstance::kNoMemReg );
398427 if ((vi->vi_flags & vectoriterobject::kNeedLifeLine ) && result)
399428 PyObject_SetAttr (result, PyStrings::gLifeLine , vi->ii_container );
400429 } else {
@@ -431,6 +460,12 @@ PyTypeObject VectorIter_Type = {
431460#if PY_VERSION_HEX >= 0x03040000
432461 , 0 // tp_finalize
433462#endif
463+ #if PY_VERSION_HEX >= 0x03080000
464+ , 0 // tp_vectorcall
465+ #endif
466+ #if PY_VERSION_HEX >= 0x030c0000
467+ , 0 // tp_watched
468+ #endif
434469};
435470
436471} // namespace CPyCppyy
0 commit comments