From 8bb1fabd55c82b698484f925663885ed9f1fe652 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Sat, 11 Apr 2020 06:30:50 +0800 Subject: [PATCH 01/12] Convert PyObject_IS_GC() macro to a function --- Doc/c-api/gcsupport.rst | 6 ++++++ Include/cpython/objimpl.h | 4 +--- .../C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst | 2 ++ Modules/gcmodule.c | 10 ++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 924a7fd2fda4d5..05d4647f430526 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -60,6 +60,12 @@ Constructors for container types must conform to two rules: followed by the :c:member:`~PyTypeObject.tp_traverse` handler become valid, usually near the end of the constructor. +.. c:function:: int PyObject_IS_GC(PyObject *obj) + + Return non-zero if the object have GC head. Return zero otherwise. + + .. versionadded:: 3.9 + Similarly, the deallocator for the object must conform to a similar pair of rules: diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 832622cb61921f..334327fbc32ffd 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -121,9 +121,7 @@ PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void); /* Test if an object has a GC head */ -#define PyObject_IS_GC(o) \ - (PyType_IS_GC(Py_TYPE(o)) \ - && (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o))) +PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); /* GC information is stored BEFORE the object structure. */ typedef struct { diff --git a/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst new file mode 100644 index 00000000000000..67f8b0f05efb5d --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst @@ -0,0 +1,2 @@ +Convert :c:fun:`PyObject_IS_GC` macro to a function to hide +implementation details: the macro test an object have GC head or not. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 1bc41fb83d8a60..52bf287af5fcd0 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2203,6 +2203,16 @@ PyObject_GC_UnTrack(void *op_raw) } } +/* Test if an object has a GC head */ +int +PyObject_IS_GC(PyObject *obj) +{ + if (PyType_IS_GC(Py_TYPE(obj))) { + return (Py_TYPE(obj)->tp_is_gc == NULL || Py_TYPE(obj)->tp_is_gc(obj)); + } + return 0; +} + static PyObject * _PyObject_GC_Alloc(int use_calloc, size_t basicsize) { From be2bbab999b03d0a805ce7d422032cd1897fb6b9 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Sat, 11 Apr 2020 06:46:31 +0800 Subject: [PATCH 02/12] Update 2020-04-11-06-12-44.bpo-40170.cmM9oK.rst Fix typo of news --- Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst index 67f8b0f05efb5d..6ec5e17b1f03f8 100644 --- a/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst +++ b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst @@ -1,2 +1,2 @@ -Convert :c:fun:`PyObject_IS_GC` macro to a function to hide +Convert :c:func:`PyObject_IS_GC` macro to a function to hide implementation details: the macro test an object have GC head or not. From 0783d0b42ab56d18197b1a1793b4cb3225259dae Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Mon, 13 Apr 2020 14:04:36 +0800 Subject: [PATCH 03/12] add _PyObject_IS_GC() --- Include/cpython/objimpl.h | 12 +++++++++++- Modules/gcmodule.c | 21 +++++++++------------ Objects/object.c | 4 ++-- Python/sysmodule.c | 2 +- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 334327fbc32ffd..2115e7732aa86d 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -123,6 +123,16 @@ PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void); /* Test if an object has a GC head */ PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); +/* Fast inlined version of PyObject_IS_GC() */ +static inline int +_PyObject_IS_GC(PyObject *obj) +{ + if (PyType_IS_GC(Py_TYPE(obj))) { + return (Py_TYPE(obj)->tp_is_gc == NULL || Py_TYPE(obj)->tp_is_gc(obj)); + } + return 0; +} + /* GC information is stored BEFORE the object structure. */ typedef struct { // Pointer to next object in the list. @@ -142,7 +152,7 @@ typedef struct { /* True if the object may be tracked by the GC in the future, or already is. This can be useful to implement some optimizations. */ #define _PyObject_GC_MAY_BE_TRACKED(obj) \ - (PyObject_IS_GC(obj) && \ + (_PyObject_IS_GC(obj) && \ (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj))) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 9fab0189d710d4..cdba8ebe2a239e 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -441,7 +441,7 @@ visit_decref(PyObject *op, void *parent) { _PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op)); - if (PyObject_IS_GC(op)) { + if (_PyObject_IS_GC(op)) { PyGC_Head *gc = AS_GC(op); /* We're only interested in gc_refs for objects in the * generation being collected, which can be recognized @@ -477,7 +477,7 @@ subtract_refs(PyGC_Head *containers) static int visit_reachable(PyObject *op, PyGC_Head *reachable) { - if (!PyObject_IS_GC(op)) { + if (!_PyObject_IS_GC(op)) { return 0; } @@ -704,7 +704,7 @@ clear_unreachable_mask(PyGC_Head *unreachable) static int visit_move(PyObject *op, PyGC_Head *tolist) { - if (PyObject_IS_GC(op)) { + if (_PyObject_IS_GC(op)) { PyGC_Head *gc = AS_GC(op); if (gc_is_collecting(gc)) { gc_list_move(gc, tolist); @@ -1715,7 +1715,7 @@ gc_get_referents(PyObject *self, PyObject *args) traverseproc traverse; PyObject *obj = PyTuple_GET_ITEM(args, i); - if (! PyObject_IS_GC(obj)) + if (!_PyObject_IS_GC(obj)) continue; traverse = Py_TYPE(obj)->tp_traverse; if (! traverse) @@ -1855,7 +1855,7 @@ gc_is_tracked(PyObject *module, PyObject *obj) { PyObject *result; - if (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) + if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) result = Py_True; else result = Py_False; @@ -1876,7 +1876,7 @@ static PyObject * gc_is_finalized(PyObject *module, PyObject *obj) /*[clinic end generated code: output=e1516ac119a918ed input=201d0c58f69ae390]*/ { - if (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { + if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { Py_RETURN_TRUE; } Py_RETURN_FALSE; @@ -2207,10 +2207,7 @@ PyObject_GC_UnTrack(void *op_raw) int PyObject_IS_GC(PyObject *obj) { - if (PyType_IS_GC(Py_TYPE(obj))) { - return (Py_TYPE(obj)->tp_is_gc == NULL || Py_TYPE(obj)->tp_is_gc(obj)); - } - return 0; + return _PyObject_IS_GC(obj); } static PyObject * @@ -2326,7 +2323,7 @@ PyObject_GC_Del(void *op) int PyObject_GC_IsTracked(PyObject* obj) { - if (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) { + if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) { return 1; } return 0; @@ -2335,7 +2332,7 @@ PyObject_GC_IsTracked(PyObject* obj) int PyObject_GC_IsFinalized(PyObject *obj) { - if (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { + if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) { return 1; } return 0; diff --git a/Objects/object.c b/Objects/object.c index ef4ba997de4273..b63cb4fd52892c 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2030,7 +2030,7 @@ _PyTrash_deposit_object(PyObject *op) PyThreadState *tstate = _PyThreadState_GET(); struct _gc_runtime_state *gcstate = &tstate->interp->gc; - _PyObject_ASSERT(op, PyObject_IS_GC(op)); + _PyObject_ASSERT(op, _PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); _PyObject_ASSERT(op, Py_REFCNT(op) == 0); _PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later); @@ -2042,7 +2042,7 @@ void _PyTrash_thread_deposit_object(PyObject *op) { PyThreadState *tstate = _PyThreadState_GET(); - _PyObject_ASSERT(op, PyObject_IS_GC(op)); + _PyObject_ASSERT(op, _PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); _PyObject_ASSERT(op, Py_REFCNT(op) == 0); _PyGCHead_SET_PREV(_Py_AS_GC(op), tstate->trash_delete_later); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 994e3582fe6b5c..fc192d70fd6576 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1679,7 +1679,7 @@ _PySys_GetSizeOf(PyObject *o) } /* add gc_head size */ - if (PyObject_IS_GC(o)) + if (_PyObject_IS_GC(o)) return ((size_t)size) + sizeof(PyGC_Head); return (size_t)size; } From c69d6972ecd69299da34473b5aac534f4a7a80a3 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Tue, 14 Apr 2020 19:31:20 +0800 Subject: [PATCH 04/12] update docs --- Doc/c-api/gcsupport.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 7bfdbf6e5c3b65..ea52ab3dd11495 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -63,9 +63,16 @@ Constructors for container types must conform to two rules: .. c:function:: int PyObject_IS_GC(PyObject *obj) - Return non-zero if the object have GC head. Return zero otherwise. + Return 0 if the object type does not have the :c:data:`Py_TPFLAGS_HAVE_GC` flag. + Otherwise, return non-zero if object type does not implement tp_is_gc slot or + if tp_is_gc(obj) is non-zero. - .. versionadded:: 3.9 + For example, if *obj* is a type(`PyTypeObject`), check if *obj* has + the :c:data:`Py_TPFLAGS_HEAPTYPE` flag. + + If the function returns non-zero, you can use :c:func:`PyObject_GC_ISTracked` + to check if the object is currently tracked by the GC. + Notice that if this function return zero, the object cannot be tracked the GC. .. c:function:: int PyObject_GC_IsTracked(PyObject *op) From 1dd8dd213c53d9b8b6571eeb4cd743557f771229 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Tue, 14 Apr 2020 22:53:01 +0800 Subject: [PATCH 05/12] Update Doc/c-api/gcsupport.rst Co-Authored-By: Victor Stinner --- Doc/c-api/gcsupport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index ea52ab3dd11495..3116554d435f72 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -67,7 +67,7 @@ Constructors for container types must conform to two rules: Otherwise, return non-zero if object type does not implement tp_is_gc slot or if tp_is_gc(obj) is non-zero. - For example, if *obj* is a type(`PyTypeObject`), check if *obj* has + For example, if *obj* is a type (:c:type:`PyTypeObject`), check if *obj* has the :c:data:`Py_TPFLAGS_HEAPTYPE` flag. If the function returns non-zero, you can use :c:func:`PyObject_GC_ISTracked` From 176f8a05aa765eec2146c9c36857c967400f671a Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Tue, 14 Apr 2020 22:55:31 +0800 Subject: [PATCH 06/12] Update Doc/c-api/gcsupport.rst Co-Authored-By: Victor Stinner --- Doc/c-api/gcsupport.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 3116554d435f72..fa0af6cb161ac0 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -64,8 +64,8 @@ Constructors for container types must conform to two rules: .. c:function:: int PyObject_IS_GC(PyObject *obj) Return 0 if the object type does not have the :c:data:`Py_TPFLAGS_HAVE_GC` flag. - Otherwise, return non-zero if object type does not implement tp_is_gc slot or - if tp_is_gc(obj) is non-zero. + Otherwise, return non-zero if object type does not implement ``tp_is_gc`` slot or + if ``tp_is_gc(obj)`` is non-zero. For example, if *obj* is a type (:c:type:`PyTypeObject`), check if *obj* has the :c:data:`Py_TPFLAGS_HEAPTYPE` flag. From 8d680115dc2dd0f0e7ca76106e070ed254973df3 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Tue, 14 Apr 2020 23:16:11 +0800 Subject: [PATCH 07/12] update some descriptions --- Doc/c-api/gcsupport.rst | 13 +++---------- Include/cpython/objimpl.h | 7 +++---- Modules/gcmodule.c | 1 - 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index fa0af6cb161ac0..b437e70b4bef3f 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -63,16 +63,9 @@ Constructors for container types must conform to two rules: .. c:function:: int PyObject_IS_GC(PyObject *obj) - Return 0 if the object type does not have the :c:data:`Py_TPFLAGS_HAVE_GC` flag. - Otherwise, return non-zero if object type does not implement ``tp_is_gc`` slot or - if ``tp_is_gc(obj)`` is non-zero. - - For example, if *obj* is a type (:c:type:`PyTypeObject`), check if *obj* has - the :c:data:`Py_TPFLAGS_HEAPTYPE` flag. - - If the function returns non-zero, you can use :c:func:`PyObject_GC_ISTracked` - to check if the object is currently tracked by the GC. - Notice that if this function return zero, the object cannot be tracked the GC. + Returns non-zero if the object implements the garbage collector protocol, + otherwise returns 0. The object cannot be tracked by the garbage collector + if this function return 0. .. c:function:: int PyObject_GC_IsTracked(PyObject *op) diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 461e3de74b5a61..2c361ca8c18c20 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -127,10 +127,9 @@ PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); static inline int _PyObject_IS_GC(PyObject *obj) { - if (PyType_IS_GC(Py_TYPE(obj))) { - return (Py_TYPE(obj)->tp_is_gc == NULL || Py_TYPE(obj)->tp_is_gc(obj)); - } - return 0; + return (PyType_IS_GC(Py_TYPE(obj)) + && (Py_TYPE(obj)->tp_is_gc == NULL + || Py_TYPE(obj)->tp_is_gc(obj))); } /* Code built with Py_BUILD_CORE must include pycore_gc.h instead which diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index cdba8ebe2a239e..5d635b553bfc9d 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2203,7 +2203,6 @@ PyObject_GC_UnTrack(void *op_raw) } } -/* Test if an object has a GC head */ int PyObject_IS_GC(PyObject *obj) { From ee0525bc84b86ed48be6ddd7ad1c09818d3c177c Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Tue, 14 Apr 2020 23:22:48 +0800 Subject: [PATCH 08/12] update docs --- Doc/c-api/gcsupport.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index b437e70b4bef3f..9b3d7d8f52da17 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -64,8 +64,9 @@ Constructors for container types must conform to two rules: .. c:function:: int PyObject_IS_GC(PyObject *obj) Returns non-zero if the object implements the garbage collector protocol, - otherwise returns 0. The object cannot be tracked by the garbage collector - if this function return 0. + otherwise returns 0. + + The object cannot be tracked by the garbage collector if this function return 0. .. c:function:: int PyObject_GC_IsTracked(PyObject *op) From a4d1a37c8e2d70c7bcdfb0366ad5abfe8c71b585 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Tue, 14 Apr 2020 23:24:38 +0800 Subject: [PATCH 09/12] fix typos --- Doc/c-api/gcsupport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 9b3d7d8f52da17..22de9866cc0555 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -66,7 +66,7 @@ Constructors for container types must conform to two rules: Returns non-zero if the object implements the garbage collector protocol, otherwise returns 0. - The object cannot be tracked by the garbage collector if this function return 0. + The object cannot be tracked by the garbage collector if this function returns 0. .. c:function:: int PyObject_GC_IsTracked(PyObject *op) From bdc61b9fb8545fdb58c45abf26710caa6d3ffb88 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Wed, 15 Apr 2020 00:00:58 +0800 Subject: [PATCH 10/12] remove _PyObject_IS_GC() to pycore_object.h --- Include/cpython/objimpl.h | 10 +--------- Include/internal/pycore_object.h | 9 +++++++++ Python/sysmodule.c | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 2c361ca8c18c20..b835936db70112 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -120,17 +120,9 @@ PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void); PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void); -/* Test if an object has a GC head */ +/* Test if an object implements the garbage collector protocol */ PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); -/* Fast inlined version of PyObject_IS_GC() */ -static inline int -_PyObject_IS_GC(PyObject *obj) -{ - return (PyType_IS_GC(Py_TYPE(obj)) - && (Py_TYPE(obj)->tp_is_gc == NULL - || Py_TYPE(obj)->tp_is_gc(obj))); -} /* Code built with Py_BUILD_CORE must include pycore_gc.h instead which defines a different _PyGC_FINALIZED() macro. */ diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 5c3d3cae235f47..edf965cb663967 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -100,6 +100,15 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) { return ((type->tp_flags & feature) != 0); } +// Fast inlined version of PyObject_IS_GC() +static inline int +_PyObject_IS_GC(PyObject *obj) +{ + return (PyType_IS_GC(Py_TYPE(obj)) + && (Py_TYPE(obj)->tp_is_gc == NULL + || Py_TYPE(obj)->tp_is_gc(obj))); +} + // Fast inlined version of PyType_IS_GC() #define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b472843d9df7f8..92f600311e0d15 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -19,6 +19,7 @@ Data members: #include "frameobject.h" #include "pycore_ceval.h" #include "pycore_initconfig.h" +#include "pycore_object.h" #include "pycore_pathconfig.h" #include "pycore_pyerrors.h" #include "pycore_pylifecycle.h" From 1c242b510a7d14fed0db1eed82a72aa2f7693bc5 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Wed, 15 Apr 2020 00:10:35 +0800 Subject: [PATCH 11/12] remove white space --- Doc/c-api/gcsupport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 22de9866cc0555..eee114c19d5904 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -65,7 +65,7 @@ Constructors for container types must conform to two rules: Returns non-zero if the object implements the garbage collector protocol, otherwise returns 0. - + The object cannot be tracked by the garbage collector if this function returns 0. From cffba905c5eae6c721387c413dfff5a0af6f8807 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Wed, 15 Apr 2020 00:12:52 +0800 Subject: [PATCH 12/12] update news --- Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst index 6ec5e17b1f03f8..832b7f6e081d52 100644 --- a/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst +++ b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst @@ -1,2 +1,2 @@ Convert :c:func:`PyObject_IS_GC` macro to a function to hide -implementation details: the macro test an object have GC head or not. +implementation details.