From 53a03aafd5812018a3821a2e83063fd3d6cd2576 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 5 Nov 2020 15:02:12 +0100 Subject: [PATCH] bpo-42262: Add Py_NewRef() and Py_XNewRef() (GH-23152) Added Py_NewRef() and Py_XNewRef() functions to increment the reference count of an object and return the object. --- Doc/c-api/refcounting.rst | 31 +++++++++++++++++++ Doc/whatsnew/3.10.rst | 4 +++ Include/boolobject.h | 4 +-- Include/object.h | 30 ++++++++++++++++-- .../2020-11-04-17-22-36.bpo-42262.fCWzBb.rst | 2 ++ Objects/object.c | 16 ++++++++++ PC/python3dll.c | 4 ++- 7 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-11-04-17-22-36.bpo-42262.fCWzBb.rst diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst index 0df12c67f40..b15c0e6aecc 100644 --- a/Doc/c-api/refcounting.rst +++ b/Doc/c-api/refcounting.rst @@ -16,12 +16,43 @@ objects. Increment the reference count for object *o*. The object must not be ``NULL``; if you aren't sure that it isn't ``NULL``, use :c:func:`Py_XINCREF`. + See also :c:func:`Py_NewRef`. + .. c:function:: void Py_XINCREF(PyObject *o) Increment the reference count for object *o*. The object may be ``NULL``, in which case the macro has no effect. + See also :c:func:`Py_XNewRef`. + + +.. c:function:: PyObject* Py_NewRef(PyObject *o) + + Increment the reference count of the object *o* and return the object *o*. + + The object *o* must not be ``NULL``. + + For example:: + + Py_INCREF(obj); + self->attr = obj; + + can be written as:: + + self->attr = Py_NewRef(obj); + + .. versionadded:: 3.10 + + +.. c:function:: PyObject* Py_XNewRef(PyObject *o) + + Similar to :c:func:`Py_NewRef`, but the object *o* can be NULL. + + If the object *o* is ``NULL``, the function just returns ``NULL``. + + .. versionadded:: 3.10 + .. c:function:: void Py_DECREF(PyObject *o) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 9d9284897be..bac1a2e6783 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -379,6 +379,10 @@ New Features success. (Contributed by Victor Stinner in :issue:`1635741`.) +* Added :c:func:`Py_NewRef` and :c:func:`Py_XNewRef` functions to increment the + reference count of an object and return the object. + (Contributed by Victor Stinner in :issue:`42262`.) + Porting to Python 3.10 ---------------------- diff --git a/Include/boolobject.h b/Include/boolobject.h index bb8044a2b02..6673d7206c0 100644 --- a/Include/boolobject.h +++ b/Include/boolobject.h @@ -22,8 +22,8 @@ PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct; #define Py_True ((PyObject *) &_Py_TrueStruct) /* Macros for returning Py_True or Py_False, respectively */ -#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True -#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#define Py_RETURN_TRUE return Py_NewRef(Py_True) +#define Py_RETURN_FALSE return Py_NewRef(Py_False) /* Function to return a bool from a C long */ PyAPI_FUNC(PyObject *) PyBool_FromLong(long); diff --git a/Include/object.h b/Include/object.h index 6ee4ee78485..835d9de01fb 100644 --- a/Include/object.h +++ b/Include/object.h @@ -526,6 +526,31 @@ they can have object code that is not dependent on Python compilation flags. PyAPI_FUNC(void) Py_IncRef(PyObject *); PyAPI_FUNC(void) Py_DecRef(PyObject *); +// Increment the reference count of the object and return the object. +PyAPI_FUNC(PyObject*) Py_NewRef(PyObject *obj); + +// Similar to Py_NewRef() but the object can be NULL. +PyAPI_FUNC(PyObject*) Py_XNewRef(PyObject *obj); + +static inline PyObject* _Py_NewRef(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} + +static inline PyObject* _Py_XNewRef(PyObject *obj) +{ + Py_XINCREF(obj); + return obj; +} + +// Py_NewRef() and Py_XNewRef() are exported as functions for the stable ABI. +// Names overriden with macros by static inline functions for best +// performances. +#define Py_NewRef(obj) _Py_NewRef(obj) +#define Py_XNewRef(obj) _Py_XNewRef(obj) + + /* _Py_NoneStruct is an object of undefined type which can be used in contexts where NULL (nil) is not suitable (since NULL often means 'error'). @@ -536,7 +561,7 @@ PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */ #define Py_None (&_Py_NoneStruct) /* Macro for returning Py_None from a function */ -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#define Py_RETURN_NONE return Py_NewRef(Py_None) /* Py_NotImplemented is a singleton used to signal that an operation is @@ -546,8 +571,7 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ #define Py_NotImplemented (&_Py_NotImplementedStruct) /* Macro for returning Py_NotImplemented from a function */ -#define Py_RETURN_NOTIMPLEMENTED \ - return Py_INCREF(Py_NotImplemented), Py_NotImplemented +#define Py_RETURN_NOTIMPLEMENTED return Py_NewRef(Py_NotImplemented) /* Rich comparison opcodes */ #define Py_LT 0 diff --git a/Misc/NEWS.d/next/C API/2020-11-04-17-22-36.bpo-42262.fCWzBb.rst b/Misc/NEWS.d/next/C API/2020-11-04-17-22-36.bpo-42262.fCWzBb.rst new file mode 100644 index 00000000000..8c1e4f41844 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-11-04-17-22-36.bpo-42262.fCWzBb.rst @@ -0,0 +1,2 @@ +Added :c:func:`Py_NewRef` and :c:func:`Py_XNewRef` functions to increment the +reference count of an object and return the object. Patch by Victor Stinner. diff --git a/Objects/object.c b/Objects/object.c index 7bc3e48d40a..be7790eefd1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2208,6 +2208,22 @@ PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) } +#undef Py_NewRef +#undef Py_XNewRef + +// Export Py_NewRef() and Py_XNewRef() as regular functions for the stable ABI. +PyObject* +Py_NewRef(PyObject *obj) +{ + return _Py_NewRef(obj); +} + +PyObject* +Py_XNewRef(PyObject *obj) +{ + return _Py_XNewRef(obj); +} + #ifdef __cplusplus } #endif diff --git a/PC/python3dll.c b/PC/python3dll.c index 7e4a5101773..d1fdd0ac54c 100644 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -40,8 +40,8 @@ EXPORT_FUNC(Py_AddPendingCall) EXPORT_FUNC(Py_AtExit) EXPORT_FUNC(Py_BuildValue) EXPORT_FUNC(Py_CompileString) -EXPORT_FUNC(Py_DecodeLocale) EXPORT_FUNC(Py_DecRef) +EXPORT_FUNC(Py_DecodeLocale) EXPORT_FUNC(Py_EncodeLocale) EXPORT_FUNC(Py_EndInterpreter) EXPORT_FUNC(Py_EnterRecursiveCall) @@ -72,6 +72,7 @@ EXPORT_FUNC(Py_LeaveRecursiveCall) EXPORT_FUNC(Py_Main) EXPORT_FUNC(Py_MakePendingCalls) EXPORT_FUNC(Py_NewInterpreter) +EXPORT_FUNC(Py_NewRef) EXPORT_FUNC(Py_ReprEnter) EXPORT_FUNC(Py_ReprLeave) EXPORT_FUNC(Py_SetPath) @@ -80,6 +81,7 @@ EXPORT_FUNC(Py_SetPythonHome) EXPORT_FUNC(Py_SetRecursionLimit) EXPORT_FUNC(Py_SymtableString) EXPORT_FUNC(Py_VaBuildValue) +EXPORT_FUNC(Py_XNewRef) EXPORT_FUNC(PyArg_Parse) EXPORT_FUNC(PyArg_ParseTuple) EXPORT_FUNC(PyArg_ParseTupleAndKeywords)