Skip to content

Commit bba99f2

Browse files
authored
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.
1 parent 4849a01 commit bba99f2

3 files changed

Lines changed: 10 additions & 7 deletions

File tree

Include/cpython/object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
352352
#ifdef _Py_TYPEOF
353353
#define Py_SETREF(dst, src) \
354354
do { \
355-
_Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
355+
_Py_TYPEOF(&(dst)) _tmp_dst_ptr = &(dst); \
356356
_Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
357357
*_tmp_dst_ptr = (src); \
358358
Py_DECREF(_tmp_old_dst); \
@@ -374,7 +374,7 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
374374
#ifdef _Py_TYPEOF
375375
#define Py_XSETREF(dst, src) \
376376
do { \
377-
_Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
377+
_Py_TYPEOF(&(dst)) _tmp_dst_ptr = &(dst); \
378378
_Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
379379
*_tmp_dst_ptr = (src); \
380380
Py_XDECREF(_tmp_old_dst); \

Include/pyport.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -538,15 +538,18 @@ extern "C" {
538538
//
539539
// Example: _Py_TYPEOF(x) x_copy = (x);
540540
//
541-
// On C23, use typeof(). Otherwise __typeof__() if on GCC, clang or
542-
// MSVC 17.9 and newer. Else if on C++11 or newer, decltype() is used.
541+
// On C23, use typeof(). On C++11, use decltype(). Otherwise, use __typeof__()
542+
// if on GCC, clang or MSVC 17.9 and newer.
543+
//
544+
// On MSVC, check also _MSVC_LANG since __cplusplus is 199711L unless
545+
// the /Zc:__cplusplus flag is used.
543546
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
544547
# define _Py_TYPEOF(expr) typeof(expr)
548+
#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)
549+
# define _Py_TYPEOF(expr) decltype(expr)
545550
#elif defined(__GNUC__) || defined(__clang__) || \
546551
(defined(_MSC_VER) && _MSC_VER >= 1939)
547552
# define _Py_TYPEOF(expr) __typeof__(expr)
548-
#elif defined(__cplusplus) && __cplusplus >= 201103L
549-
# define _Py_TYPEOF(expr) decltype(expr)
550553
#endif
551554

552555

Include/refcount.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
482482
#ifdef _Py_TYPEOF
483483
#define Py_CLEAR(op) \
484484
do { \
485-
_Py_TYPEOF(op)* _tmp_op_ptr = &(op); \
485+
_Py_TYPEOF(&(op)) _tmp_op_ptr = &(op); \
486486
_Py_TYPEOF(op) _tmp_old_op = (*_tmp_op_ptr); \
487487
if (_tmp_old_op != _Py_NULL) { \
488488
*_tmp_op_ptr = _Py_NULL; \

0 commit comments

Comments
 (0)