diff --git a/Include/pyport.h b/Include/pyport.h index 614a2789fb0781..5053c8d3ce031b 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -21,13 +21,20 @@ // 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; +}; +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 # 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 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 */ };