Skip to content

Commit a93f29c

Browse files
committed
Backport Py_CLEAR/Py_SETREF/Py_XSETREF from main
1 parent 8c7671f commit a93f29c

3 files changed

Lines changed: 44 additions & 8 deletions

File tree

‎Include/cpython/object.h‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,21 +331,29 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
331331
* `dst` points to a valid object.
332332
*
333333
* Temporary variables are used to only evaluate macro arguments once and so
334-
* avoid the duplication of side effects. _Py_TYPEOF() or memcpy() is used to
335-
* avoid a miscompilation caused by type punning. See Py_CLEAR() comment for
336-
* implementation details about type punning.
334+
* avoid the duplication of side effects. _Py_TYPEOF(), C++ auto, or memcpy()
335+
* is used to avoid a miscompilation caused by type punning. See Py_CLEAR()
336+
* comment for implementation details about type punning.
337337
*
338338
* The memcpy() implementation does not emit a compiler warning if 'src' has
339339
* not the same type than 'src': any pointer type is accepted for 'src'.
340340
*/
341341
#ifdef _Py_TYPEOF
342342
#define Py_SETREF(dst, src) \
343343
do { \
344-
_Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
344+
_Py_TYPEOF(&(dst)) _tmp_dst_ptr = &(dst); \
345345
_Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
346346
*_tmp_dst_ptr = (src); \
347347
Py_DECREF(_tmp_old_dst); \
348348
} while (0)
349+
#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)
350+
#define Py_SETREF(dst, src) \
351+
do { \
352+
auto _tmp_dst_ptr = &(dst); \
353+
auto _tmp_old_dst = (*_tmp_dst_ptr); \
354+
*_tmp_dst_ptr = (src); \
355+
Py_DECREF(_tmp_old_dst); \
356+
} while (0)
349357
#else
350358
#define Py_SETREF(dst, src) \
351359
do { \
@@ -363,11 +371,19 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
363371
#ifdef _Py_TYPEOF
364372
#define Py_XSETREF(dst, src) \
365373
do { \
366-
_Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
374+
_Py_TYPEOF(&(dst)) _tmp_dst_ptr = &(dst); \
367375
_Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
368376
*_tmp_dst_ptr = (src); \
369377
Py_XDECREF(_tmp_old_dst); \
370378
} while (0)
379+
#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)
380+
#define Py_XSETREF(dst, src) \
381+
do { \
382+
auto _tmp_dst_ptr = &(dst); \
383+
auto _tmp_old_dst = (*_tmp_dst_ptr); \
384+
*_tmp_dst_ptr = (src); \
385+
Py_XDECREF(_tmp_old_dst); \
386+
} while (0)
371387
#else
372388
#define Py_XSETREF(dst, src) \
373389
do { \

‎Include/pyport.h‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,15 @@ extern "C" {
565565
//
566566
// Example: _Py_TYPEOF(x) x_copy = (x);
567567
//
568-
// The macro is only defined if GCC or clang compiler is used.
569-
#if defined(__GNUC__) || defined(__clang__)
568+
// On C23, use typeof(). Otherwise, use __typeof__()
569+
// if on GCC, clang or MSVC 17.9 and newer.
570+
//
571+
// gh-157649: Do not use decltype() on C++, since it produces invalid code in
572+
// Py_CLEAR()/Py_SETREF().
573+
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
574+
# define _Py_TYPEOF(expr) typeof(expr)
575+
#elif (defined(__GNUC__) || defined(__clang__) \
576+
|| (defined(_MSC_VER) && _MSC_VER >= 1939 && !defined(__cplusplus)))
570577
# define _Py_TYPEOF(expr) __typeof__(expr)
571578
#endif
572579

‎Include/refcount.h‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,17 +472,30 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
472472
* and so avoid type punning. Otherwise, use memcpy() which causes type erasure
473473
* and so prevents the compiler to reuse an old cached 'op' value after
474474
* Py_CLEAR().
475+
*
476+
* On C++11 and newer, use "auto". On MSVC, check also _MSVC_LANG since
477+
* __cplusplus is 199711L unless the /Zc:__cplusplus flag is used.
475478
*/
476479
#ifdef _Py_TYPEOF
477480
#define Py_CLEAR(op) \
478481
do { \
479-
_Py_TYPEOF(op)* _tmp_op_ptr = &(op); \
482+
_Py_TYPEOF(&(op)) _tmp_op_ptr = &(op); \
480483
_Py_TYPEOF(op) _tmp_old_op = (*_tmp_op_ptr); \
481484
if (_tmp_old_op != _Py_NULL) { \
482485
*_tmp_op_ptr = _Py_NULL; \
483486
Py_DECREF(_tmp_old_op); \
484487
} \
485488
} while (0)
489+
#elif defined(__cplusplus) && (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)
490+
#define Py_CLEAR(op) \
491+
do { \
492+
auto _tmp_op_ptr = &(op); \
493+
auto _tmp_old_op = (*_tmp_op_ptr); \
494+
if (_tmp_old_op != _Py_NULL) { \
495+
*_tmp_op_ptr = _Py_NULL; \
496+
Py_DECREF(_tmp_old_op); \
497+
} \
498+
} while (0)
486499
#else
487500
#define Py_CLEAR(op) \
488501
do { \

0 commit comments

Comments
 (0)