From 1ed296f8da1c7f28dacf94c86dda61d494c7c642 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 10 Feb 2026 14:35:43 +0100 Subject: [PATCH 1/2] gh-121617: Include for Py_CLEAR() macro If the _Py_TYPEOF macro is not available, include to get memcpy() for the Py_CLEAR() macro. The limited C API version 3.11 and newer doesn't include anymore. Add a Py_CLEAR() test in test_cext. Modify also _Py_TYPEOF to use C23 typeof() if available. --- Include/pyport.h | 7 +++++-- Include/refcount.h | 4 ++++ Lib/test/test_cext/extension.c | 6 ++++++ .../C_API/2026-02-10-14-49-49.gh-issue-121617.57vMqa.rst | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-02-10-14-49-49.gh-issue-121617.57vMqa.rst diff --git a/Include/pyport.h b/Include/pyport.h index 61e2317976eed1..1e1702abd99a2c 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -567,8 +567,11 @@ extern "C" { // // Example: _Py_TYPEOF(x) x_copy = (x); // -// The macro is only defined if GCC or clang compiler is used. -#if defined(__GNUC__) || defined(__clang__) +// On C23, use typeof(). Otherwise, the macro is only defined +// if GCC or clang compiler is used. +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define _Py_TYPEOF(expr) typeof(expr) +#elif defined(__GNUC__) || defined(__clang__) # define _Py_TYPEOF(expr) __typeof__(expr) #endif diff --git a/Include/refcount.h b/Include/refcount.h index 51346c7e519321..5b48630842d3f7 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -471,6 +471,9 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op) * and so avoid type punning. Otherwise, use memcpy() which causes type erasure * and so prevents the compiler to reuse an old cached 'op' value after * Py_CLEAR(). + * + * Include if _Py_TYPEOF() is not available, since the limited C API + * version 3.11 and newer doesn't include it. */ #ifdef _Py_TYPEOF #define Py_CLEAR(op) \ @@ -483,6 +486,7 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op) } \ } while (0) #else +#include // memcpy() #define Py_CLEAR(op) \ do { \ PyObject **_tmp_op_ptr = _Py_CAST(PyObject**, &(op)); \ diff --git a/Lib/test/test_cext/extension.c b/Lib/test/test_cext/extension.c index 0f668c1da32d6e..5547b831b5faeb 100644 --- a/Lib/test/test_cext/extension.c +++ b/Lib/test/test_cext/extension.c @@ -65,6 +65,8 @@ _testcext_exec( #endif ) { + PyObject *obj; + #ifdef __STDC_VERSION__ if (PyModule_AddIntMacro(module, __STDC_VERSION__) < 0) { return -1; @@ -75,6 +77,10 @@ _testcext_exec( Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int)); assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0); + // Test Py_CLEAR() + obj = NULL; + Py_CLEAR(obj); + return 0; } diff --git a/Misc/NEWS.d/next/C_API/2026-02-10-14-49-49.gh-issue-121617.57vMqa.rst b/Misc/NEWS.d/next/C_API/2026-02-10-14-49-49.gh-issue-121617.57vMqa.rst new file mode 100644 index 00000000000000..276948c37ce73c --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-02-10-14-49-49.gh-issue-121617.57vMqa.rst @@ -0,0 +1,3 @@ +Fix the :c:macro:`Py_CLEAR` implementation in the limited C API version 3.11 +and newer: include ```` to get the ``memcpy()`` function. Patch by +Victor Stinner. From 0e3dda37825ced641b3ff0d63146cff7ac0b7326 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 10 Feb 2026 15:27:24 +0100 Subject: [PATCH 2/2] Update the system includes doc --- Doc/c-api/intro.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index e7ea5b9ba4016c..83fa45466d9d6f 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -140,6 +140,10 @@ System includes * ```` * ```` + The ```` header is also included when using :ref:`Limited API + ` 3.11 or newer if Python is unable to get a ``typeof()`` + implementation. + .. note:: Since Python may define some pre-processor definitions which affect the standard