From 2d6d57a91983e1eb0a84f8a8c938797cf5dab82b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 02:51:19 +0200 Subject: [PATCH] gh-105059: In C++, Py_INCREF() uses a function call In C++, Py_INCREF() and Py_DECREF() are now implemented as function calls. Moreover, in C++, PyObject.ob_refcnt type is just Py_ssize_t: don't use an anonymous union to avoid compiler warnings (anonymous unions were added to C11). --- Include/object.h | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/Include/object.h b/Include/object.h index 3ef64511399c66..76a89ee3a2e593 100644 --- a/Include/object.h +++ b/Include/object.h @@ -134,13 +134,21 @@ check by comparing the reference count field to the immortality reference count. { _Py_IMMORTAL_REFCNT }, \ (type) \ }, -#else +#elif !defined(__cplusplus) #define PyObject_HEAD_INIT(type) \ { \ _PyObject_EXTRA_INIT \ { 1 }, \ (type) \ }, +#else + // gh-105059: In C++, ob_refcnt type is Py_ssize_t +#define PyObject_HEAD_INIT(type) \ + { \ + _PyObject_EXTRA_INIT \ + 1, \ + (type) \ + }, #endif /* Py_BUILD_CORE */ #define PyVarObject_HEAD_INIT(type, size) \ @@ -165,12 +173,18 @@ check by comparing the reference count field to the immortality reference count. */ struct _object { _PyObject_HEAD_EXTRA +#ifndef __cplusplus union { Py_ssize_t ob_refcnt; #if SIZEOF_VOID_P > 4 PY_UINT32_T ob_refcnt_split[2]; #endif }; +#else + // gh-105059: In C++, avoid anonymous union for ob_refcnt. + // C++ uses opaque function calls for Py_INCREF() and Py_DECREF(). + Py_ssize_t ob_refcnt; +#endif PyTypeObject *ob_type; }; @@ -611,15 +625,18 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *); static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) { #if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG)) - // Stable ABI implements Py_INCREF() as a function call on limited C API - // version 3.12 and newer, and on Python built in debug mode. _Py_IncRef() - // was added to Python 3.10.0a7, use Py_IncRef() on older Python versions. - // Py_IncRef() accepts NULL whereas _Py_IncRef() doesn't. + // In limited C API version 3.12 and newer and on Python built in debug + // mode, Py_INCREF() is implemented as a function call. _Py_IncRef() was + // added to Python 3.10.0a7, use Py_IncRef() on older Python versions. + // Py_IncRef() accepts NULL, whereas _Py_IncRef() doesn't. # if Py_LIMITED_API+0 >= 0x030a00A7 _Py_IncRef(op); # else Py_IncRef(op); # endif +#elif defined(__cplusplus) + // gh-105059: In C++, Py_INCREF() is implemented as a function call + _Py_IncRef(op); #else // Non-limited C API and limited C API for Python 3.9 and older access // directly PyObject.ob_refcnt. @@ -649,10 +666,10 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) #endif #if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG)) -// Stable ABI implements Py_DECREF() as a function call on limited C API -// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was -// added to Python 3.10.0a7, use Py_DecRef() on older Python versions. -// Py_DecRef() accepts NULL whereas _Py_IncRef() doesn't. +// In limited C API version 3.12 and newer and on Python built in debug mode, +// Py_DECREF() is implemented as a function call. _Py_DecRef() was added to +// Python 3.10.0a7, use Py_DecRef() on older Python versions. Py_DecRef() +// accepts NULL, whereas _Py_DecRef() doesn't. static inline void Py_DECREF(PyObject *op) { # if Py_LIMITED_API+0 >= 0x030a00A7 _Py_DecRef(op); @@ -662,6 +679,13 @@ static inline void Py_DECREF(PyObject *op) { } #define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op)) +#elif defined(__cplusplus) +// gh-105059: In C++, Py_DECREF() is implemented as a function call +static inline void Py_DECREF(PyObject *op) { + _Py_DecRef(op); +} +#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op)) + #elif defined(Py_REF_DEBUG) static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) {