diff --git a/Doc/c-api/coro.rst b/Doc/c-api/coro.rst index caa855a10d20ca9..019a576b3b96137 100644 --- a/Doc/c-api/coro.rst +++ b/Doc/c-api/coro.rst @@ -25,11 +25,3 @@ return. Return true if *ob*'s type is :c:type:`PyCoro_Type`; *ob* must not be ``NULL``. This function always succeeds. - - -.. c:function:: PyObject* PyCoro_New(PyFrameObject *frame, PyObject *name, PyObject *qualname) - - Create and return a new coroutine object based on the *frame* object, - with ``__name__`` and ``__qualname__`` set to *name* and *qualname*. - A reference to *frame* is stolen by this function. The *frame* argument - must not be ``NULL``. diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst index 0eb5922f6da75f2..11cf8817c29dee4 100644 --- a/Doc/c-api/gen.rst +++ b/Doc/c-api/gen.rst @@ -6,8 +6,7 @@ Generator Objects ----------------- Generator objects are what Python uses to implement generator iterators. They -are normally created by iterating over a function that yields values, rather -than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. +are normally created by iterating over a function that yields values. .. c:type:: PyGenObject @@ -30,17 +29,3 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. Return true if *ob*'s type is :c:type:`PyGen_Type`; *ob* must not be ``NULL``. This function always succeeds. - - -.. c:function:: PyObject* PyGen_New(PyFrameObject *frame) - - Create and return a new generator object based on the *frame* object. - A reference to *frame* is stolen by this function. The argument must not be - ``NULL``. - -.. c:function:: PyObject* PyGen_NewWithQualName(PyFrameObject *frame, PyObject *name, PyObject *qualname) - - Create and return a new generator object based on the *frame* object, - with ``__name__`` and ``__qualname__`` set to *name* and *qualname*. - A reference to *frame* is stolen by this function. The *frame* argument - must not be ``NULL``. diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 349c4dd5be3d811..aaa432786e2701b 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -959,22 +959,9 @@ PyGen_Check:PyObject*:ob:0: PyGen_CheckExact:int::: PyGen_CheckExact:PyObject*:ob:0: -PyGen_New:PyObject*::+1: -PyGen_New:PyFrameObject*:frame:0: - -PyGen_NewWithQualName:PyObject*::+1: -PyGen_NewWithQualName:PyFrameObject*:frame:0: -PyGen_NewWithQualName:PyObject*:name:0: -PyGen_NewWithQualName:PyObject*:qualname:0: - PyCoro_CheckExact:int::: PyCoro_CheckExact:PyObject*:ob:0: -PyCoro_New:PyObject*::+1: -PyCoro_New:PyFrameObject*:frame:0: -PyCoro_New:PyObject*:name:0: -PyCoro_New:PyObject*:qualname:0: - PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules PyImport_AddModule:const char*:name:: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index e9e25b9dc4664f9..def57be63833296 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -944,3 +944,18 @@ Removed * Remove ``_use_broken_old_ctypes_structure_semantics_`` flag from :mod:`ctypes` module. (Contributed by Nikita Sobolev in :gh:`99285`.) + +* Remove untested functions which were used to create generators and + coroutines: + + * ``PyAsyncGen_New()`` + * ``PyCoro_New()`` + * ``PyGen_New()`` + * ``PyGen_NewWithQualName()`` + + Since 3.11, these functions can no longer be used in practice, because there + is no public C API function creating a frame usable by these functions. In + Python 3.10, these functions were called directly by Python, but Python now + uses another internal function which create generators and coroutines with no + frame ("frame cleared" state). + (Contributed by Victor Stinner in :gh:`99485`.) diff --git a/Include/cpython/genobject.h b/Include/cpython/genobject.h index 6127ba7babb80f2..8773c281ce33eea 100644 --- a/Include/cpython/genobject.h +++ b/Include/cpython/genobject.h @@ -40,9 +40,6 @@ PyAPI_DATA(PyTypeObject) PyGen_Type; #define PyGen_Check(op) PyObject_TypeCheck((op), &PyGen_Type) #define PyGen_CheckExact(op) Py_IS_TYPE((op), &PyGen_Type) -PyAPI_FUNC(PyObject *) PyGen_New(PyFrameObject *); -PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(PyFrameObject *, - PyObject *name, PyObject *qualname); PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *); PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); @@ -58,8 +55,6 @@ PyAPI_DATA(PyTypeObject) PyCoro_Type; PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type; #define PyCoro_CheckExact(op) Py_IS_TYPE((op), &PyCoro_Type) -PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *, - PyObject *name, PyObject *qualname); /* --- Asynchronous Generators -------------------------------------------- */ @@ -73,9 +68,6 @@ PyAPI_DATA(PyTypeObject) _PyAsyncGenASend_Type; PyAPI_DATA(PyTypeObject) _PyAsyncGenWrappedValue_Type; PyAPI_DATA(PyTypeObject) _PyAsyncGenAThrow_Type; -PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *, - PyObject *name, PyObject *qualname); - #define PyAsyncGen_CheckExact(op) Py_IS_TYPE((op), &PyAsyncGen_Type) diff --git a/Misc/NEWS.d/next/C API/2022-12-07-15-13-10.gh-issue-99485.bwn7ef.rst b/Misc/NEWS.d/next/C API/2022-12-07-15-13-10.gh-issue-99485.bwn7ef.rst new file mode 100644 index 000000000000000..6668ffdd6f14cb8 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-12-07-15-13-10.gh-issue-99485.bwn7ef.rst @@ -0,0 +1,13 @@ +Remove untested functions which were used to create generators and +coroutines: + +* ``PyAsyncGen_New()`` +* ``PyCoro_New()`` +* ``PyGen_New()`` +* ``PyGen_NewWithQualName()`` + +Since 3.11, these functions can no longer be used in practice, because there +is no public C API function creating a frame usable by these functions. In +Python 3.10, these functions were called directly by Python, but Python now +uses another internal function which create generators and coroutines with +no frame ("frame cleared" state). Patch by Victor Stinner. diff --git a/Objects/genobject.c b/Objects/genobject.c index c006f1af2177f94..f8df23707db75ae 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -914,56 +914,6 @@ _Py_MakeCoro(PyFunctionObject *func) return coro; } -static PyObject * -gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, - PyObject *name, PyObject *qualname) -{ - PyCodeObject *code = f->f_frame->f_code; - int size = code->co_nlocalsplus + code->co_stacksize; - PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size); - if (gen == NULL) { - Py_DECREF(f); - return NULL; - } - /* Copy the frame */ - assert(f->f_frame->frame_obj == NULL); - assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; - _PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame); - gen->gi_frame_state = FRAME_CREATED; - assert(frame->frame_obj == f); - f->f_frame = frame; - frame->owner = FRAME_OWNED_BY_GENERATOR; - assert(PyObject_GC_IsTracked((PyObject *)f)); - gen->gi_code = PyFrame_GetCode(f); - Py_INCREF(gen->gi_code); - Py_DECREF(f); - gen->gi_weakreflist = NULL; - gen->gi_exc_state.exc_value = NULL; - gen->gi_exc_state.previous_item = NULL; - if (name != NULL) - gen->gi_name = Py_NewRef(name); - else - gen->gi_name = Py_NewRef(gen->gi_code->co_name); - if (qualname != NULL) - gen->gi_qualname = Py_NewRef(qualname); - else - gen->gi_qualname = Py_NewRef(gen->gi_code->co_qualname); - _PyObject_GC_TRACK(gen); - return (PyObject *)gen; -} - -PyObject * -PyGen_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname) -{ - return gen_new_with_qualname(&PyGen_Type, f, name, qualname); -} - -PyObject * -PyGen_New(PyFrameObject *f) -{ - return gen_new_with_qualname(&PyGen_Type, f, NULL, NULL); -} /* Coroutine Object */ @@ -1311,31 +1261,6 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame) return cr_origin; } -PyObject * -PyCoro_New(PyFrameObject *f, PyObject *name, PyObject *qualname) -{ - PyObject *coro = gen_new_with_qualname(&PyCoro_Type, f, name, qualname); - if (!coro) { - return NULL; - } - - PyThreadState *tstate = _PyThreadState_GET(); - int origin_depth = tstate->coroutine_origin_tracking_depth; - - if (origin_depth == 0) { - ((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL; - } else { - PyObject *cr_origin = compute_cr_origin(origin_depth, _PyEval_GetFrame()); - ((PyCoroObject *)coro)->cr_origin_or_finalizer = cr_origin; - if (!cr_origin) { - Py_DECREF(coro); - return NULL; - } - } - - return coro; -} - /* ========= Asynchronous Generators ========= */ @@ -1604,23 +1529,6 @@ get_async_gen_state(void) #endif -PyObject * -PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) -{ - PyAsyncGenObject *o; - o = (PyAsyncGenObject *)gen_new_with_qualname( - &PyAsyncGen_Type, f, name, qualname); - if (o == NULL) { - return NULL; - } - o->ag_origin_or_finalizer = NULL; - o->ag_closed = 0; - o->ag_hooks_inited = 0; - o->ag_running_async = 0; - return (PyObject*)o; -} - - void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp) {