From a8b27e623d75377aabe50df27e97cab4e81a174a Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 24 Jun 2019 12:41:05 +0200 Subject: [PATCH] bpo-36974: inherit tp_vectorcall_offset unconditionally (GH-13858) --- Lib/test/test_call.py | 9 +++++++++ .../2019-06-06-11-00-55.bpo-36974.wdzzym.rst | 2 ++ Objects/call.c | 2 +- Objects/typeobject.c | 12 ++++++------ 4 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-06-06-11-00-55.bpo-36974.wdzzym.rst diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index b4ab74903ed..b252ca1076a 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -577,9 +577,18 @@ class TestPEP590(unittest.TestCase): def __call__(self, n): return 'new' + class SuperBase: + def __call__(self, *args): + return super().__call__(*args) + + class MethodDescriptorSuper(SuperBase, _testcapi.MethodDescriptorBase): + def __call__(self, *args): + return super().__call__(*args) + calls += [ (MethodDescriptorHeap(), (0,), {}, True), (MethodDescriptorOverridden(), (0,), {}, 'new'), + (MethodDescriptorSuper(), (0,), {}, True), ] for (func, args, kwargs, expected) in calls: diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-06-06-11-00-55.bpo-36974.wdzzym.rst b/Misc/NEWS.d/next/Core and Builtins/2019-06-06-11-00-55.bpo-36974.wdzzym.rst new file mode 100644 index 00000000000..035cdd3d6a9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-06-06-11-00-55.bpo-36974.wdzzym.rst @@ -0,0 +1,2 @@ +The slot ``tp_vectorcall_offset`` is inherited unconditionally to support +``super().__call__()`` when the base class uses vectorcall. diff --git a/Objects/call.c b/Objects/call.c index 8a1ce7f55fe..bde5513fb4d 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -184,7 +184,7 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) /* get vectorcallfunc as in _PyVectorcall_Function, but without * the _Py_TPFLAGS_HAVE_VECTORCALL check */ Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset; - if ((offset <= 0) || (!Py_TYPE(callable)->tp_call)) { + if (offset <= 0) { PyErr_Format(PyExc_TypeError, "'%.200s' object does not support vectorcall", Py_TYPE(callable)->tp_name); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e4952511e33..f8143337840 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5153,15 +5153,15 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) COPYSLOT(tp_repr); /* tp_hash see tp_richcompare */ { - /* Inherit tp_vectorcall_offset only if tp_call is not overridden */ - if (!type->tp_call) { - COPYSLOT(tp_vectorcall_offset); - } - /* Inherit_Py_TPFLAGS_HAVE_VECTORCALL for non-heap types + /* Always inherit tp_vectorcall_offset to support PyVectorcall_Call(). + * If _Py_TPFLAGS_HAVE_VECTORCALL is not inherited, then vectorcall + * won't be used automatically. */ + COPYSLOT(tp_vectorcall_offset); + + /* Inherit _Py_TPFLAGS_HAVE_VECTORCALL for non-heap types * if tp_call is not overridden */ if (!type->tp_call && (base->tp_flags & _Py_TPFLAGS_HAVE_VECTORCALL) && - !(type->tp_flags & _Py_TPFLAGS_HAVE_VECTORCALL) && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { type->tp_flags |= _Py_TPFLAGS_HAVE_VECTORCALL;