From 85a6ba9d4cc4458379fe3af2b7a02579092e38b8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Sep 2026 15:08:58 +0200 Subject: [PATCH 1/4] gh-121647: Prefer decltype() for _Py_TYPEOF() on C++ Using MSVC (on Windows), prefer decltype() over __typeof__() on C++. --- Include/pyport.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/pyport.h b/Include/pyport.h index 03f9b869bc82b5..07178f0a6b28c7 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -538,15 +538,15 @@ extern "C" { // // Example: _Py_TYPEOF(x) x_copy = (x); // -// On C23, use typeof(). Otherwise __typeof__() if on GCC, clang or -// MSVC 17.9 and newer. Else if on C++11 or newer, decltype() is used. +// On C23, use typeof(). On C++11, use decltype(). Otherwise, use __typeof__() +// if on GCC, clang or MSVC 17.9 and newer. #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L # define _Py_TYPEOF(expr) typeof(expr) +#elif defined(__cplusplus) && __cplusplus >= 201103L +# define _Py_TYPEOF(expr) decltype(expr) #elif defined(__GNUC__) || defined(__clang__) || \ (defined(_MSC_VER) && _MSC_VER >= 1939) # define _Py_TYPEOF(expr) __typeof__(expr) -#elif defined(__cplusplus) && __cplusplus >= 201103L -# define _Py_TYPEOF(expr) decltype(expr) #endif From 13de0a04c4391f4cd933b9c07f260d7bc8ed2a16 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Sep 2026 16:58:20 +0200 Subject: [PATCH 2/4] Use _MSVC_LANG macro --- Include/pyport.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Include/pyport.h b/Include/pyport.h index 07178f0a6b28c7..aaaa3024d3515d 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -540,10 +540,15 @@ extern "C" { // // On C23, use typeof(). On C++11, use decltype(). Otherwise, use __typeof__() // if on GCC, clang or MSVC 17.9 and newer. +// +// On MSVC, check also _MSVC_LANG since __cplusplus is 199711L unless +// the /Zc:__cplusplus flag is used. #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L # define _Py_TYPEOF(expr) typeof(expr) #elif defined(__cplusplus) && __cplusplus >= 201103L # define _Py_TYPEOF(expr) decltype(expr) +#elif defined(_MSVC_LANG) && _MSVC_LANG >= 201103L +# define _Py_TYPEOF(expr) decltype(expr) #elif defined(__GNUC__) || defined(__clang__) || \ (defined(_MSC_VER) && _MSC_VER >= 1939) # define _Py_TYPEOF(expr) __typeof__(expr) From ae56459232d5b9bb83558de05b779370de4e9851 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Sep 2026 17:19:01 +0200 Subject: [PATCH 3/4] Fix Py_CLEAR/Py_SETREF macros for C++ Replace "_Py_TYPEOF(dst)*" with "_Py_TYPEOF(&(dst))". In C++, "_Py_TYPEOF(dst)*" can fail with a compiler error. --- Include/cpython/object.h | 4 ++-- Include/refcount.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 4c5a677e5543ec..0ef52d4d2bc7b4 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -352,7 +352,7 @@ 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); \ @@ -374,7 +374,7 @@ 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); \ diff --git a/Include/refcount.h b/Include/refcount.h index b21697ae1780fa..d96c75421aef33 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -482,7 +482,7 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op) #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; \ From dec5373713c49ec624e6c9553820d104f6e0e0f5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 10 Sep 2026 18:37:07 +0200 Subject: [PATCH 4/4] Use Chris's suggestion --- Include/pyport.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Include/pyport.h b/Include/pyport.h index aaaa3024d3515d..744bae6c57e299 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -545,9 +545,7 @@ extern "C" { // the /Zc:__cplusplus flag is used. #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L # define _Py_TYPEOF(expr) typeof(expr) -#elif defined(__cplusplus) && __cplusplus >= 201103L -# define _Py_TYPEOF(expr) decltype(expr) -#elif defined(_MSVC_LANG) && _MSVC_LANG >= 201103L +#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >= 201103L) # define _Py_TYPEOF(expr) decltype(expr) #elif defined(__GNUC__) || defined(__clang__) || \ (defined(_MSC_VER) && _MSC_VER >= 1939)