From 636d461ba0812e6f24a0cf2c6922e269b1fb5efa Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Thu, 19 May 2022 11:57:41 +0200 Subject: [PATCH] Make _Py_Cast C++ version compatible with cast operator Use the adequate kind of cast based on the macro argument: const ref, cont pointer, ref or pointer. This should be compatible with C++ overloads. Fix #92898 --- Include/pyport.h | 28 ++++++++++++++++++++++++++-- Lib/test/_testcppext.cpp | 9 +++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Include/pyport.h b/Include/pyport.h index 614a2789fb0781..086ed4204e4ff1 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -26,8 +26,32 @@ // _Py_CAST(const PyObject*, expr) fails with a compiler error. #ifdef __cplusplus # define _Py_STATIC_CAST(type, expr) static_cast(expr) -# define _Py_CAST(type, expr) \ - const_cast(reinterpret_cast(expr)) + +extern "C++" { +namespace { +template +inline type _Py_reinterpret_cast_impl(expr_type *expr) { + return reinterpret_cast(expr); +} + +template +inline type _Py_reinterpret_cast_impl(expr_type const *expr) { + return reinterpret_cast(const_cast(expr)); +} + +template +inline type _Py_reinterpret_cast_impl(expr_type &expr) { + return static_cast(expr); +} + +template +inline type _Py_reinterpret_cast_impl(expr_type const &expr) { + return static_cast(const_cast(expr)); +} +} // namespace +} +# define _Py_CAST(type, expr) _Py_reinterpret_cast_impl(expr) + #else # define _Py_STATIC_CAST(type, expr) ((type)(expr)) # define _Py_CAST(type, expr) ((type)(expr)) diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp index f38b4870e0edbc..f6049eedd00048 100644 --- a/Lib/test/_testcppext.cpp +++ b/Lib/test/_testcppext.cpp @@ -40,6 +40,15 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) PyTypeObject *type = Py_TYPE(const_obj); assert(Py_REFCNT(const_obj) >= 1); + struct PyObjectProxy { + PyObject* obj; + operator PyObject *() { return obj; } + } proxy_obj = { obj }; + Py_INCREF(proxy_obj); + Py_DECREF(proxy_obj); + assert(Py_REFCNT(proxy_obj) >= 1); + + assert(type == &PyTuple_Type); assert(PyTuple_GET_SIZE(const_obj) == 2); PyObject *one = PyTuple_GET_ITEM(const_obj, 0);