Skip to content

Commit 7a6873c

Browse files
jdemeyerencukou
authored andcommitted
bpo-37151: remove special case for PyCFunction from PyObject_Call (pythonGH-14684)
bpo-37151: remove special case for PyCFunction from PyObject_Call Alse, make the undocumented function PyCFunction_Call an alias of PyObject_Call and deprecate it.
1 parent 2d8d597 commit 7a6873c

File tree

6 files changed

+47
-66
lines changed

6 files changed

+47
-66
lines changed

Include/methodobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
3939
#define PyCFunction_GET_FLAGS(func) \
4040
(((PyCFunctionObject *)func) -> m_ml -> ml_flags)
4141
#endif
42-
PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
42+
Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
4343

4444
struct PyMethodDef {
4545
const char *ml_name; /* The name of the built-in function/method */
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``PyCFunction_Call`` is now a deprecated alias of :c:func:`PyObject_Call`.

Objects/call.c

Lines changed: 7 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
#include "frameobject.h"
66

77

8-
static PyObject *
9-
cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs);
10-
118
static PyObject *const *
129
_PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
1310
PyObject **p_kwnames);
@@ -236,11 +233,6 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
236233
if (_PyVectorcall_Function(callable) != NULL) {
237234
return PyVectorcall_Call(callable, args, kwargs);
238235
}
239-
else if (PyCFunction_Check(callable)) {
240-
/* This must be a METH_VARARGS function, otherwise we would be
241-
* in the previous case */
242-
return cfunction_call_varargs(callable, args, kwargs);
243-
}
244236
else {
245237
call = callable->ob_type->tp_call;
246238
if (call == NULL) {
@@ -261,6 +253,13 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
261253
}
262254

263255

256+
PyObject *
257+
PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
258+
{
259+
return PyObject_Call(callable, args, kwargs);
260+
}
261+
262+
264263
/* --- PyFunction call functions ---------------------------------- */
265264

266265
static PyObject* _Py_HOT_FUNCTION
@@ -363,60 +362,6 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
363362
}
364363

365364

366-
/* --- PyCFunction call functions --------------------------------- */
367-
368-
static PyObject *
369-
cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
370-
{
371-
assert(!PyErr_Occurred());
372-
assert(kwargs == NULL || PyDict_Check(kwargs));
373-
374-
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
375-
PyObject *self = PyCFunction_GET_SELF(func);
376-
PyObject *result;
377-
378-
assert(PyCFunction_GET_FLAGS(func) & METH_VARARGS);
379-
if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) {
380-
if (Py_EnterRecursiveCall(" while calling a Python object")) {
381-
return NULL;
382-
}
383-
384-
result = (*(PyCFunctionWithKeywords)(void(*)(void))meth)(self, args, kwargs);
385-
386-
Py_LeaveRecursiveCall();
387-
}
388-
else {
389-
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
390-
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
391-
((PyCFunctionObject*)func)->m_ml->ml_name);
392-
return NULL;
393-
}
394-
395-
if (Py_EnterRecursiveCall(" while calling a Python object")) {
396-
return NULL;
397-
}
398-
399-
result = (*meth)(self, args);
400-
401-
Py_LeaveRecursiveCall();
402-
}
403-
404-
return _Py_CheckFunctionResult(func, result, NULL);
405-
}
406-
407-
408-
PyObject *
409-
PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs)
410-
{
411-
/* For METH_VARARGS, we cannot use vectorcall as the vectorcall pointer
412-
* is NULL. This is intentional, since vectorcall would be slower. */
413-
if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) {
414-
return cfunction_call_varargs(func, args, kwargs);
415-
}
416-
return PyVectorcall_Call(func, args, kwargs);
417-
}
418-
419-
420365
/* --- More complex call functions -------------------------------- */
421366

422367
/* External interface to call any callable object.

Objects/methodobject.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ static PyObject * cfunction_vectorcall_NOARGS(
1919
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
2020
static PyObject * cfunction_vectorcall_O(
2121
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
22+
static PyObject * cfunction_call(
23+
PyObject *func, PyObject *args, PyObject *kwargs);
2224

2325

2426
PyObject *
@@ -289,7 +291,7 @@ PyTypeObject PyCFunction_Type = {
289291
0, /* tp_as_sequence */
290292
0, /* tp_as_mapping */
291293
(hashfunc)meth_hash, /* tp_hash */
292-
PyCFunction_Call, /* tp_call */
294+
cfunction_call, /* tp_call */
293295
0, /* tp_str */
294296
PyObject_GenericGetAttr, /* tp_getattro */
295297
0, /* tp_setattro */
@@ -441,3 +443,36 @@ cfunction_vectorcall_O(
441443
Py_LeaveRecursiveCall();
442444
return result;
443445
}
446+
447+
448+
static PyObject *
449+
cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
450+
{
451+
assert(!PyErr_Occurred());
452+
assert(kwargs == NULL || PyDict_Check(kwargs));
453+
454+
int flags = PyCFunction_GET_FLAGS(func);
455+
if (!(flags & METH_VARARGS)) {
456+
/* If this is not a METH_VARARGS function, delegate to vectorcall */
457+
return PyVectorcall_Call(func, args, kwargs);
458+
}
459+
460+
/* For METH_VARARGS, we cannot use vectorcall as the vectorcall pointer
461+
* is NULL. This is intentional, since vectorcall would be slower. */
462+
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
463+
PyObject *self = PyCFunction_GET_SELF(func);
464+
465+
PyObject *result;
466+
if (flags & METH_KEYWORDS) {
467+
result = (*(PyCFunctionWithKeywords)(void(*)(void))meth)(self, args, kwargs);
468+
}
469+
else {
470+
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
471+
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
472+
((PyCFunctionObject*)func)->m_ml->ml_name);
473+
return NULL;
474+
}
475+
result = meth(self, args);
476+
}
477+
return _Py_CheckFunctionResult(func, result, NULL);
478+
}

Python/ceval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5001,7 +5001,7 @@ do_call_core(PyThreadState *tstate, PyObject *func, PyObject *callargs, PyObject
50015001
PyObject *result;
50025002

50035003
if (PyCFunction_Check(func)) {
5004-
C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
5004+
C_TRACE(result, PyObject_Call(func, callargs, kwdict));
50055005
return result;
50065006
}
50075007
else if (Py_TYPE(func) == &PyMethodDescr_Type) {

Tools/gdb/libpython.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ def is_other_python_frame(self):
15641564
return False
15651565

15661566
if (caller.startswith('cfunction_vectorcall_') or
1567-
caller == 'cfunction_call_varargs'):
1567+
caller == 'cfunction_call'):
15681568
arg_name = 'func'
15691569
# Within that frame:
15701570
# "func" is the local containing the PyObject* of the

0 commit comments

Comments
 (0)