https://github.com/python/cpython/commit/7ba9a776ec4c951e3905a191cfdb8d2f62914e26
commit: 7ba9a776ec4c951e3905a191cfdb8d2f62914e26
branch: 3.15
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-10T20:31:36Z
summary:
[3.15] gh-157649: Fix Py_CLEAR()/Py_SETREF() on C++ (#159143)
* gh-121647: Fix _Py_TYPEOF() on C++ (#157267)
Using MSVC (on Windows), _Py_TYPEOF() prefers decltype()
over __typeof__() on C++.
Fix also _Py_TYPEOF() usage in Py_CLEAR() and Py_SETREF() macros.
Replace "_Py_TYPEOF(dst)*" with "_Py_TYPEOF(&(dst))". In C++,
"_Py_TYPEOF(dst)*" can fail with a compiler error.
(cherry picked from commit bba99f2b3272cbe47af9bee05a294961c0528829)
* gh-157649: Fix Py_CLEAR()/Py_SETREF() on C++ (#158070)
On C++, do not use decltype() in _Py_TYPEOF since it produces invalid
code in Py_CLEAR() and Py_SETREF(). Instead, implement Py_CLEAR(),
Py_SETREF() and Py_XSETREF() using "auto" on C++11 and newer.
Add Py_CLEAR(), Py_SETREF() and Py_XSETREF() tests on an array.
(cherry picked from commit 333071231d3a46cccc32d7f44b99328c3299d0b1)
files:
A Misc/NEWS.d/next/C_API/2026-09-24-11-47-32.gh-issue-157649.3HSU2h.rst
M Include/cpython/object.h
M Include/pyport.h
M Include/refcount.h
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index c8b8119d44bb1d0..c0809effb996107 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -340,9 +340,9 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
* `dst` points to a valid object.
*
* Temporary variables are used to only evaluate macro arguments once and so
- * avoid the duplication of side effects. _Py_TYPEOF() or memcpy() is used to
- * avoid a miscompilation caused by type punning. See Py_CLEAR() comment for
- * implementation details about type punning.
+ * avoid the duplication of side effects. _Py_TYPEOF(), C++ auto, or memcpy()
+ * is used to avoid a miscompilation caused by type punning. See Py_CLEAR()
+ * comment for implementation details about type punning.
*
* The memcpy() implementation does not emit a compiler warning if 'src' has
* not the same type than 'src': any pointer type is accepted for 'src'.
@@ -350,11 +350,19 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
#ifdef _Py_TYPEOF
#define Py_SETREF(dst, src) \
do { \
- _Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
+ _Py_TYPEOF(&(dst)) _tmp_dst_ptr = &(dst); \
_Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
*_tmp_dst_ptr = (src); \
Py_DECREF(_tmp_old_dst); \
} while (0)
+#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >=
201103L)
+#define Py_SETREF(dst, src) \
+ do { \
+ auto _tmp_dst_ptr = &(dst); \
+ auto _tmp_old_dst = (*_tmp_dst_ptr); \
+ *_tmp_dst_ptr = (src); \
+ Py_DECREF(_tmp_old_dst); \
+ } while (0)
#else
#define Py_SETREF(dst, src) \
do { \
@@ -372,11 +380,19 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
#ifdef _Py_TYPEOF
#define Py_XSETREF(dst, src) \
do { \
- _Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
+ _Py_TYPEOF(&(dst)) _tmp_dst_ptr = &(dst); \
_Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
*_tmp_dst_ptr = (src); \
Py_XDECREF(_tmp_old_dst); \
} while (0)
+#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >=
201103L)
+#define Py_XSETREF(dst, src) \
+ do { \
+ auto _tmp_dst_ptr = &(dst); \
+ auto _tmp_old_dst = (*_tmp_dst_ptr); \
+ *_tmp_dst_ptr = (src); \
+ Py_XDECREF(_tmp_old_dst); \
+ } while (0)
#else
#define Py_XSETREF(dst, src) \
do { \
diff --git a/Include/pyport.h b/Include/pyport.h
index 73a3e6cdaf09200..9cfdd09689d5c81 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -538,11 +538,15 @@ extern "C" {
//
// Example: _Py_TYPEOF(x) x_copy = (x);
//
-// On C23, use typeof(). Otherwise, the macro is only defined
-// if GCC or clang compiler is used.
+// On C23, use typeof(). Otherwise, use __typeof__()
+// if on GCC, clang or MSVC 17.9 and newer.
+//
+// gh-157649: Do not use decltype() on C++, since it produces invalid code in
+// Py_CLEAR()/Py_SETREF().
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
# define _Py_TYPEOF(expr) typeof(expr)
-#elif defined(__GNUC__) || defined(__clang__)
+#elif (defined(__GNUC__) || defined(__clang__) \
+ || (defined(_MSC_VER) && _MSC_VER >= 1939 && !defined(__cplusplus)))
# define _Py_TYPEOF(expr) __typeof__(expr)
#endif
diff --git a/Include/refcount.h b/Include/refcount.h
index b21697ae1780fa8..39661680e85a183 100644
--- a/Include/refcount.h
+++ b/Include/refcount.h
@@ -478,17 +478,30 @@ 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().
+ *
+ * On C++11 and newer, use "auto". On MSVC, check also _MSVC_LANG since
+ * __cplusplus is 199711L unless the /Zc:__cplusplus flag is used.
*/
#ifdef _Py_TYPEOF
#define Py_CLEAR(op) \
do { \
- _Py_TYPEOF(op)* _tmp_op_ptr = &(op); \
+ _Py_TYPEOF(&(op)) _tmp_op_ptr = &(op); \
_Py_TYPEOF(op) _tmp_old_op = (*_tmp_op_ptr); \
if (_tmp_old_op != _Py_NULL) { \
*_tmp_op_ptr = _Py_NULL; \
Py_DECREF(_tmp_old_op); \
} \
} while (0)
+#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >=
201103L)
+#define Py_CLEAR(op) \
+ do { \
+ auto _tmp_op_ptr = &(op); \
+ auto _tmp_old_op = (*_tmp_op_ptr); \
+ if (_tmp_old_op != _Py_NULL) { \
+ *_tmp_op_ptr = _Py_NULL; \
+ Py_DECREF(_tmp_old_op); \
+ } \
+ } while (0)
#else
#define Py_CLEAR(op) \
do { \
diff --git
a/Misc/NEWS.d/next/C_API/2026-09-24-11-47-32.gh-issue-157649.3HSU2h.rst
b/Misc/NEWS.d/next/C_API/2026-09-24-11-47-32.gh-issue-157649.3HSU2h.rst
new file mode 100644
index 000000000000000..92eafbdbe39641c
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2026-09-24-11-47-32.gh-issue-157649.3HSU2h.rst
@@ -0,0 +1,4 @@
+Fix :c:macro:`Py_CLEAR` and :c:macro:`Py_SETREF` macros on C++: implement
+them using ``auto`` instead of ``decltype()``. Using ``decltype()``
+produced invalid code when clearing/setting an array item. Patch by Victor
+Stinner.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]