From dd910a707ea66afdd221f235546582e554207e38 Mon Sep 17 00:00:00 2001 From: da-woods Date: Sun, 15 May 2022 12:28:54 +0100 Subject: [PATCH 1/3] Fix C++ _Py_CAST with constant types Thus fixing PyUnicode_READ in C++. Fixes https://github.com/python/cpython/issues/92800 I've created a C++ helper struct definition to work out the type with constant added (it's OK to add const to a constant type in typedefs in C++). --- Include/pyport.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Include/pyport.h b/Include/pyport.h index 614a2789fb0781..db7a54c015f5a9 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -21,13 +21,16 @@ // non constant type using const_cast. For example, // _Py_CAST(PyObject*, op) can convert a "const PyObject*" to // "PyObject*". -// -// The type argument must not be constant. For example, in C++, -// _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)) +// _Py_add_const is purely for the implementation of the C++ cast +// It isn't intended as public interface +template +struct _Py_add_const { + typedef const T type; +}; +# define _Py_CAST(tp, expr) \ + const_cast(reinterpret_cast<_Py_add_const::type>(expr)) #else # define _Py_STATIC_CAST(type, expr) ((type)(expr)) # define _Py_CAST(type, expr) ((type)(expr)) From 928ebf50ee0d2a89ef0cef567c3e793d374a2e55 Mon Sep 17 00:00:00 2001 From: da-woods Date: Sun, 15 May 2022 13:11:14 +0100 Subject: [PATCH 2/3] Add pointer specialization --- Include/pyport.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Include/pyport.h b/Include/pyport.h index db7a54c015f5a9..5053c8d3ce031b 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -29,6 +29,10 @@ template struct _Py_add_const { typedef const T type; }; +template +struct _Py_add_const { // specialization for pointer + typedef const T* type; +}; # define _Py_CAST(tp, expr) \ const_cast(reinterpret_cast<_Py_add_const::type>(expr)) #else From 953418637644397dced8537a48bc03635caeed7e Mon Sep 17 00:00:00 2001 From: da-woods Date: Sun, 15 May 2022 14:44:25 +0100 Subject: [PATCH 3/3] Added test --- Lib/test/_testcppext.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp index dc40f0ee9eb1cb..41a5090e10b6bd 100644 --- a/Lib/test/_testcppext.cpp +++ b/Lib/test/_testcppext.cpp @@ -49,10 +49,23 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } +static PyObject * +test_unicode_read(PyObject *Py_UNUSED(module), PyObject *arg) { + // PyUnicode_READ contains a cast to a const and failed to compile (gh-92800) + if (!PyUnicode_Check(arg) || PyUnicode_GET_LENGTH(arg) > 0) { + Py_RETURN_NONE; // not a suitable unicode object + } + void* data = PyUnicode_DATA(arg); + unsigned int kind = PyUnicode_KIND(arg); + Py_UCS4 chr0 = PyUnicode_READ(kind, data, 0); + return PyLong_FromUnsignedLong(chr0); +} + static PyMethodDef _testcppext_methods[] = { {"add", _testcppext_add, METH_VARARGS, _testcppext_add_doc}, {"test_api_casts", test_api_casts, METH_NOARGS, nullptr}, + {"test_unicode_read", test_unicode_read, METH_O, nullptr}, {nullptr, nullptr, 0, nullptr} /* sentinel */ };