From c69e8c5d2d6f3c0116465c4d5bda52f4dc4e53ca Mon Sep 17 00:00:00 2001 From: mcbarton Date: Thu, 27 Aug 2026 14:48:23 +0100 Subject: [PATCH 1/5] Remove obsolete single_module flag --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 7f1433e..62d1d22 100644 --- a/test/Makefile +++ b/test/Makefile @@ -26,7 +26,7 @@ cppflags= -std=c++17 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; p PLATFORM := $(shell uname -s) ifeq ($(PLATFORM),Darwin) - cppflags+=-dynamiclib -single_module -undefined dynamic_lookup -Wno-delete-non-virtual-dtor + cppflags+=-dynamiclib -undefined dynamic_lookup -Wno-delete-non-virtual-dtor endif # a worker can load the library while another rebuilds it, so publish it whole From 55c879eb38a18723fb98349a0eafd7a2bd6b9665 Mon Sep 17 00:00:00 2001 From: mcbarton Date: Thu, 27 Aug 2026 16:39:45 +0100 Subject: [PATCH 2/5] Update warning flags and update test standard to C++20 --- CMakeLists.txt | 2 +- test/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 465d158..7722c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,7 +142,7 @@ target_include_directories(cppjit PRIVATE ) target_compile_options(cppjit PRIVATE - -Wall -Wno-strict-aliasing -Wno-register + -Wall -Wextra -Wno-strict-aliasing -Wno-register -Werror ) if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/test/Makefile b/test/Makefile index 62d1d22..0cd3372 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,7 +22,7 @@ dicts = $(addprefix cpp/,$(addsuffix Dict.so,$(dictnames))) all : $(dicts) PYTHON ?= python3 -cppflags= -std=c++17 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register +cppflags= -Wall -Wextra -Werror -std=c++20 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register PLATFORM := $(shell uname -s) ifeq ($(PLATFORM),Darwin) From fe4135f36449fd5fc3cad957c1d8d23d6fefec7c Mon Sep 17 00:00:00 2001 From: mcbarton Date: Thu, 27 Aug 2026 18:23:24 +0100 Subject: [PATCH 3/5] Try new fix Try to fix more warnings Try to fix more warnings Try to fix error Try fixes Revert "Try fixes" This reverts commit 1adc6fbca31032d32399498846c1f7452b84842a. Try partial fix Try fix Attempt partial fix Attempt partial fix Try partial fix Try fix Try fix Attempt fix Fix Test fix Test fix Test Test fix Revert "Test fix" This reverts commit e4eff56e553d3b7d8355b535d6b3d7404df3598d. Test fix Test fix Test fix Test fix Test fix Test fix Try fix Test fix Try fix Partial fix Revert "Partial fix" This reverts commit 1bee1a84b0e6b016724f00cf9dc8240acc8461ed. Revert test makefile changes Try fixing test Try to fix Revert "Try fixing test" This reverts commit 09db7cd4cd79ce04938d723f45eff9d3dcdc206b. Revert "Try fix" This reverts commit f0f32c1cbc95294251d385cb4c85cac3b47fa07c. Revert "Test fix" This reverts commit 88a03b155a06a95de7ae03685bcb36dc302676b7. Revert "Try fix" This reverts commit e32f2927c293cc4528de66d1e9ad8e79f075a19a. --- src/cpyrt/CPPEnum.cxx | 6 +- src/cpyrt/CPPInstance.cxx | 33 +++--- src/cpyrt/CPPOverload.cxx | 52 ++++++---- src/cpyrt/CPPScope.cxx | 5 +- src/cpyrt/LowLevelViews.cxx | 106 ++++++++++---------- src/cpyrt/MemoryRegulator.cxx | 7 +- src/cpyrt/Pythonize.cxx | 184 +++++++++++++++++++--------------- src/cpyrt/cpyrtModule.cxx | 8 +- test/Makefile | 2 +- 9 files changed, 220 insertions(+), 183 deletions(-) diff --git a/src/cpyrt/CPPEnum.cxx b/src/cpyrt/CPPEnum.cxx index 6585265..f64dad8 100644 --- a/src/cpyrt/CPPEnum.cxx +++ b/src/cpyrt/CPPEnum.cxx @@ -139,7 +139,7 @@ static PyTypeObject* GetCTypesType(const std::string& cppname) { return (PyTypeObject*)PyObject_GetAttrString(ctmod, nn->second.c_str()); } -static PyObject* enum_ctype(PyObject* cls, PyObject* args, PyObject* kwds) { +static PyObject* enum_ctype(PyObject* cls, PyObject* args) { PyObject* pyres = PyObject_GetAttr(cls, cpyrt::PyStrings::gUnderlying); if (!pyres) PyErr_Clear(); @@ -149,7 +149,7 @@ static PyObject* enum_ctype(PyObject* cls, PyObject* args, PyObject* kwds) { if (!ct) return nullptr; - return PyType_Type.tp_call((PyObject*)ct, args, kwds); + return PyType_Type.tp_call((PyObject*)ct, args, nullptr); } //- creation ----------------------------------------------------------------- @@ -213,7 +213,7 @@ cpyrt::CPPEnum* cpyrt::CPPEnum_New(const std::string& name, // add pythonizations Utility::AddToClass((PyObject*)Py_TYPE(pyenum), "__ctype__", - (PyCFunction)enum_ctype, METH_VARARGS | METH_KEYWORDS); + enum_ctype, METH_VARARGS); ((PyTypeObject*)pyenum)->tp_repr = enum_repr; ((PyTypeObject*)pyenum)->tp_str = ((PyTypeObject*)pyside_type)->tp_repr; diff --git a/src/cpyrt/CPPInstance.cxx b/src/cpyrt/CPPInstance.cxx index 59cde8a..9d9c9d7 100644 --- a/src/cpyrt/CPPInstance.cxx +++ b/src/cpyrt/CPPInstance.cxx @@ -270,18 +270,17 @@ static int op_nonzero(CPPInstance* self) { } //= cpyrt object explicit destruction ===================================== -static PyObject* op_destruct(CPPInstance* self) { +static PyObject* op_destruct(PyObject* self, PyObject* /*args*/) { // User access to force deletion of the object. Needed in case of a true // garbage collector (like in PyPy), to allow the user control over when // the C++ destructor is called. This method requires that the C++ object // is owned (no-op otherwise). - op_dealloc_nofree(self); + op_dealloc_nofree((CPPInstance*)self); Py_RETURN_NONE; } //= cpyrt object dispatch support ========================================= -static PyObject* op_dispatch(PyObject* self, PyObject* args, - PyObject* /* kdws */) { +static PyObject* op_dispatch(PyObject* self, PyObject* args) { // User-side __dispatch__ method to allow selection of a specific overloaded // method. The actual selection is in the __overload__() method of // CPPOverload. @@ -312,13 +311,14 @@ static PyObject* op_dispatch(PyObject* self, PyObject* args, } //= cpyrt smart pointer support =========================================== -static PyObject* op_get_smartptr(CPPInstance* self) { - if (!self->IsSmart()) { +static PyObject* op_get_smartptr(PyObject* self, PyObject* /*args*/) { + CPPInstance* inst = (CPPInstance*)self; + if (!inst->IsSmart()) { // TODO: more likely should raise Py_RETURN_NONE; } - return cpyrt::BindCppObjectNoCast(self->GetSmartObject(), SMART_TYPE(self), + return cpyrt::BindCppObjectNoCast(inst->GetSmartObject(), SMART_TYPE(inst), CPPInstance::kNoWrapConv); } @@ -335,7 +335,8 @@ Py_ssize_t cpyrt::CPPInstance::ArrayLength() { return (Py_ssize_t)ARRAY_SIZE(this); } -static PyObject* op_reshape(CPPInstance* self, PyObject* shape) { +static PyObject* op_reshape(PyObject* self, PyObject* shape) { + CPPInstance* inst = (CPPInstance*)self; // Allow the user to fix up the actual (type-strided) size of the buffer. if (!PyTuple_Check(shape) || PyTuple_GET_SIZE(shape) != 1) { PyErr_SetString(PyExc_TypeError, "tuple object of size 1 expected"); @@ -348,7 +349,7 @@ static PyObject* op_reshape(CPPInstance* self, PyObject* shape) { return nullptr; } - self->CastToArray(sz); + inst->CastToArray(sz); Py_RETURN_NONE; } @@ -417,26 +418,26 @@ PyCFunction& CPPInstance::ReduceMethod() { return reducer; } -PyObject* op_reduce(PyObject* self, PyObject* args) { +PyObject* op_reduce(PyObject* self, PyObject* /*args*/) { auto& reducer = CPPInstance::ReduceMethod(); if (!reducer) { PyErr_SetString(PyExc_NotImplementedError, ""); return nullptr; } - return reducer(self, args); + return reducer(self, nullptr); } //---------------------------------------------------------------------------- static PyMethodDef op_methods[] = { - {(char*)"__destruct__", (PyCFunction)op_destruct, METH_NOARGS, + {(char*)"__destruct__", op_destruct, METH_NOARGS, (char*)"call the C++ destructor"}, - {(char*)"__dispatch__", (PyCFunction)op_dispatch, METH_VARARGS, + {(char*)"__dispatch__", op_dispatch, METH_VARARGS, (char*)"dispatch to selected overload"}, - {(char*)"__smartptr__", (PyCFunction)op_get_smartptr, METH_NOARGS, + {(char*)"__smartptr__", op_get_smartptr, METH_NOARGS, (char*)"get associated smart pointer, if any"}, - {(char*)"__reduce__", (PyCFunction)op_reduce, METH_NOARGS, + {(char*)"__reduce__", op_reduce, METH_NOARGS, (char*)"reduce method for serialization"}, - {(char*)"__reshape__", (PyCFunction)op_reshape, METH_O, + {(char*)"__reshape__", op_reshape, METH_O, (char*)"cast pointer to 1D array type"}, {(char*)nullptr, nullptr, 0, nullptr}}; diff --git a/src/cpyrt/CPPOverload.cxx b/src/cpyrt/CPPOverload.cxx index 49778df..cbe1053 100644 --- a/src/cpyrt/CPPOverload.cxx +++ b/src/cpyrt/CPPOverload.cxx @@ -218,18 +218,20 @@ static inline PyObject* HandleReturn(CPPOverload* pymeth, CPPInstance* im_self, } //= cpyrt method proxy object behaviour =================================== -static PyObject* mp_name(CPPOverload* pymeth, void*) { +static PyObject* mp_name(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; return cpyrt_PyText_FromString(pymeth->GetName().c_str()); } //---------------------------------------------------------------------------- -static PyObject* mp_module(CPPOverload* /* pymeth */, void*) { +static PyObject* mp_module(PyObject*, void*) { Py_INCREF(PyStrings::gThisModule); return PyStrings::gThisModule; } //---------------------------------------------------------------------------- -static PyObject* mp_doc(CPPOverload* pymeth, void*) { +static PyObject* mp_doc(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; if (pymeth->fMethodInfo->fDoc) { Py_INCREF(pymeth->fMethodInfo->fDoc); return pymeth->fMethodInfo->fDoc; @@ -259,7 +261,8 @@ static PyObject* mp_doc(CPPOverload* pymeth, void*) { return doc; } -static int mp_doc_set(CPPOverload* pymeth, PyObject* val, void*) { +static int mp_doc_set(PyObject* self, PyObject* val, void*) { + CPPOverload* pymeth = (CPPOverload*)self; Py_XDECREF(pymeth->fMethodInfo->fDoc); Py_INCREF(val); pymeth->fMethodInfo->fDoc = val; @@ -276,8 +279,8 @@ static int mp_doc_set(CPPOverload* pymeth, PyObject* val, void*) { * 'int ::foo(int a)': ('a',), * 'int ::foo(int a, float b)': ('a', 'b')} */ -static PyObject* mp_func_overloads_names(CPPOverload* pymeth) { - +static PyObject* mp_func_overloads_names(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; const CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; PyObject* overloads_names_dict = PyDict_New(); @@ -301,8 +304,8 @@ static PyObject* mp_func_overloads_names(CPPOverload* pymeth) { * ('int',), 'return_type': 'int'}, 'int ::foo(int a, float b)': {'input_types': * ('int', 'float'), 'return_type': 'int'}} */ -static PyObject* mp_func_overloads_types(CPPOverload* pymeth) { - +static PyObject* mp_func_overloads_types(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; const CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; PyObject* overloads_types_dict = PyDict_New(); @@ -316,7 +319,8 @@ static PyObject* mp_func_overloads_types(CPPOverload* pymeth) { } //---------------------------------------------------------------------------- -static PyObject* mp_meth_func(CPPOverload* pymeth, void*) { +static PyObject* mp_meth_func(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Create a new method proxy to be returned. CPPOverload* newPyMeth = (CPPOverload*)CPPOverload_Type.tp_alloc(&CPPOverload_Type, 0); @@ -333,7 +337,8 @@ static PyObject* mp_meth_func(CPPOverload* pymeth, void*) { } //---------------------------------------------------------------------------- -static PyObject* mp_meth_self(CPPOverload* pymeth, void*) { +static PyObject* mp_meth_self(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Return the bound self, if any; in case of pseudo-function role, pretend // that the data member im_self does not exist. if (IsPseudoFunc(pymeth)) { @@ -350,7 +355,8 @@ static PyObject* mp_meth_self(CPPOverload* pymeth, void*) { } //---------------------------------------------------------------------------- -static PyObject* mp_meth_class(CPPOverload* pymeth, void*) { +static PyObject* mp_meth_class(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Return scoping class; in case of pseudo-function role, pretend that there // is no encompassing class (i.e. global scope). if (!IsPseudoFunc(pymeth) && pymeth->fMethodInfo->fMethods.size()) { @@ -366,13 +372,13 @@ static PyObject* mp_meth_class(CPPOverload* pymeth, void*) { } //---------------------------------------------------------------------------- -static PyObject* mp_func_closure(CPPOverload* /* pymeth */, void*) { +static PyObject* mp_func_closure(PyObject*, void*) { // Stub only, to fill out the python function interface. Py_RETURN_NONE; } //---------------------------------------------------------------------------- -static PyObject* mp_func_code(CPPOverload*, void*) { +static PyObject* mp_func_code(PyObject*, void*) { // Code details are used in module inspect to fill out interactive help() // not important for functioning of most code, so not implemented for p3 for // now (TODO) @@ -380,7 +386,8 @@ static PyObject* mp_func_code(CPPOverload*, void*) { } //---------------------------------------------------------------------------- -static PyObject* mp_func_defaults(CPPOverload* pymeth, void*) { +static PyObject* mp_func_defaults(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Create a tuple of default values, if there is only one method (otherwise // leave undefined: this is only used by inspect for interactive help()) CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods; @@ -406,7 +413,7 @@ static PyObject* mp_func_defaults(CPPOverload* pymeth, void*) { } //---------------------------------------------------------------------------- -static PyObject* mp_func_globals(CPPOverload* /* pymeth */, void*) { +static PyObject* mp_func_globals(PyObject*, void*) { // Return this function's global dict (hard-wired to be the cppjit module); // used for lookup of names from co_code indexing into co_names. PyObject* pyglobal = PyModule_GetDict(PyImport_AddModule((char*)"cppjit")); @@ -438,19 +445,22 @@ static inline int set_flag(CPPOverload* pymeth, PyObject* value, } //---------------------------------------------------------------------------- -static PyObject* mp_getcreates(CPPOverload* pymeth, void*) { +static PyObject* mp_getcreates(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Get '__creates__' boolean, which determines ownership of return values. return PyInt_FromLong((long)IsCreator(pymeth->fMethodInfo->fFlags)); } //---------------------------------------------------------------------------- -static int mp_setcreates(CPPOverload* pymeth, PyObject* value, void*) { +static int mp_setcreates(PyObject* self, PyObject* value, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Set '__creates__' boolean, which determines ownership of return values. return set_flag(pymeth, value, CallContext::kIsCreator, "__creates__"); } //---------------------------------------------------------------------------- -static PyObject* mp_getmempolicy(CPPOverload* pymeth, void*) { +static PyObject* mp_getmempolicy(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Get '_mempolicy' enum, which determines ownership of call arguments. if (pymeth->fMethodInfo->fFlags & CallContext::kUseHeuristics) return PyInt_FromLong(CallContext::kUseHeuristics); @@ -462,7 +472,8 @@ static PyObject* mp_getmempolicy(CPPOverload* pymeth, void*) { } //---------------------------------------------------------------------------- -static int mp_setmempolicy(CPPOverload* pymeth, PyObject* value, void*) { +static int mp_setmempolicy(PyObject* self, PyObject* value, void*) { + CPPOverload* pymeth = (CPPOverload*)self; // Set '_mempolicy' enum, which determines ownership of call arguments. long mempolicy = PyLong_AsLong(value); if (mempolicy == CallContext::kUseHeuristics) { @@ -501,7 +512,8 @@ CPPJIT_BOOLEAN_PROPERTY(useffi, CallContext::kUseFFI, "__useffi__") CPPJIT_BOOLEAN_PROPERTY(sig2exc, CallContext::kProtected, "__sig2exc__") // clang-format on -static PyObject* mp_getcppname(CPPOverload* pymeth, void*) { +static PyObject* mp_getcppname(PyObject* self, void*) { + CPPOverload* pymeth = (CPPOverload*)self; if ((void*)pymeth == (void*)&CPPOverload_Type) return cpyrt_PyText_FromString("CPPOverload_Type"); diff --git a/src/cpyrt/CPPScope.cxx b/src/cpyrt/CPPScope.cxx index b58469d..30cd8ad 100644 --- a/src/cpyrt/CPPScope.cxx +++ b/src/cpyrt/CPPScope.cxx @@ -623,7 +623,8 @@ static PyObject* meta_reflex(CPPScope* klass, PyObject* args) { // quite what I'd expected of it, so the following pulls in the internal code #include "PyObjectDir27.inc" -static PyObject* meta_dir(CPPScope* klass) { +static PyObject* meta_dir(PyObject* self, PyObject*) { + CPPScope* klass = (CPPScope*)self; // Collect a list of everything (currently) available in the namespace. // The backend can filter by returning empty strings. Special care is // taken for functions, which need not be unique (overloading). @@ -673,7 +674,7 @@ static PyObject* meta_dir(CPPScope* klass) { static PyMethodDef meta_methods[] = { {(char*)"__cpp_reflex__", (PyCFunction)meta_reflex, METH_VARARGS, (char*)"C++ datamember reflection information"}, - {(char*)"__dir__", (PyCFunction)meta_dir, METH_NOARGS, nullptr}, + {(char*)"__dir__", meta_dir, METH_NOARGS, nullptr}, {(char*)nullptr, nullptr, 0, nullptr}}; //----------------------------------------------------------------------------- diff --git a/src/cpyrt/LowLevelViews.cxx b/src/cpyrt/LowLevelViews.cxx index b4b5be1..e2e4715 100644 --- a/src/cpyrt/LowLevelViews.cxx +++ b/src/cpyrt/LowLevelViews.cxx @@ -76,26 +76,23 @@ static void ll_dealloc(cpyrt::LowLevelView* pyobj) { } //---------------------------------------------------------------------------- -#define CPYRT_LL_FLAG_GETSET(name, flag, doc) \ - static PyObject* ll_get##name(cpyrt::LowLevelView* pyobj) { \ - return PyBool_FromLong((long)((intptr_t)pyobj->fBufInfo.internal & flag)); \ - } \ - \ - static int ll_set##name(cpyrt::LowLevelView* pyobj, PyObject* value, \ - void*) { \ - long settrue = PyLong_AsLong(value); \ - if (settrue == -1 && PyErr_Occurred()) { \ - PyErr_SetString(PyExc_ValueError, \ - #doc " should be either True or False"); \ - return -1; \ - } \ - \ - if ((bool)settrue) \ - (intptr_t&)pyobj->fBufInfo.internal |= flag; \ - else \ - (intptr_t&)pyobj->fBufInfo.internal &= ~flag; \ - \ - return 0; \ +#define CPYRT_LL_FLAG_GETSET(name, flag, doc) \ + static PyObject* ll_get##name(PyObject* pyobj, void*) { \ + auto* view = (cpyrt::LowLevelView*)pyobj; \ + return PyBool_FromLong((long)((intptr_t)view->fBufInfo.internal & flag)); \ + } \ + static int ll_set##name(PyObject* pyobj, PyObject* value, void*) { \ + auto* view = (cpyrt::LowLevelView*)pyobj; \ + long settrue = PyLong_AsLong(value); \ + if (settrue == -1 && PyErr_Occurred()) { \ + PyErr_SetString(PyExc_ValueError, #doc " should be either True or False"); \ + return -1; \ + } \ + if ((bool)settrue) \ + (intptr_t&)view->fBufInfo.internal |= flag; \ + else \ + (intptr_t&)view->fBufInfo.internal &= ~flag; \ + return 0; \ } // clang-format off @@ -681,8 +678,9 @@ static PyBufferProcs ll_as_buffer = { }; //--------------------------------------------------------------------------- -static PyObject* ll_shape(cpyrt::LowLevelView* self) { - Py_buffer& view = self->fBufInfo; +static PyObject* ll_shape(PyObject* self, void*) { + cpyrt::LowLevelView* inst = (cpyrt::LowLevelView*)self; + Py_buffer& view = inst->fBufInfo; PyObject* shape = PyTuple_New(view.ndim); for (Py_ssize_t idim = 0; idim < view.ndim; ++idim) @@ -692,8 +690,9 @@ static PyObject* ll_shape(cpyrt::LowLevelView* self) { } //--------------------------------------------------------------------------- -static PyObject* ll_reshape(cpyrt::LowLevelView* self, PyObject* shape) { - // Allow the user to fix up the actual (type-strided) size of the buffer. +static int ll_reshape(PyObject* self, PyObject* shape, void*) { + cpyrt::LowLevelView* inst = (cpyrt::LowLevelView*)self; + if (!PyTuple_Check(shape)) { if (shape) { PyObject* pystr = PyObject_Str(shape); @@ -701,22 +700,22 @@ static PyObject* ll_reshape(cpyrt::LowLevelView* self, PyObject* shape) { PyErr_Format(PyExc_TypeError, "tuple object expected, received %s", cpyrt_PyText_AsStringChecked(pystr)); Py_DECREF(pystr); - return nullptr; + return -1; } } PyErr_SetString(PyExc_TypeError, "tuple object expected"); - return nullptr; + return -1; } - Py_buffer& view = self->fBufInfo; + Py_buffer& view = inst->fBufInfo; // verify size match Py_ssize_t oldsz = 0; for (Py_ssize_t idim = 0; idim < view.ndim; ++idim) { Py_ssize_t nlen = view.shape[idim]; if (nlen == cpyrt::UNKNOWN_SIZE || - nlen == INT_MAX / view.itemsize /* fake 'max' */) { - oldsz = -1; // meaning, unable to check size match + nlen == INT_MAX / view.itemsize) { + oldsz = -1; break; } oldsz += view.shape[idim]; @@ -732,11 +731,11 @@ static PyObject* ll_reshape(cpyrt::LowLevelView* self, PyObject* shape) { "cannot reshape array of size %ld into shape %s", (long)oldsz, cpyrt_PyText_AsString(tas)); Py_DECREF(tas); - return nullptr; + return -1; } } - // reshape + // reshape layout logic... size_t itemsize = view.strides[view.ndim - 1]; if (view.ndim != PyTuple_GET_SIZE(shape)) { PyMem_Free(view.shape); @@ -750,7 +749,7 @@ static PyObject* ll_reshape(cpyrt::LowLevelView* self, PyObject* shape) { for (Py_ssize_t idim = 0; idim < PyTuple_GET_SIZE(shape); ++idim) { Py_ssize_t nlen = PyInt_AsSsize_t(PyTuple_GET_ITEM(shape, idim)); if (nlen == -1 && PyErr_Occurred()) - return nullptr; + return -1; if (idim == 0) view.len = nlen * view.itemsize; @@ -758,14 +757,21 @@ static PyObject* ll_reshape(cpyrt::LowLevelView* self, PyObject* shape) { view.shape[idim] = nlen; } - set_strides(view, itemsize, false /* by definition not fixed */); + set_strides(view, itemsize, false); + return 0; // Success +} + +static PyObject* ll_reshape(PyObject* self, PyObject* shape) { + if (ll_reshape(self, shape, nullptr) < 0) { + return nullptr; + } Py_RETURN_NONE; } //--------------------------------------------------------------------------- -static PyObject* ll_array(cpyrt::LowLevelView* self, PyObject* args, - PyObject* kwds) { +static PyObject* ll_array(PyObject* self, PyObject* args) { + cpyrt::LowLevelView* inst = (cpyrt::LowLevelView*)self; // Construct a numpy array from the lowlevelview (w/o copy if possible); this // uses the Python methods to avoid depending on numpy directly @@ -775,17 +781,6 @@ static PyObject* ll_array(cpyrt::LowLevelView* self, PyObject* args, return nullptr; bool docopy = false; - if (kwds) { - PyObject* pycp = PyObject_GetItem(kwds, cpyrt::PyStrings::gCopy); - if (!pycp) { - PyErr_SetString(PyExc_TypeError, - "__array__ only supports the \"copy\" keyword"); - return nullptr; - } - - docopy = PyObject_IsTrue(pycp); - Py_DECREF(pycp); - } if (!docopy) { // view requested // expect possible dtype from the arguments, otherwise take it from the type @@ -793,7 +788,7 @@ static PyObject* ll_array(cpyrt::LowLevelView* self, PyObject* args, PyObject* dtype; if (!args || PyTuple_GET_SIZE(args) != 1) { PyObject* npdtype = PyObject_GetAttr(npmod, cpyrt::PyStrings::gDType); - PyObject* typecode = ll_typecode(self, nullptr); + PyObject* typecode = ll_typecode(inst, nullptr); dtype = PyObject_CallFunctionObjArgs(npdtype, typecode, nullptr); Py_DECREF(typecode); Py_DECREF(npdtype); @@ -807,7 +802,7 @@ static PyObject* ll_array(cpyrt::LowLevelView* self, PyObject* args, PyObject* npfrombuf = PyObject_GetAttr(npmod, cpyrt::PyStrings::gFromBuffer); - PyObject* view = PyObject_CallFunctionObjArgs(npfrombuf, (PyObject*)self, + PyObject* view = PyObject_CallFunctionObjArgs(npfrombuf, (PyObject*)inst, dtype, nullptr); Py_DECREF(dtype); Py_DECREF(npfrombuf); @@ -817,7 +812,7 @@ static PyObject* ll_array(cpyrt::LowLevelView* self, PyObject* args, } else { // copy requested PyObject* npcopy = PyObject_GetAttr(npmod, cpyrt::PyStrings::gCopy); PyObject* newarr = - PyObject_CallFunctionObjArgs(npcopy, (PyObject*)self, nullptr); + PyObject_CallFunctionObjArgs(npcopy, (PyObject*)inst, nullptr); Py_DECREF(npcopy); return newarr; @@ -828,9 +823,10 @@ static PyObject* ll_array(cpyrt::LowLevelView* self, PyObject* args, } //--------------------------------------------------------------------------- -static PyObject* ll_as_string(cpyrt::LowLevelView* self) { +static PyObject* ll_as_string(PyObject* self, PyObject* /*args*/) { + cpyrt::LowLevelView* inst = (cpyrt::LowLevelView*)self; // Interpret memory as a null-terminated char string. - Py_buffer& view = self->fBufInfo; + Py_buffer& view = inst->fBufInfo; if (strcmp(view.format, "b") != 0 || view.ndim != 1) { PyErr_Format( @@ -840,19 +836,19 @@ static PyObject* ll_as_string(cpyrt::LowLevelView* self) { return nullptr; } - char* buf = (char*)self->get_buf(); + char* buf = (char*)inst->get_buf(); size_t sz = strnlen(buf, (size_t)view.shape[0]); return cpyrt_PyText_FromStringAndSize(buf, sz); } //--------------------------------------------------------------------------- static PyMethodDef ll_methods[] = { - {(char*)"reshape", (PyCFunction)ll_reshape, METH_O, + {(char*)"reshape", ll_reshape, METH_O, (char*)"change the shape (not layout) of the low level view"}, - {(char*)"as_string", (PyCFunction)ll_as_string, METH_NOARGS, + {(char*)"as_string", ll_as_string, METH_NOARGS, (char*)"interpret memory as a null-terminated char string and return " "Python str"}, - {(char*)"__array__", (PyCFunction)ll_array, METH_VARARGS | METH_KEYWORDS, + {(char*)"__array__", ll_array, METH_VARARGS, (char*)"return a numpy array from the low level view"}, {(char*)nullptr, nullptr, 0, nullptr}}; diff --git a/src/cpyrt/MemoryRegulator.cxx b/src/cpyrt/MemoryRegulator.cxx index 6ea7671..69d45ea 100644 --- a/src/cpyrt/MemoryRegulator.cxx +++ b/src/cpyrt/MemoryRegulator.cxx @@ -52,7 +52,9 @@ struct Initcpyrt_NoneType_t { cpyrt_NoneType.tp_repr = Py_TYPE(Py_None)->tp_repr; cpyrt_NoneType.tp_richcompare = (richcmpfunc)&Initcpyrt_NoneType_t::RichCompare; - cpyrt_NoneType.tp_hash = (hashfunc)&Initcpyrt_NoneType_t::PtrHash; + + // Assigned directly without a cast + cpyrt_NoneType.tp_hash = PtrHash; cpyrt_NoneType.tp_as_mapping = &cpyrt_NoneType_mapping; @@ -60,7 +62,8 @@ struct Initcpyrt_NoneType_t { } static void DeAlloc(PyObject* pyobj) { Py_TYPE(pyobj)->tp_free(pyobj); } - static int PtrHash(PyObject* pyobj) { return (int)ptrdiff_t(pyobj); } + // Return Py_hash_t instead of int to match hashfunc signature natively + static Py_hash_t PtrHash(PyObject* pyobj) { return (Py_hash_t)pyobj; } static PyObject* RichCompare(PyObject*, PyObject* other, int opid) { return PyObject_RichCompare(other, Py_None, opid); diff --git a/src/cpyrt/Pythonize.cxx b/src/cpyrt/Pythonize.cxx index e14067c..91348ec 100644 --- a/src/cpyrt/Pythonize.cxx +++ b/src/cpyrt/Pythonize.cxx @@ -209,7 +209,7 @@ PyObject* FollowGetAttr(PyObject* self, PyObject* name) { } //- pointer checking bool converter ------------------------------------------- -PyObject* NullCheckBool(PyObject* self) { +PyObject* NullCheckBool(PyObject* self, PyObject* Py_UNUSED(args)) { if (!CPPInstance_Check(self)) { PyErr_SetString(PyExc_TypeError, "C++ object proxy expected"); return nullptr; @@ -438,7 +438,7 @@ static bool FillVector(PyObject* vecin, PyObject* args, ItemGetter* getter) { return fill_ok; } -PyObject* VectorIAdd(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* VectorIAdd(PyObject* self, PyObject* args) { // Implement fast __iadd__ on std::vector (generic __iadd__ is in Python) ItemGetter* getter = GetGetter(args); @@ -474,7 +474,7 @@ PyObject* VectorIAdd(PyObject* self, PyObject* args, PyObject* /* kwds */) { return nullptr; // error already set } -PyObject* VectorInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* VectorInit(PyObject* self, PyObject* args) { // Specialized vector constructor to allow construction from containers; // allowing such construction from initializer_list instead would possible, // but can be error-prone. This use case is common enough for std::vector to @@ -538,10 +538,10 @@ PyObject* VectorData(PyObject* self, PyObject*) { } //--------------------------------------------------------------------------- -PyObject* VectorArray(PyObject* self, PyObject* args, PyObject* kwargs) { +PyObject* VectorArray(PyObject* self, PyObject* args) { PyObject* pydata = VectorData(self, nullptr); PyObject* arrcall = PyObject_GetAttr(pydata, PyStrings::gArray); - PyObject* newarr = PyObject_Call(arrcall, args, kwargs); + PyObject* newarr = PyObject_Call(arrcall, args, nullptr); Py_DECREF(arrcall); Py_DECREF(pydata); return newarr; @@ -778,7 +778,7 @@ PyObject* VectorBoolSetItem(CPPInstance* self, PyObject* args) { } //- array behavior as primitives ---------------------------------------------- -PyObject* ArrayInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* ArrayInit(PyObject* self, PyObject* args) { // std::array is normally only constructed using aggregate initialization, // which is a concept that does not exist in python, so use this custom // constructor to to fill the array using setitem @@ -867,7 +867,7 @@ static PyObject* MapFromPairs(PyObject* self, PyObject* pairs) { return result; } -PyObject* MapInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* MapInit(PyObject* self, PyObject* args) { // Specialized map constructor to allow construction from mapping containers // and from tuples of pairs ("initializer_list style"). @@ -941,7 +941,7 @@ PyObject* STLContainsWithFind(PyObject* self, PyObject* obj) { } //- set behavior as primitives ------------------------------------------------ -PyObject* SetInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* SetInit(PyObject* self, PyObject* args) { // Specialized set constructor to allow construction from Python sets. if (PyTuple_GET_SIZE(args) == 1 && PySet_Check(PyTuple_GET_ITEM(args, 0))) { PyObject* pyset = PyTuple_GET_ITEM(args, 0); @@ -993,9 +993,9 @@ static const ptrdiff_t PS_END_ADDR = 7; // non-aligned address, so no clash static const ptrdiff_t PS_FLAG_ADDR = 11; // id. static const ptrdiff_t PS_COLL_ADDR = 13; // id. -PyObject* STLIterNext(PyObject* self); // defined below; used by STLSequenceIter +PyObject* STLIterNext(PyObject* self, PyObject* Py_UNUSED(args)); // defined below; used by STLSequenceIter -PyObject* LLSequenceIter(PyObject* self) { +PyObject* LLSequenceIter(PyObject* self, PyObject* Py_UNUSED(args)) { // Implement python's __iter__ for low level views used through STL-type // begin()/end() PyObject* iter = PyObject_CallMethodNoArgs(self, PyStrings::gBegin); @@ -1022,7 +1022,21 @@ PyObject* LLSequenceIter(PyObject* self) { return nullptr; } -PyObject* STLSequenceIter(PyObject* self) { +static PyObject* my_iter(PyObject* self, PyObject* Py_UNUSED(args)) { + return PyObject_SelfIter(self); +} + +static PyObject* STLIterNextAdapter(PyObject *self) +{ + return STLIterNext(self, nullptr); +} + +static PyObject* LLSequenceIterAdapter(PyObject *self) +{ + return LLSequenceIter(self, nullptr); +} + +PyObject* STLSequenceIter(PyObject* self, PyObject* Py_UNUSED(args)) { // Implement python's __iter__ for std::iterator<>s PyObject* iter = PyObject_CallMethodNoArgs(self, PyStrings::gBegin); if (iter) { @@ -1040,13 +1054,13 @@ PyObject* STLSequenceIter(PyObject* self) { PyTypeObject* itype = Py_TYPE(iter); if (!PyIter_Check(iter)) { // no tp_iternext, or the // _PyObject_NextNotImplemented sentinel - itype->tp_iternext = (iternextfunc)STLIterNext; + itype->tp_iternext = (iternextfunc)STLIterNextAdapter; Utility::AddToClass((PyObject*)itype, CPPJIT__next__, - (PyCFunction)STLIterNext, METH_NOARGS); + STLIterNext, METH_NOARGS); if (!itype->tp_iter) { itype->tp_iter = (getiterfunc)PyObject_SelfIter; Utility::AddToClass((PyObject*)itype, "__iter__", - (PyCFunction)PyObject_SelfIter, METH_NOARGS); + my_iter, METH_NOARGS); } PyType_Modified(itype); } @@ -1073,9 +1087,14 @@ PyObject* STLSequenceIter(PyObject* self) { return iter; } +static PyObject* STLSequenceIterAdapter(PyObject *self) +{ + return STLSequenceIter(self, nullptr); +} + //- generic iterator support over a sequence with operator[] and size --------- //----------------------------------------------------------------------------- -static PyObject* index_iter(PyObject* c) { +static PyObject* index_iter(PyObject* c, PyObject* Py_UNUSED(args)) { indexiterobject* ii = PyObject_GC_New(indexiterobject, &IndexIter_Type); if (!ii) return nullptr; @@ -1089,6 +1108,11 @@ static PyObject* index_iter(PyObject* c) { return (PyObject*)ii; } +static PyObject* index_iterAdapter(PyObject *self) +{ + return index_iter(self, nullptr); +} + //- safe indexing for STL-like vector w/o iterator dictionaries --------------- /* replaced by indexiterobject iteration, but may still have some future use ... PyObject* CheckedGetItem(PyObject* self, PyObject* obj) @@ -1145,7 +1169,7 @@ PyObject* PairUnpack(PyObject* self, PyObject* pyindex) { PyObject* ReturnTwo(CPPInstance*, PyObject*) { return PyInt_FromLong(2); } //- shared/unique_ptr behavior ----------------------------------------------- -PyObject* SmartPtrInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* SmartPtrInit(PyObject* self, PyObject* args) { // since the shared/unique pointer will take ownership, we need to relinquish // it PyObject* realInit = PyObject_GetAttr(self, PyStrings::gRealInit); @@ -1198,7 +1222,7 @@ static inline PyObject* cpyrt_PyString_FromCppString(std::wstring_view s, return nullptr; \ } \ \ - PyObject* name##StringStr(PyObject* self) { \ + PyObject* name##StringStr(PyObject* self, PyObject* Py_UNUSED(args)) { \ PyObject* pyobj = name##StringGetData(self, false); \ if (!pyobj) { \ /* do a native conversion to make printing possible (debatable) */ \ @@ -1212,11 +1236,11 @@ static inline PyObject* cpyrt_PyString_FromCppString(std::wstring_view s, return pyobj; \ } \ \ - PyObject* name##StringBytes(PyObject* self) { \ + PyObject* name##StringBytes(PyObject* self, PyObject* Py_UNUSED(args)) { \ return name##StringGetData(self, true); \ } \ \ - PyObject* name##StringRepr(PyObject* self) { \ + PyObject* name##StringRepr(PyObject* self, PyObject* Py_UNUSED(args)) { \ PyObject* data = name##StringGetData(self, true); \ if (data) { \ PyObject* repr = PyObject_Repr(data); \ @@ -1278,16 +1302,15 @@ static inline std::string* GetSTLString(CPPInstance* self) { return obj; } -PyObject* STLStringDecode(CPPInstance* self, PyObject* args, PyObject* kwds) { - std::string* obj = GetSTLString(self); +PyObject* STLStringDecode(PyObject* self, PyObject* args) { + CPPInstance* inst = (CPPInstance*)self; + std::string* obj = GetSTLString(inst); if (!obj) return nullptr; - char* keywords[] = {(char*)"encoding", (char*)"errors", (char*)nullptr}; const char* encoding = nullptr; const char* errors = nullptr; - if (!PyArg_ParseTupleAndKeywords(args, kwds, const_cast("s|s"), - keywords, &encoding, &errors)) + if (!PyArg_ParseTuple(args, "s|s", &encoding, &errors)) return nullptr; return PyUnicode_Decode(obj->data(), obj->size(), encoding, errors); @@ -1309,9 +1332,9 @@ PyObject* STLStringContains(CPPInstance* self, PyObject* pyobj) { Py_RETURN_FALSE; } -PyObject* STLStringReplace(CPPInstance* self, PyObject* args, - PyObject* /*kwds*/) { - std::string* obj = GetSTLString(self); +PyObject* STLStringReplace(PyObject* self, PyObject* args) { + CPPInstance* inst = (CPPInstance*)self; + std::string* obj = GetSTLString(inst); if (!obj) return nullptr; @@ -1330,7 +1353,7 @@ PyObject* STLStringReplace(CPPInstance* self, PyObject* args, } PyObject* cppreplace = - PyObject_GetAttrString((PyObject*)self, (char*)"__cpp_replace"); + PyObject_GetAttrString((PyObject*)inst, (char*)"__cpp_replace"); if (cppreplace) { PyObject* result = PyObject_Call(cppreplace, args, nullptr); Py_DECREF(cppreplace); @@ -1343,14 +1366,14 @@ PyObject* STLStringReplace(CPPInstance* self, PyObject* args, } #define CPYRT_STRING_FINDMETHOD(name, cppname, pyname) \ - PyObject* STLString##name(CPPInstance* self, PyObject* args, \ - PyObject* /*kwds*/) { \ - std::string* obj = GetSTLString(self); \ + PyObject* STLString##name(PyObject* self, PyObject* args) { \ + CPPInstance* inst = (CPPInstance*) self; \ + std::string* obj = GetSTLString(inst); \ if (!obj) \ return nullptr; \ \ PyObject* cppmeth = \ - PyObject_GetAttrString((PyObject*)self, (char*)#cppname); \ + PyObject_GetAttrString((PyObject*)inst, (char*)#cppname); \ if (cppmeth) { \ PyObject* result = PyObject_Call(cppmeth, args, nullptr); \ Py_DECREF(cppmeth); \ @@ -1392,7 +1415,7 @@ PyObject* STLStringGetAttr(CPPInstance* self, PyObject* attr_name) { return attr; } -PyObject* UTF8Repr(PyObject* self) { +PyObject* UTF8Repr(PyObject* self, PyObject* Py_UNUSED(args)) { // force C++ string types conversion to Python str per Python __repr__ // requirements PyObject* res = PyObject_CallMethodNoArgs(self, PyStrings::gCppRepr); @@ -1403,7 +1426,7 @@ PyObject* UTF8Repr(PyObject* self) { return str_res; } -PyObject* UTF8Str(PyObject* self) { +PyObject* UTF8Str(PyObject* self, PyObject* Py_UNUSED(args)) { // force C++ string types conversion to Python str per Python __str__ // requirements PyObject* res = PyObject_CallMethodNoArgs(self, PyStrings::gCppStr); @@ -1424,7 +1447,7 @@ Py_hash_t STLStringHash(PyObject* self) { } //- string_view behavior as primitive ---------------------------------------- -PyObject* StringViewInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { +PyObject* StringViewInit(PyObject* self, PyObject* args) { // if constructed from a Python unicode object, the constructor will convert // it to a temporary byte string, which is likely to go out of scope too soon; // so buffer it as needed @@ -1464,7 +1487,7 @@ PyObject* StringViewInit(PyObject* self, PyObject* args, PyObject* /* kwds */) { } //- STL iterator behavior ---------------------------------------------------- -PyObject* STLIterNext(PyObject* self) { +PyObject* STLIterNext(PyObject* self, PyObject* Py_UNUSED(args)) { // Python iterator protocol __next__ for STL forward iterators. bool mustIncrement = true; PyObject* last = nullptr; @@ -1536,7 +1559,7 @@ PyObject* STLIterNext(PyObject* self) { COMPLEX_METH_GETSET(real, PyStrings::gCppReal) COMPLEX_METH_GETSET(imag, PyStrings::gCppImag) -static PyObject* ComplexComplex(PyObject* self) { +static PyObject* ComplexComplex(PyObject* self, PyObject* Py_UNUSED(args)) { PyObject* real = PyObject_CallMethodNoArgs(self, PyStrings::gCppReal); if (!real) return nullptr; @@ -1556,7 +1579,7 @@ static PyObject* ComplexComplex(PyObject* self) { return PyComplex_FromDoubles(r, i); } -static PyObject* ComplexRepr(PyObject* self) { +static PyObject* ComplexRepr(PyObject* self, PyObject* Py_UNUSED(args)) { PyObject* real = PyObject_CallMethodNoArgs(self, PyStrings::gCppReal); if (!real) return nullptr; @@ -1608,9 +1631,10 @@ static int ComplexDImagSet(CPPInstance* self, PyObject* value, void*) { PyGetSetDef ComplexDImag{(char*)"imag", (getter)ComplexDImagGet, (setter)ComplexDImagSet, nullptr, nullptr}; -static PyObject* ComplexDComplex(CPPInstance* self) { - double r = ((std::complex*)self->GetObject())->real(); - double i = ((std::complex*)self->GetObject())->imag(); +static PyObject* ComplexDComplex(PyObject* self, PyObject* Py_UNUSED(args)) { + CPPInstance* inst = (CPPInstance*)self; + double r = ((std::complex*)inst->GetObject())->real(); + double i = ((std::complex*)inst->GetObject())->imag(); return PyComplex_FromDoubles(r, i); } @@ -1671,7 +1695,7 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { // for pre-check of nullptr for boolean types if (HasAttrDirect(pyclass, PyStrings::gCppBool)) { const char* pybool_name = "__bool__"; - Utility::AddToClass(pyclass, pybool_name, (PyCFunction)NullCheckBool, + Utility::AddToClass(pyclass, pybool_name, NullCheckBool, METH_NOARGS); } @@ -1708,8 +1732,8 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { if (isIterator) { // install iterator protocol a la STL - ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)STLSequenceIter; - Utility::AddToClass(pyclass, "__iter__", (PyCFunction)STLSequenceIter, + ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)STLSequenceIterAdapter; + Utility::AddToClass(pyclass, "__iter__", STLSequenceIter, METH_NOARGS); } else { // still okay if this is some pointer type of builtin persuasion @@ -1718,9 +1742,9 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { std::string resolved = interop::ResolveName(resname); if (resolved.back() == '*' && interop::IsBuiltin(resolved.substr(0, resolved.size() - 1))) { - ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)LLSequenceIter; + ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)LLSequenceIterAdapter; Utility::AddToClass(pyclass, "__iter__", - (PyCFunction)LLSequenceIter, METH_NOARGS); + LLSequenceIter, METH_NOARGS); } } } @@ -1733,8 +1757,8 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { // if beyond size()) works in some cases but would mess up if operator[] // is meant to implement an associative container. So, this has to be // implemented as an iterator protocol. - ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)index_iter; - Utility::AddToClass(pyclass, "__iter__", (PyCFunction)index_iter, + ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)index_iterAdapter; + Utility::AddToClass(pyclass, "__iter__", index_iter, METH_NOARGS); } } @@ -1780,14 +1804,14 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { if (HasAttrDirect(pyclass, PyStrings::gRepr, true)) { // guarantee that the result of __repr__ is a Python string Utility::AddToClass(pyclass, "__cpp_repr", "__repr__"); - Utility::AddToClass(pyclass, "__repr__", (PyCFunction)UTF8Repr, + Utility::AddToClass(pyclass, "__repr__", UTF8Repr, METH_NOARGS); } if (HasAttrDirect(pyclass, PyStrings::gStr, true)) { // guarantee that the result of __str__ is a Python string Utility::AddToClass(pyclass, "__cpp_str", "__str__"); - Utility::AddToClass(pyclass, "__str__", (PyCFunction)UTF8Str, METH_NOARGS); + Utility::AddToClass(pyclass, "__str__", UTF8Str, METH_NOARGS); } if (interop::IsAggregate(((CPPClass*)pyclass)->fCppType) && @@ -1894,7 +1918,7 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { } else { // constructor that takes python collections Utility::AddToClass(pyclass, "__real_init", "__init__"); - Utility::AddToClass(pyclass, "__init__", (PyCFunction)VectorInit, + Utility::AddToClass(pyclass, "__init__", VectorInit, METH_VARARGS | METH_KEYWORDS); // data with size @@ -1903,8 +1927,8 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { Utility::AddToClass(pyclass, "data", (PyCFunction)VectorData); // numpy array conversion - Utility::AddToClass(pyclass, "__array__", (PyCFunction)VectorArray, - METH_VARARGS | METH_KEYWORDS /* unused */); + Utility::AddToClass(pyclass, "__array__", VectorArray, + METH_VARARGS); // checked getitem if (HasAttrDirect(pyclass, PyStrings::gLen)) { @@ -1917,7 +1941,7 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)vector_iter; // optimized __iadd__ - Utility::AddToClass(pyclass, "__iadd__", (PyCFunction)VectorIAdd, + Utility::AddToClass(pyclass, "__iadd__", VectorIAdd, METH_VARARGS | METH_KEYWORDS); // helpers for iteration @@ -1946,7 +1970,7 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { else if (IsTemplatedSTLClass(name, "array")) { // constructor that takes python associative collections Utility::AddToClass(pyclass, "__real_init", "__init__"); - Utility::AddToClass(pyclass, "__init__", (PyCFunction)ArrayInit, + Utility::AddToClass(pyclass, "__init__", ArrayInit, METH_VARARGS | METH_KEYWORDS); } @@ -1954,7 +1978,7 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { IsTemplatedSTLClass(name, "unordered_map")) { // constructor that takes python associative collections Utility::AddToClass(pyclass, "__real_init", "__init__"); - Utility::AddToClass(pyclass, "__init__", (PyCFunction)MapInit, + Utility::AddToClass(pyclass, "__init__", MapInit, METH_VARARGS | METH_KEYWORDS); // From C++20, std::map/unordered_map have a native contains() that the // generic contains->__contains__ mapping above will pick up. Strong-types @@ -1969,7 +1993,7 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { else if (IsTemplatedSTLClass(name, "set")) { // constructor that takes python associative collections Utility::AddToClass(pyclass, "__real_init", "__init__"); - Utility::AddToClass(pyclass, "__init__", (PyCFunction)SetInit, + Utility::AddToClass(pyclass, "__init__", SetInit, METH_VARARGS | METH_KEYWORDS); // From C++20, std::set has a native contains() that the generic // contains->__contains__ mapping above will pick up. Strong-types @@ -1990,18 +2014,18 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { if (IsTemplatedSTLClass(name, "shared_ptr") || IsTemplatedSTLClass(name, "unique_ptr")) { Utility::AddToClass(pyclass, "__real_init", "__init__"); - Utility::AddToClass(pyclass, "__init__", (PyCFunction)SmartPtrInit, + Utility::AddToClass(pyclass, "__init__", SmartPtrInit, METH_VARARGS | METH_KEYWORDS); } else if (!((PyTypeObject*)pyclass)->tp_iter && (name.find("iterator") != std::string::npos || gIteratorTypes.find(name) != gIteratorTypes.end())) { - ((PyTypeObject*)pyclass)->tp_iternext = (iternextfunc)STLIterNext; - Utility::AddToClass(pyclass, CPPJIT__next__, (PyCFunction)STLIterNext, + ((PyTypeObject*)pyclass)->tp_iternext = (iternextfunc)STLIterNextAdapter; + Utility::AddToClass(pyclass, CPPJIT__next__, STLIterNext, METH_NOARGS); ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)PyObject_SelfIter; - Utility::AddToClass(pyclass, "__iter__", (PyCFunction)PyObject_SelfIter, + Utility::AddToClass(pyclass, "__iter__", my_iter, METH_NOARGS); } @@ -2009,11 +2033,11 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { name == "std::__1::basic_string" || // libc++ inline namespace name == "std::string") { // typedef preserved by GetScopedFinalName // on libc++ - Utility::AddToClass(pyclass, "__repr__", (PyCFunction)STLStringRepr, + Utility::AddToClass(pyclass, "__repr__", STLStringRepr, METH_NOARGS); - Utility::AddToClass(pyclass, "__str__", (PyCFunction)STLStringStr, + Utility::AddToClass(pyclass, "__str__", STLStringStr, METH_NOARGS); - Utility::AddToClass(pyclass, "__bytes__", (PyCFunction)STLStringBytes, + Utility::AddToClass(pyclass, "__bytes__", STLStringBytes, METH_NOARGS); Utility::AddToClass(pyclass, "__cmp__", (PyCFunction)STLStringCompare, METH_O); @@ -2027,16 +2051,16 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { // wrongly dropped it when built with -std=c++2c (__cplusplus == 202400L). Utility::AddToClass(pyclass, "__contains__", (PyCFunction)STLStringContains, METH_O); - Utility::AddToClass(pyclass, "decode", (PyCFunction)STLStringDecode, - METH_VARARGS | METH_KEYWORDS); + Utility::AddToClass(pyclass, "decode", STLStringDecode, + METH_VARARGS); Utility::AddToClass(pyclass, "__cpp_find", "find"); - Utility::AddToClass(pyclass, "find", (PyCFunction)STLStringFind, + Utility::AddToClass(pyclass, "find", STLStringFind, METH_VARARGS | METH_KEYWORDS); Utility::AddToClass(pyclass, "__cpp_rfind", "rfind"); - Utility::AddToClass(pyclass, "rfind", (PyCFunction)STLStringRFind, + Utility::AddToClass(pyclass, "rfind", STLStringRFind, METH_VARARGS | METH_KEYWORDS); Utility::AddToClass(pyclass, "__cpp_replace", "replace"); - Utility::AddToClass(pyclass, "replace", (PyCFunction)STLStringReplace, + Utility::AddToClass(pyclass, "replace", STLStringReplace, METH_VARARGS | METH_KEYWORDS); Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)STLStringGetAttr, METH_O); @@ -2051,9 +2075,9 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { name == "std::string_view") { // typedef preserved by // GetScopedFinalName on libc++ Utility::AddToClass(pyclass, "__real_init", "__init__"); - Utility::AddToClass(pyclass, "__init__", (PyCFunction)StringViewInit, + Utility::AddToClass(pyclass, "__init__", StringViewInit, METH_VARARGS | METH_KEYWORDS); - Utility::AddToClass(pyclass, "__bytes__", (PyCFunction)STLViewStringBytes, + Utility::AddToClass(pyclass, "__bytes__", STLViewStringBytes, METH_NOARGS); Utility::AddToClass(pyclass, "__cmp__", (PyCFunction)STLViewStringCompare, METH_O); @@ -2061,9 +2085,9 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { METH_O); Utility::AddToClass(pyclass, "__ne__", (PyCFunction)STLViewStringIsNotEqual, METH_O); - Utility::AddToClass(pyclass, "__repr__", (PyCFunction)STLViewStringRepr, + Utility::AddToClass(pyclass, "__repr__", STLViewStringRepr, METH_NOARGS); - Utility::AddToClass(pyclass, "__str__", (PyCFunction)STLViewStringStr, + Utility::AddToClass(pyclass, "__str__", STLViewStringStr, METH_NOARGS); } @@ -2072,11 +2096,11 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { name == "std::__1::basic_string,std::__1::allocator >" || name == "std::wstring") { - Utility::AddToClass(pyclass, "__repr__", (PyCFunction)STLWStringRepr, + Utility::AddToClass(pyclass, "__repr__", STLWStringRepr, METH_NOARGS); - Utility::AddToClass(pyclass, "__str__", (PyCFunction)STLWStringStr, + Utility::AddToClass(pyclass, "__str__", STLWStringStr, METH_NOARGS); - Utility::AddToClass(pyclass, "__bytes__", (PyCFunction)STLWStringBytes, + Utility::AddToClass(pyclass, "__bytes__", STLWStringBytes, METH_NOARGS); Utility::AddToClass(pyclass, "__cmp__", (PyCFunction)STLWStringCompare, METH_O); @@ -2095,9 +2119,9 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { PyObject_SetAttrString( pyclass, "imag", PyDescr_NewGetSet((PyTypeObject*)pyclass, &ComplexDImag)); - Utility::AddToClass(pyclass, "__complex__", (PyCFunction)ComplexDComplex, + Utility::AddToClass(pyclass, "__complex__", ComplexDComplex, METH_NOARGS); - Utility::AddToClass(pyclass, "__repr__", (PyCFunction)ComplexRepr, + Utility::AddToClass(pyclass, "__repr__", ComplexRepr, METH_NOARGS); } @@ -2110,9 +2134,9 @@ bool cpyrt::Pythonize(PyObject* pyclass, interop::TCppScope_t scope) { PyObject_SetAttrString( pyclass, "imag", PyDescr_NewGetSet((PyTypeObject*)pyclass, &imagComplex)); - Utility::AddToClass(pyclass, "__complex__", (PyCFunction)ComplexComplex, + Utility::AddToClass(pyclass, "__complex__", ComplexComplex, METH_NOARGS); - Utility::AddToClass(pyclass, "__repr__", (PyCFunction)ComplexRepr, + Utility::AddToClass(pyclass, "__repr__", ComplexRepr, METH_NOARGS); } diff --git a/src/cpyrt/cpyrtModule.cxx b/src/cpyrt/cpyrtModule.cxx index b2c0733..4fb5441 100644 --- a/src/cpyrt/cpyrtModule.cxx +++ b/src/cpyrt/cpyrtModule.cxx @@ -593,7 +593,7 @@ static PyObject* addressof(PyObject* /* dummy */, PyObject* args, } //---------------------------------------------------------------------------- -static PyObject* AsCObject(PyObject* /* unused */, PyObject* args, +static PyObject* AsCObject(PyObject* args, PyObject* kwds) { // Return object proxy as an opaque CObject. void* addr = GetCPPInstanceAddress("as_cobject", args, kwds); @@ -603,7 +603,7 @@ static PyObject* AsCObject(PyObject* /* unused */, PyObject* args, } //---------------------------------------------------------------------------- -static PyObject* AsCapsule(PyObject* /* unused */, PyObject* args, +static PyObject* AsCapsule(PyObject* args, PyObject* kwds) { // Return object proxy as an opaque PyCapsule. void* addr = GetCPPInstanceAddress("as_capsule", args, kwds); @@ -613,7 +613,7 @@ static PyObject* AsCapsule(PyObject* /* unused */, PyObject* args, } //---------------------------------------------------------------------------- -static PyObject* AsCTypes(PyObject* /* unused */, PyObject* args, +static PyObject* AsCTypes(PyObject* args, PyObject* kwds) { // Return object proxy as a ctypes c_void_p void* addr = GetCPPInstanceAddress("as_ctypes", args, kwds); @@ -677,7 +677,7 @@ static PyObject* AsMemoryView(PyObject* /* unused */, PyObject* pyobject) { } //---------------------------------------------------------------------------- -static PyObject* BindObject(PyObject*, PyObject* args, PyObject* kwds) { +static PyObject* BindObject(PyObject* args, PyObject* kwds) { // From a long representing an address or a PyCapsule/CObject, bind to a // class. Py_ssize_t argc = PyTuple_GET_SIZE(args); diff --git a/test/Makefile b/test/Makefile index 0cd3372..62d1d22 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,7 +22,7 @@ dicts = $(addprefix cpp/,$(addsuffix Dict.so,$(dictnames))) all : $(dicts) PYTHON ?= python3 -cppflags= -Wall -Wextra -Werror -std=c++20 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register +cppflags= -std=c++17 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register PLATFORM := $(shell uname -s) ifeq ($(PLATFORM),Darwin) From 49d4f4f2963d6814f4e73ced74c9f61391eaae79 Mon Sep 17 00:00:00 2001 From: mcbarton Date: Tue, 1 Sep 2026 14:43:49 +0100 Subject: [PATCH 4/5] Fixes --- CMakeLists.txt | 2 +- test/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7722c04..004b86a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,7 +142,7 @@ target_include_directories(cppjit PRIVATE ) target_compile_options(cppjit PRIVATE - -Wall -Wextra -Wno-strict-aliasing -Wno-register -Werror + -Wall -Wextra -Wno-strict-aliasing -Wno-register ) if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/test/Makefile b/test/Makefile index 62d1d22..a7698e2 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,7 +22,7 @@ dicts = $(addprefix cpp/,$(addsuffix Dict.so,$(dictnames))) all : $(dicts) PYTHON ?= python3 -cppflags= -std=c++17 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register +cppflags= -Wall -std=c++20 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register PLATFORM := $(shell uname -s) ifeq ($(PLATFORM),Darwin) From daa55ff46cb9bb47ce685a073d64455dc4827640 Mon Sep 17 00:00:00 2001 From: mcbarton Date: Tue, 1 Sep 2026 14:44:24 +0100 Subject: [PATCH 5/5] Fix --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index a7698e2..924d62a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,7 +22,7 @@ dicts = $(addprefix cpp/,$(addsuffix Dict.so,$(dictnames))) all : $(dicts) PYTHON ?= python3 -cppflags= -Wall -std=c++20 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register +cppflags= -Wall -std=c++17 -O3 -fPIC -I$(shell $(PYTHON) -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register PLATFORM := $(shell uname -s) ifeq ($(PLATFORM),Darwin)