From 1f777396f52a4cf7417f56097f10add8042295f4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 7 Nov 2024 23:40:03 +0200 Subject: [PATCH] gh-122943: Rework support of var-positional parameter in Argument Clinic (GH-122945) Move creation of a tuple for var-positional parameter out of _PyArg_UnpackKeywordsWithVararg(). Merge _PyArg_UnpackKeywordsWithVararg() with _PyArg_UnpackKeywords(). Add a new parameter in _PyArg_UnpackKeywords(). The "parameters" and "converters" attributes of ParseArgsCodeGen no longer contain the var-positional parameter. It is now available as the "varpos" attribute. Optimize code generation for var-positional parameter and reuse the same generating code for functions with and without keyword parameters. Add special converters for var-positional parameter. "tuple" represents it as a Python tuple and "array" represents it as a continuous array of PyObject*. "object" is a temporary alias of "tuple". --- Include/internal/pycore_modsupport.h | 23 +- Include/internal/pycore_tuple.h | 2 +- Lib/test/clinic.test.c | 206 ++++- Lib/test/test_clinic.py | 101 ++- Modules/_testclinic.c | 332 +++++++- Modules/clinic/_testclinic.c.h | 776 ++++++++++++++++--- Modules/clinic/_testclinic_depr.c.h | 3 +- Modules/clinic/gcmodule.c.h | 33 +- Modules/clinic/mathmodule.c.h | 50 +- Modules/gcmodule.c | 39 +- Modules/mathmodule.c | 43 +- Objects/clinic/setobject.c.h | 103 +-- Objects/clinic/typevarobject.c.h | 35 +- Objects/setobject.c | 74 +- Python/clinic/bltinmodule.c.h | 31 +- Python/getargs.c | 168 +--- Tools/c-analyzer/c_parser/parser/__init__.py | 2 +- Tools/clinic/libclinic/clanguage.py | 16 +- Tools/clinic/libclinic/converter.py | 2 +- Tools/clinic/libclinic/converters.py | 27 + Tools/clinic/libclinic/dsl_parser.py | 9 +- Tools/clinic/libclinic/parse_args.py | 184 +++-- 22 files changed, 1597 insertions(+), 662 deletions(-) diff --git a/Include/internal/pycore_modsupport.h b/Include/internal/pycore_modsupport.h index 11fde814875..250106ad83a 100644 --- a/Include/internal/pycore_modsupport.h +++ b/Include/internal/pycore_modsupport.h @@ -76,7 +76,7 @@ PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords( ...); // Export for 'math' shared extension -PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords( +PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsEx( PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, @@ -85,20 +85,19 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords( int minpos, int maxpos, int minkw, + int varpos, PyObject **buf); #define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \ (((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \ - (minpos) <= (nargs) && (nargs) <= (maxpos) && (args) != NULL) ? (args) : \ - _PyArg_UnpackKeywords((args), (nargs), (kwargs), (kwnames), (parser), \ - (minpos), (maxpos), (minkw), (buf))) - -// Export for '_testclinic' shared extension -PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsWithVararg( - PyObject *const *args, Py_ssize_t nargs, - PyObject *kwargs, PyObject *kwnames, - struct _PyArg_Parser *parser, - int minpos, int maxpos, int minkw, - int vararg, PyObject **buf); + (minpos) <= (nargs) && (nargs) <= (maxpos) && (args) != NULL) ? \ + (args) : \ + _PyArg_UnpackKeywordsEx((args), (nargs), (kwargs), (kwnames), (parser), \ + (minpos), (maxpos), (minkw), 0, (buf))) +#define _PyArg_UnpackKeywordsWithVararg(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \ + (((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \ + (minpos) <= (nargs) && (args) != NULL) ? (args) : \ + _PyArg_UnpackKeywordsEx((args), (nargs), (kwargs), (kwnames), (parser), \ + (minpos), (maxpos), (minkw), 1, (buf))) #ifdef __cplusplus } diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h index dfbbd6fd0c7..82b875241f4 100644 --- a/Include/internal/pycore_tuple.h +++ b/Include/internal/pycore_tuple.h @@ -20,7 +20,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *); #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) -extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t); +PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index e22324efc49..80208862f2a 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4144,6 +4144,45 @@ PyDoc_STRVAR(test_vararg_and_posonly__doc__, "--\n" "\n"); +#define TEST_VARARG_AND_POSONLY_METHODDEF \ + {"test_vararg_and_posonly", _PyCFunction_CAST(test_vararg_and_posonly), METH_FASTCALL, test_vararg_and_posonly__doc__}, + +static PyObject * +test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args); + +static PyObject * +test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *__clinic_args = NULL; + + if (!_PyArg_CheckPositional("test_vararg_and_posonly", nargs, 1, PY_SSIZE_T_MAX)) { + goto exit; + } + a = args[0]; + __clinic_args = _PyTuple_FromArray(args + 1, nargs - 1); + if (__clinic_args == NULL) { + goto exit; + } + return_value = test_vararg_and_posonly_impl(module, a, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static PyObject * +test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args) +/*[clinic end generated code: output=0c11c475e240869e input=9cfa748bbff09877]*/ + +PyDoc_STRVAR(test_vararg_and_posonly__doc__, +"test_vararg_and_posonly($module, a, /, *args)\n" +"--\n" +"\n"); + #define TEST_VARARG_AND_POSONLY_METHODDEF \ {"test_vararg_and_posonly", _PyCFunction_CAST(test_vararg_and_posonly), METH_FASTCALL, test_vararg_and_posonly__doc__}, @@ -4163,17 +4202,19 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg goto exit; } a = args[0]; - __clinic_args = args + 1; + __clinic_args = _PyTuple_FromArray(args + 1, nargs - 1); + if (__clinic_args == NULL) { + goto exit; + } return_value = test_vararg_and_posonly_impl(module, a, nvararg, __clinic_args); exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + return return_value; } -static PyObject * -test_vararg_and_posonly_impl(PyObject *module, PyObject *a, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=dc2dd9483cc0459e input=9cfa748bbff09877]*/ /*[clinic input] test_vararg @@ -4224,26 +4265,34 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; + PyObject *argsbuf[1]; + PyObject * const *fastargs; PyObject *a; PyObject *__clinic_args = NULL; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + __clinic_args = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (__clinic_args == NULL) { goto exit; } - a = args[0]; - __clinic_args = args[1]; return_value = test_vararg_impl(module, a, __clinic_args); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } static PyObject * test_vararg_impl(PyObject *module, PyObject *a, PyObject *args) -/*[clinic end generated code: output=1411e464f358a7ba input=81d33815ad1bae6e]*/ +/*[clinic end generated code: output=e7d7da6a7e008125 input=81d33815ad1bae6e]*/ /*[clinic input] test_vararg_with_default @@ -4296,37 +4345,45 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *a; PyObject *__clinic_args = NULL; int b = 0; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { goto exit; } - a = args[0]; - __clinic_args = args[1]; + a = fastargs[0]; if (!noptargs) { goto skip_optional_kwonly; } - b = PyObject_IsTrue(args[2]); + b = PyObject_IsTrue(fastargs[1]); if (b < 0) { goto exit; } skip_optional_kwonly: + __clinic_args = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (__clinic_args == NULL) { + goto exit; + } return_value = test_vararg_with_default_impl(module, a, __clinic_args, b); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } static PyObject * test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args, int b) -/*[clinic end generated code: output=f09d4b917063ca41 input=6e110b54acd9b22d]*/ +/*[clinic end generated code: output=46781f9920ecedcf input=6e110b54acd9b22d]*/ /*[clinic input] test_vararg_with_only_defaults @@ -4379,22 +4436,22 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *__clinic_args = NULL; int b = 0; PyObject *c = " "; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!fastargs) { goto exit; } - __clinic_args = args[0]; if (!noptargs) { goto skip_optional_kwonly; } - if (args[1]) { - b = PyObject_IsTrue(args[1]); + if (fastargs[0]) { + b = PyObject_IsTrue(fastargs[0]); if (b < 0) { goto exit; } @@ -4402,19 +4459,25 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize goto skip_optional_kwonly; } } - c = args[2]; + c = fastargs[1]; skip_optional_kwonly: + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } return_value = test_vararg_with_only_defaults_impl(module, __clinic_args, b, c); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } static PyObject * test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b, PyObject *c) -/*[clinic end generated code: output=cc6590b8805d5433 input=fa56a709a035666e]*/ +/*[clinic end generated code: output=d03daf5067039c03 input=fa56a709a035666e]*/ /*[clinic input] test_paramname_module @@ -4926,6 +4989,41 @@ PyDoc_STRVAR(Test___init____doc__, "\n" "Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE."); +static int +Test___init___impl(TestObj *self, PyObject *args); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyTypeObject *base_tp = TestType; + PyObject *__clinic_args = NULL; + + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + __clinic_args = Py_NewRef(args); + return_value = Test___init___impl((TestObj *)self, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static int +Test___init___impl(TestObj *self, PyObject *args) +/*[clinic end generated code: output=f172425cec373cd6 input=2a8bd0033c9ac772]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test(*args)\n" +"--\n" +"\n" +"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE."); + static int Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args); @@ -4941,19 +5039,16 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) !_PyArg_NoKeywords("Test", kwargs)) { goto exit; } - if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = _PyTuple_CAST(args)->ob_item; + __clinic_args = Py_NewRef(args); return_value = Test___init___impl((TestObj *)self, nvararg, __clinic_args); exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + return return_value; } -static int -Test___init___impl(TestObj *self, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=6a64b417c9080a73 input=2a8bd0033c9ac772]*/ /*[clinic input] @@ -4970,6 +5065,40 @@ PyDoc_STRVAR(Test__doc__, "\n" "Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE."); +static PyObject * +Test_impl(PyTypeObject *type, PyObject *args); + +static PyObject * +Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = TestType; + PyObject *__clinic_args = NULL; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + __clinic_args = Py_NewRef(args); + return_value = Test_impl(type, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static PyObject * +Test_impl(PyTypeObject *type, PyObject *args) +/*[clinic end generated code: output=ee1e8892a67abd4a input=70ad829df3dd9b84]*/ + +PyDoc_STRVAR(Test__doc__, +"Test(*args)\n" +"--\n" +"\n" +"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE."); + static PyObject * Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args); @@ -4984,19 +5113,16 @@ Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) !_PyArg_NoKeywords("Test", kwargs)) { goto exit; } - if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = _PyTuple_CAST(args)->ob_item; + __clinic_args = Py_NewRef(args); return_value = Test_impl(type, nvararg, __clinic_args); exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + return return_value; } -static PyObject * -Test_impl(PyTypeObject *type, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=bf22f942407383a5 input=70ad829df3dd9b84]*/ /*[clinic input] diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index d492ea1d76a..a4317a3ad46 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -33,6 +33,15 @@ with test_tools.imports_under_tool('clinic'): from libclinic.cli import parse_file, Clinic +def repeat_fn(*functions): + def wrapper(test): + def wrapped(self): + for fn in functions: + with self.subTest(fn=fn): + test(self, fn) + return wrapped + return wrapper + def _make_clinic(*, filename='clinic_tests', limited_capi=False): clang = CLanguage(filename) c = Clinic(clang, filename=filename, limited_capi=limited_capi) @@ -3378,30 +3387,53 @@ class ClinicFunctionalTest(unittest.TestCase): ac_tester.keyword_only_parameter(1) self.assertEqual(ac_tester.keyword_only_parameter(a=1), (1,)) - def test_varpos(self): - # fn(*args) - fn = ac_tester.varpos - self.assertEqual(fn(), ((),)) - self.assertEqual(fn(1, 2), ((1, 2),)) + if ac_tester is not None: + @repeat_fn(ac_tester.varpos, + ac_tester.varpos_array, + ac_tester.TestClass.varpos_no_fastcall, + ac_tester.TestClass.varpos_array_no_fastcall) + def test_varpos(self, fn): + # fn(*args) + self.assertEqual(fn(), ()) + self.assertEqual(fn(1, 2), (1, 2)) - def test_posonly_varpos(self): - # fn(a, b, /, *args) - fn = ac_tester.posonly_varpos - self.assertRaises(TypeError, fn) - self.assertRaises(TypeError, fn, 1) - self.assertRaises(TypeError, fn, 1, b=2) - self.assertEqual(fn(1, 2), (1, 2, ())) - self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) + @repeat_fn(ac_tester.posonly_varpos, + ac_tester.posonly_varpos_array, + ac_tester.TestClass.posonly_varpos_no_fastcall, + ac_tester.TestClass.posonly_varpos_array_no_fastcall) + def test_posonly_varpos(self, fn): + # fn(a, b, /, *args) + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, 1) + self.assertRaises(TypeError, fn, 1, b=2) + self.assertEqual(fn(1, 2), (1, 2, ())) + self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) - def test_posonly_poskw_varpos(self): - # fn(a, /, b, *args) - fn = ac_tester.posonly_poskw_varpos - self.assertRaises(TypeError, fn) - self.assertEqual(fn(1, 2), (1, 2, ())) - self.assertEqual(fn(1, b=2), (1, 2, ())) - self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) - self.assertRaises(TypeError, fn, b=4) - self.assertRaises(TypeError, fn, 1, 2, 3, b=4) + @repeat_fn(ac_tester.posonly_req_opt_varpos, + ac_tester.posonly_req_opt_varpos_array, + ac_tester.TestClass.posonly_req_opt_varpos_no_fastcall, + ac_tester.TestClass.posonly_req_opt_varpos_array_no_fastcall) + def test_posonly_req_opt_varpos(self, fn): + # fn(a, b=False, /, *args) + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, a=1) + self.assertEqual(fn(1), (1, False, ())) + self.assertEqual(fn(1, 2), (1, 2, ())) + self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) + + @repeat_fn(ac_tester.posonly_poskw_varpos, + ac_tester.posonly_poskw_varpos_array, + ac_tester.TestClass.posonly_poskw_varpos_no_fastcall, + ac_tester.TestClass.posonly_poskw_varpos_array_no_fastcall) + def test_posonly_poskw_varpos(self, fn): + # fn(a, /, b, *args) + self.assertRaises(TypeError, fn) + self.assertEqual(fn(1, 2), (1, 2, ())) + self.assertEqual(fn(1, b=2), (1, 2, ())) + self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4))) + self.assertRaises(TypeError, fn, b=4) + errmsg = re.escape("given by name ('b') and position (2)") + self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, b=4) def test_poskw_varpos(self): # fn(a, *args) @@ -3409,7 +3441,8 @@ class ClinicFunctionalTest(unittest.TestCase): self.assertRaises(TypeError, fn) self.assertRaises(TypeError, fn, 1, b=2) self.assertEqual(fn(a=1), (1, ())) - self.assertRaises(TypeError, fn, 1, a=2) + errmsg = re.escape("given by name ('a') and position (1)") + self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2) self.assertEqual(fn(1), (1, ())) self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4))) @@ -3417,7 +3450,8 @@ class ClinicFunctionalTest(unittest.TestCase): # fn(a, *args, b=False) fn = ac_tester.poskw_varpos_kwonly_opt self.assertRaises(TypeError, fn) - self.assertRaises(TypeError, fn, 1, a=2) + errmsg = re.escape("given by name ('a') and position (1)") + self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2) self.assertEqual(fn(1, b=2), (1, (), True)) self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False)) self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True)) @@ -3428,7 +3462,8 @@ class ClinicFunctionalTest(unittest.TestCase): # fn(a, *args, b=False, c=False) fn = ac_tester.poskw_varpos_kwonly_opt2 self.assertRaises(TypeError, fn) - self.assertRaises(TypeError, fn, 1, a=2) + errmsg = re.escape("given by name ('a') and position (1)") + self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2) self.assertEqual(fn(1, b=2), (1, (), 2, False)) self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3)) self.assertEqual(fn(1, 2, 3), (1, (2, 3), False, False)) @@ -3490,9 +3525,10 @@ class ClinicFunctionalTest(unittest.TestCase): self.assertEqual(fn(covariant=True, name='a'), ('a', (), True)) self.assertRaises(TypeError, fn, covariant=True) - self.assertRaises(TypeError, fn, 1, name='a') - self.assertRaises(TypeError, fn, 1, 2, 3, name='a', covariant=True) - self.assertRaises(TypeError, fn, 1, 2, 3, covariant=True, name='a') + errmsg = re.escape("given by name ('name') and position (1)") + self.assertRaisesRegex(TypeError, errmsg, fn, 1, name='a') + self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, name='a', covariant=True) + self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, covariant=True, name='a') def test_cloned_func_exception_message(self): incorrect_arg = -1 # f1() and f2() accept a single str @@ -3568,14 +3604,15 @@ class ClinicFunctionalTest(unittest.TestCase): cls = ac_tester.TestClass obj = cls() fn = obj.defclass_posonly_varpos - self.assertRaises(TypeError, fn) - self.assertRaises(TypeError, fn, 1) + errmsg = 'takes at least 2 positional arguments' + self.assertRaisesRegex(TypeError, errmsg, fn) + self.assertRaisesRegex(TypeError, errmsg, fn, 1) self.assertEqual(fn(1, 2), (cls, 1, 2, ())) self.assertEqual(fn(1, 2, 3, 4), (cls, 1, 2, (3, 4))) fn = cls.defclass_posonly_varpos self.assertRaises(TypeError, fn) - self.assertRaises(TypeError, fn, obj) - self.assertRaises(TypeError, fn, obj, 1) + self.assertRaisesRegex(TypeError, errmsg, fn, obj) + self.assertRaisesRegex(TypeError, errmsg, fn, obj, 1) self.assertEqual(fn(obj, 1, 2), (cls, 1, 2, ())) self.assertEqual(fn(obj, 1, 2, 3, 4), (cls, 1, 2, (3, 4))) diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index e3c8ba9b0b5..320c8ddf214 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -59,19 +59,20 @@ pack_arguments_newref(int argc, ...) } static PyObject * -pack_varargs_to_tuple(Py_ssize_t varargssize, PyObject *const *args) +pack_arguments_2pos_varpos(PyObject *a, PyObject *b, + PyObject * const *args, Py_ssize_t args_length) +/*[clinic end generated code: output=267032f41bd039cc input=86ee3064b7853e86]*/ { - assert(!PyErr_Occurred()); - PyObject *tuple = PyTuple_New(varargssize); - if (!tuple) { + PyObject *tuple = _PyTuple_FromArray(args, args_length); + if (tuple == NULL) { return NULL; } - for (Py_ssize_t i = 0; i < varargssize; i++) { - PyTuple_SET_ITEM(tuple, i, Py_NewRef(args[i])); - } - return tuple; + PyObject *result = pack_arguments_newref(3, a, b, tuple); + Py_DECREF(tuple); + return result; } + /* Pack arguments to a tuple. * `wrapper` is function which converts primitive type to PyObject. * `arg_type` is type that arguments should be converted to before wrapped. */ @@ -984,16 +985,10 @@ varpos [clinic start generated code]*/ static PyObject * -varpos_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=b65096f423fb5dcc input=f87cd674145d394c]*/ +varpos_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=7b0b9545872bdca4 input=f87cd674145d394c]*/ { - PyObject *vararg_tuple = pack_varargs_to_tuple(nargs, args); - if (!vararg_tuple) { - return NULL; - } - PyObject *result = pack_arguments_newref(1, vararg_tuple); - Py_DECREF(vararg_tuple); - return result; + return Py_NewRef(args); } @@ -1009,16 +1004,29 @@ posonly_varpos static PyObject * posonly_varpos_impl(PyObject *module, PyObject *a, PyObject *b, - Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=d10d43d86d117ab3 input=c9fd7895cfbaabba]*/ + PyObject *args) +/*[clinic end generated code: output=5dae5eb2a0d623cd input=c9fd7895cfbaabba]*/ { - PyObject *vararg_tuple = pack_varargs_to_tuple(nargs, args); - if (!vararg_tuple) { - return NULL; - } - PyObject *result = pack_arguments_newref(3, a, b, vararg_tuple); - Py_DECREF(vararg_tuple); - return result; + return pack_arguments_newref(3, a, b, args); +} + + +/*[clinic input] +posonly_req_opt_varpos + + a: object + b: object = False + / + *args: object + +[clinic start generated code]*/ + +static PyObject * +posonly_req_opt_varpos_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject *args) +/*[clinic end generated code: output=67f82f90838e166a input=a49bd64740171e1c]*/ +{ + return pack_arguments_newref(3, a, b, args); } @@ -1130,6 +1138,81 @@ varpos_kwonly_req_opt_impl(PyObject *module, PyObject *args, PyObject *a, } +/*[clinic input] +varpos_array + + *args: array + +[clinic start generated code]*/ + +static PyObject * +varpos_array_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=a25f42f39c9b13ad input=97b8bdcf87e019c7]*/ +{ + return _PyTuple_FromArray(args, args_length); +} + + +/*[clinic input] +posonly_varpos_array + + a: object + b: object + / + *args: array + +[clinic start generated code]*/ + +static PyObject * +posonly_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject * const *args, Py_ssize_t args_length) +/*[clinic end generated code: output=267032f41bd039cc input=86ee3064b7853e86]*/ +{ + return pack_arguments_2pos_varpos(a, b, args, args_length); +} + + +/*[clinic input] +posonly_req_opt_varpos_array + + a: object + b: object = False + / + *args: array + +[clinic start generated code]*/ + +static PyObject * +posonly_req_opt_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=f2f93c77ead93699 input=b01d7728164fd93e]*/ +{ + return pack_arguments_2pos_varpos(a, b, args, args_length); +} + + +/*[clinic input] +posonly_poskw_varpos_array + + a: object + / + b: object + *args: array + +[clinic start generated code]*/ + +static PyObject * +posonly_poskw_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=155811a8b2d65a12 input=5fb08cdc6afb9d7c]*/ +{ + return pack_arguments_2pos_varpos(a, b, args, args_length); +} + + /*[clinic input] gh_32092_oob @@ -1183,9 +1266,8 @@ Proof-of-concept of GH-99233 refcount error bug. [clinic start generated code]*/ static PyObject * -gh_99233_refcount_impl(PyObject *module, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=b570007e61e5c670 input=eecfdc2092d90dc3]*/ +gh_99233_refcount_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=585855abfbca9a7f input=eecfdc2092d90dc3]*/ { Py_RETURN_NONE; } @@ -1295,9 +1377,9 @@ clone_with_conv_f2_impl(PyObject *module, custom_t path) /*[clinic input] -class _testclinic.TestClass "PyObject *" "PyObject" +class _testclinic.TestClass "PyObject *" "&PyBaseObject_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=668a591c65bec947]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c991635bb3c91f1a]*/ /*[clinic input] _testclinic.TestClass.get_defining_class @@ -1360,11 +1442,192 @@ _testclinic_TestClass_defclass_posonly_varpos_impl(PyObject *self, return pack_arguments_newref(4, cls, a, b, args); } + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as varpos_no_fastcall + + *args: object + +[clinic start generated code]*/ + +static PyObject * +varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args) +/*[clinic end generated code: output=04e94f2898bb2dde input=b0447ebab3e81001]*/ +{ + return Py_NewRef(args); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as posonly_varpos_no_fastcall + + a: object + b: object + / + *args: object + +[clinic start generated code]*/ + +static PyObject * +posonly_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, PyObject *b, + PyObject *args) +/*[clinic end generated code: output=b0a0425719f69f5a input=d2ec37a06b3c2389]*/ +{ + return pack_arguments_newref(3, a, b, args); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as posonly_req_opt_varpos_no_fastcall + + a: object + b: object = False + / + *args: object + +[clinic start generated code]*/ + +static PyObject * +posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, PyObject *args) +/*[clinic end generated code: output=3c44915b1a554e2d input=e9e74686a5e6a06d]*/ +{ + return pack_arguments_newref(3, a, b, args); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as posonly_poskw_varpos_no_fastcall + + a: object + / + b: object + *args: object + +[clinic start generated code]*/ + +static PyObject * +posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, PyObject *args) +/*[clinic end generated code: output=6ad74bed4bdc7f96 input=fa931c38184213aa]*/ +{ + return pack_arguments_newref(3, a, b, args); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as varpos_array_no_fastcall + + *args: array + +[clinic start generated code]*/ + +static PyObject * +varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=f99d984346c60d42 input=368d8eea6de48c12]*/ +{ + return _PyTuple_FromArray(args, args_length); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as posonly_varpos_array_no_fastcall + + a: object + b: object + / + *args: array + +[clinic start generated code]*/ + +static PyObject * +posonly_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=1eec4da1fb5b5978 input=7330c8d819a23548]*/ +{ + return pack_arguments_2pos_varpos(a, b, args, args_length); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as posonly_req_opt_varpos_array_no_fastcall + + a: object + b: object = False + / + *args: array + +[clinic start generated code]*/ + +static PyObject * +posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type, + PyObject *a, PyObject *b, + PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=88041c2176135218 input=7f5fd34ee5f9e0bf]*/ +{ + return pack_arguments_2pos_varpos(a, b, args, args_length); +} + + +/*[clinic input] +@classmethod +_testclinic.TestClass.__new__ as posonly_poskw_varpos_array_no_fastcall + + a: object + / + b: object + *args: array + +[clinic start generated code]*/ + +static PyObject * +posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, + PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=70eda18c3667681e input=2b0fcd7bd9bb865c]*/ +{ + return pack_arguments_2pos_varpos(a, b, args, args_length); +} + static struct PyMethodDef test_class_methods[] = { _TESTCLINIC_TESTCLASS_GET_DEFINING_CLASS_METHODDEF _TESTCLINIC_TESTCLASS_GET_DEFINING_CLASS_ARG_METHODDEF _TESTCLINIC_TESTCLASS_DEFCLASS_VARPOS_METHODDEF _TESTCLINIC_TESTCLASS_DEFCLASS_POSONLY_VARPOS_METHODDEF + + {"varpos_no_fastcall", _PyCFunction_CAST(varpos_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {"posonly_varpos_no_fastcall", _PyCFunction_CAST(posonly_varpos_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {"posonly_req_opt_varpos_no_fastcall", _PyCFunction_CAST(posonly_req_opt_varpos_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {"posonly_poskw_varpos_no_fastcall", _PyCFunction_CAST(posonly_poskw_varpos_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + + {"varpos_array_no_fastcall", + _PyCFunction_CAST(varpos_array_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {"posonly_varpos_array_no_fastcall", + _PyCFunction_CAST(posonly_varpos_array_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {"posonly_req_opt_varpos_array_no_fastcall", + _PyCFunction_CAST(posonly_req_opt_varpos_array_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {"posonly_poskw_varpos_array_no_fastcall", + _PyCFunction_CAST(posonly_poskw_varpos_array_no_fastcall), + METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""}, + {NULL, NULL} }; @@ -2023,12 +2286,19 @@ static PyMethodDef tester_methods[] = { VARPOS_METHODDEF POSONLY_VARPOS_METHODDEF + POSONLY_REQ_OPT_VARPOS_METHODDEF POSONLY_POSKW_VARPOS_METHODDEF POSKW_VARPOS_METHODDEF POSKW_VARPOS_KWONLY_OPT_METHODDEF POSKW_VARPOS_KWONLY_OPT2_METHODDEF VARPOS_KWONLY_OPT_METHODDEF VARPOS_KWONLY_REQ_OPT_METHODDEF + + VARPOS_ARRAY_METHODDEF + POSONLY_VARPOS_ARRAY_METHODDEF + POSONLY_REQ_OPT_VARPOS_ARRAY_METHODDEF + POSONLY_POSKW_VARPOS_ARRAY_METHODDEF + GH_32092_OOB_METHODDEF GH_32092_KW_PASS_METHODDEF GH_99233_REFCOUNT_METHODDEF diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 7e29998c7db..0f5ae5ec869 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -9,6 +9,7 @@ preserve #include "pycore_long.h" // _PyLong_UnsignedShort_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_runtime.h" // _Py_ID() +#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(test_empty_function__doc__, "test_empty_function($module, /)\n" @@ -2530,22 +2531,24 @@ PyDoc_STRVAR(varpos__doc__, {"varpos", _PyCFunction_CAST(varpos), METH_FASTCALL, varpos__doc__}, static PyObject * -varpos_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); +varpos_impl(PyObject *module, PyObject *args); static PyObject * varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject *__clinic_args = NULL; - if (!_PyArg_CheckPositional("varpos", nargs, 0, PY_SSIZE_T_MAX)) { + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { goto exit; } - __clinic_args = args + 0; - return_value = varpos_impl(module, nvararg, __clinic_args); + return_value = varpos_impl(module, __clinic_args); exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + return return_value; } @@ -2559,26 +2562,75 @@ PyDoc_STRVAR(posonly_varpos__doc__, static PyObject * posonly_varpos_impl(PyObject *module, PyObject *a, PyObject *b, - Py_ssize_t nargs, PyObject *const *args); + PyObject *args); static PyObject * posonly_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 2; PyObject *a; PyObject *b; - PyObject *const *__clinic_args = NULL; + PyObject *__clinic_args = NULL; if (!_PyArg_CheckPositional("posonly_varpos", nargs, 2, PY_SSIZE_T_MAX)) { goto exit; } a = args[0]; b = args[1]; - __clinic_args = args + 2; - return_value = posonly_varpos_impl(module, a, b, nvararg, __clinic_args); + __clinic_args = _PyTuple_FromArray(args + 2, nargs - 2); + if (__clinic_args == NULL) { + goto exit; + } + return_value = posonly_varpos_impl(module, a, b, __clinic_args); exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +PyDoc_STRVAR(posonly_req_opt_varpos__doc__, +"posonly_req_opt_varpos($module, a, b=False, /, *args)\n" +"--\n" +"\n"); + +#define POSONLY_REQ_OPT_VARPOS_METHODDEF \ + {"posonly_req_opt_varpos", _PyCFunction_CAST(posonly_req_opt_varpos), METH_FASTCALL, posonly_req_opt_varpos__doc__}, + +static PyObject * +posonly_req_opt_varpos_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject *args); + +static PyObject * +posonly_req_opt_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b = Py_False; + PyObject *__clinic_args = NULL; + + if (!_PyArg_CheckPositional("posonly_req_opt_varpos", nargs, 1, PY_SSIZE_T_MAX)) { + goto exit; + } + a = args[0]; + if (nargs < 2) { + goto skip_optional; + } + b = args[1]; +skip_optional: + __clinic_args = nargs > 2 + ? _PyTuple_FromArray(args + 2, nargs - 2) + : PyTuple_New(0); + if (__clinic_args == NULL) { + goto exit; + } + return_value = posonly_req_opt_varpos_impl(module, a, b, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + return return_value; } @@ -2623,22 +2675,30 @@ posonly_poskw_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs, .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; PyObject *a; PyObject *b; PyObject *__clinic_args = NULL; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, 2, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + b = fastargs[1]; + __clinic_args = nargs > 2 + ? _PyTuple_FromArray(args + 2, nargs - 2) + : PyTuple_New(0); + if (__clinic_args == NULL) { goto exit; } - a = args[0]; - b = args[1]; - __clinic_args = args[2]; return_value = posonly_poskw_varpos_impl(module, a, b, __clinic_args); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -2682,20 +2742,28 @@ poskw_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; + PyObject *argsbuf[1]; + PyObject * const *fastargs; PyObject *a; PyObject *__clinic_args = NULL; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + __clinic_args = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (__clinic_args == NULL) { goto exit; } - a = args[0]; - __clinic_args = args[1]; return_value = poskw_varpos_impl(module, a, __clinic_args); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -2740,30 +2808,38 @@ poskw_varpos_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t narg .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *a; PyObject *__clinic_args = NULL; int b = 0; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { goto exit; } - a = args[0]; - __clinic_args = args[1]; + a = fastargs[0]; if (!noptargs) { goto skip_optional_kwonly; } - b = PyObject_IsTrue(args[2]); + b = PyObject_IsTrue(fastargs[1]); if (b < 0) { goto exit; } skip_optional_kwonly: + __clinic_args = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (__clinic_args == NULL) { + goto exit; + } return_value = poskw_varpos_kwonly_opt_impl(module, a, __clinic_args, b); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -2808,34 +2884,42 @@ poskw_varpos_kwonly_opt2(PyObject *module, PyObject *const *args, Py_ssize_t nar .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[3]; + PyObject * const *fastargs; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *a; PyObject *__clinic_args = NULL; PyObject *b = Py_False; PyObject *c = Py_False; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { goto exit; } - a = args[0]; - __clinic_args = args[1]; + a = fastargs[0]; if (!noptargs) { goto skip_optional_kwonly; } - if (args[2]) { - b = args[2]; + if (fastargs[1]) { + b = fastargs[1]; if (!--noptargs) { goto skip_optional_kwonly; } } - c = args[3]; + c = fastargs[2]; skip_optional_kwonly: + __clinic_args = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (__clinic_args == NULL) { + goto exit; + } return_value = poskw_varpos_kwonly_opt2_impl(module, a, __clinic_args, b, c); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -2879,25 +2963,31 @@ varpos_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; + PyObject *argsbuf[1]; + PyObject * const *fastargs; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *__clinic_args = NULL; PyObject *b = Py_False; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!fastargs) { goto exit; } - __clinic_args = args[0]; if (!noptargs) { goto skip_optional_kwonly; } - b = args[1]; + b = fastargs[0]; skip_optional_kwonly: + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } return_value = varpos_kwonly_opt_impl(module, __clinic_args, b); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -2942,34 +3032,202 @@ varpos_kwonly_req_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[3]; + PyObject * const *fastargs; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *__clinic_args = NULL; PyObject *a; PyObject *b = Py_False; PyObject *c = Py_False; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 1, 0, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 1, argsbuf); + if (!fastargs) { goto exit; } - __clinic_args = args[0]; - a = args[1]; + a = fastargs[0]; if (!noptargs) { goto skip_optional_kwonly; } - if (args[2]) { - b = args[2]; + if (fastargs[1]) { + b = fastargs[1]; if (!--noptargs) { goto skip_optional_kwonly; } } - c = args[3]; + c = fastargs[2]; skip_optional_kwonly: + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } return_value = varpos_kwonly_req_opt_impl(module, __clinic_args, a, b, c); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + + return return_value; +} + +PyDoc_STRVAR(varpos_array__doc__, +"varpos_array($module, /, *args)\n" +"--\n" +"\n"); + +#define VARPOS_ARRAY_METHODDEF \ + {"varpos_array", _PyCFunction_CAST(varpos_array), METH_FASTCALL, varpos_array__doc__}, + +static PyObject * +varpos_array_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +varpos_array(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + __clinic_args = args; + args_length = nargs; + return_value = varpos_array_impl(module, __clinic_args, args_length); + + return return_value; +} + +PyDoc_STRVAR(posonly_varpos_array__doc__, +"posonly_varpos_array($module, a, b, /, *args)\n" +"--\n" +"\n"); + +#define POSONLY_VARPOS_ARRAY_METHODDEF \ + {"posonly_varpos_array", _PyCFunction_CAST(posonly_varpos_array), METH_FASTCALL, posonly_varpos_array__doc__}, + +static PyObject * +posonly_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject * const *args, Py_ssize_t args_length); + +static PyObject * +posonly_varpos_array(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + if (!_PyArg_CheckPositional("posonly_varpos_array", nargs, 2, PY_SSIZE_T_MAX)) { + goto exit; + } + a = args[0]; + b = args[1]; + __clinic_args = args + 2; + args_length = nargs - 2; + return_value = posonly_varpos_array_impl(module, a, b, __clinic_args, args_length); + +exit: + return return_value; +} + +PyDoc_STRVAR(posonly_req_opt_varpos_array__doc__, +"posonly_req_opt_varpos_array($module, a, b=False, /, *args)\n" +"--\n" +"\n"); + +#define POSONLY_REQ_OPT_VARPOS_ARRAY_METHODDEF \ + {"posonly_req_opt_varpos_array", _PyCFunction_CAST(posonly_req_opt_varpos_array), METH_FASTCALL, posonly_req_opt_varpos_array__doc__}, + +static PyObject * +posonly_req_opt_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +posonly_req_opt_varpos_array(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b = Py_False; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + if (!_PyArg_CheckPositional("posonly_req_opt_varpos_array", nargs, 1, PY_SSIZE_T_MAX)) { + goto exit; + } + a = args[0]; + if (nargs < 2) { + goto skip_optional; + } + b = args[1]; +skip_optional: + __clinic_args = nargs > 2 ? args + 2 : args; + args_length = Py_MAX(0, nargs - 2); + return_value = posonly_req_opt_varpos_array_impl(module, a, b, __clinic_args, args_length); + +exit: + return return_value; +} + +PyDoc_STRVAR(posonly_poskw_varpos_array__doc__, +"posonly_poskw_varpos_array($module, a, /, b, *args)\n" +"--\n" +"\n"); + +#define POSONLY_POSKW_VARPOS_ARRAY_METHODDEF \ + {"posonly_poskw_varpos_array", _PyCFunction_CAST(posonly_poskw_varpos_array), METH_FASTCALL|METH_KEYWORDS, posonly_poskw_varpos_array__doc__}, + +static PyObject * +posonly_poskw_varpos_array_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +posonly_poskw_varpos_array(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { _Py_LATIN1_CHR('b'), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "b", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "posonly_poskw_varpos_array", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject * const *fastargs; + PyObject *a; + PyObject *b; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + b = fastargs[1]; + __clinic_args = nargs > 2 ? args + 2 : args; + args_length = Py_MAX(0, nargs - 2); + return_value = posonly_poskw_varpos_array_impl(module, a, b, __clinic_args, args_length); + +exit: return return_value; } @@ -3015,7 +3273,8 @@ gh_32092_oob(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[5]; + PyObject *argsbuf[4]; + PyObject * const *fastargs; Py_ssize_t noptargs = Py_MIN(nargs, 2) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; PyObject *pos1; PyObject *pos2; @@ -3023,28 +3282,35 @@ gh_32092_oob(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject PyObject *kw1 = Py_None; PyObject *kw2 = Py_None; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, 2, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { goto exit; } - pos1 = args[0]; - pos2 = args[1]; - varargs = args[2]; + pos1 = fastargs[0]; + pos2 = fastargs[1]; if (!noptargs) { goto skip_optional_kwonly; } - if (args[3]) { - kw1 = args[3]; + if (fastargs[2]) { + kw1 = fastargs[2]; if (!--noptargs) { goto skip_optional_kwonly; } } - kw2 = args[4]; + kw2 = fastargs[3]; skip_optional_kwonly: + varargs = nargs > 2 + ? _PyTuple_FromArray(args + 2, nargs - 2) + : PyTuple_New(0); + if (varargs == NULL) { + goto exit; + } return_value = gh_32092_oob_impl(module, pos1, pos2, varargs, kw1, kw2); exit: + /* Cleanup for varargs */ Py_XDECREF(varargs); + return return_value; } @@ -3090,27 +3356,35 @@ gh_32092_kw_pass(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *pos; PyObject *__clinic_args = NULL; PyObject *kw = Py_None; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { goto exit; } - pos = args[0]; - __clinic_args = args[1]; + pos = fastargs[0]; if (!noptargs) { goto skip_optional_kwonly; } - kw = args[2]; + kw = fastargs[1]; skip_optional_kwonly: + __clinic_args = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (__clinic_args == NULL) { + goto exit; + } return_value = gh_32092_kw_pass_impl(module, pos, __clinic_args, kw); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -3124,23 +3398,24 @@ PyDoc_STRVAR(gh_99233_refcount__doc__, {"gh_99233_refcount", _PyCFunction_CAST(gh_99233_refcount), METH_FASTCALL, gh_99233_refcount__doc__}, static PyObject * -gh_99233_refcount_impl(PyObject *module, Py_ssize_t nargs, - PyObject *const *args); +gh_99233_refcount_impl(PyObject *module, PyObject *args); static PyObject * gh_99233_refcount(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject *__clinic_args = NULL; - if (!_PyArg_CheckPositional("gh_99233_refcount", nargs, 0, PY_SSIZE_T_MAX)) { + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { goto exit; } - __clinic_args = args + 0; - return_value = gh_99233_refcount_impl(module, nvararg, __clinic_args); + return_value = gh_99233_refcount_impl(module, __clinic_args); exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + return return_value; } @@ -3220,30 +3495,38 @@ null_or_tuple_for_varargs(PyObject *module, PyObject *const *args, Py_ssize_t na .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *name; PyObject *constraints = NULL; int covariant = 0; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { goto exit; } - name = args[0]; - constraints = args[1]; + name = fastargs[0]; if (!noptargs) { goto skip_optional_kwonly; } - covariant = PyObject_IsTrue(args[2]); + covariant = PyObject_IsTrue(fastargs[1]); if (covariant < 0) { goto exit; } skip_optional_kwonly: + constraints = nargs > 1 + ? _PyTuple_FromArray(args + 1, nargs - 1) + : PyTuple_New(0); + if (constraints == NULL) { + goto exit; + } return_value = null_or_tuple_for_varargs_impl(module, name, constraints, covariant); exit: + /* Cleanup for constraints */ Py_XDECREF(constraints); + return return_value; } @@ -3613,17 +3896,23 @@ _testclinic_TestClass_defclass_varpos(PyObject *self, PyTypeObject *cls, PyObjec }; #undef KWTUPLE PyObject *argsbuf[1]; + PyObject * const *fastargs; PyObject *__clinic_args = NULL; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!fastargs) { + goto exit; + } + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { goto exit; } - __clinic_args = args[0]; return_value = _testclinic_TestClass_defclass_varpos_impl(self, cls, __clinic_args); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -3658,22 +3947,335 @@ _testclinic_TestClass_defclass_posonly_varpos(PyObject *self, PyTypeObject *cls, .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[2]; + PyObject * const *fastargs; PyObject *a; PyObject *b; PyObject *__clinic_args = NULL; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, 2, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + b = fastargs[1]; + __clinic_args = _PyTuple_FromArray(args + 2, nargs - 2); + if (__clinic_args == NULL) { goto exit; } - a = args[0]; - b = args[1]; - __clinic_args = args[2]; return_value = _testclinic_TestClass_defclass_posonly_varpos_impl(self, cls, a, b, __clinic_args); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } -/*[clinic end generated code: output=7662d07e7d29cbeb input=a9049054013a1b77]*/ + +static PyObject * +varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args); + +static PyObject * +varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = &PyBaseObject_Type; + PyObject *__clinic_args = NULL; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("TestClass", kwargs)) { + goto exit; + } + __clinic_args = Py_NewRef(args); + return_value = varpos_no_fastcall_impl(type, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static PyObject * +posonly_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, PyObject *b, + PyObject *args); + +static PyObject * +posonly_varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = &PyBaseObject_Type; + PyObject *a; + PyObject *b; + PyObject *__clinic_args = NULL; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("TestClass", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 2, PY_SSIZE_T_MAX)) { + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + b = PyTuple_GET_ITEM(args, 1); + __clinic_args = PyTuple_GetSlice(args, 2, PY_SSIZE_T_MAX); + if (!__clinic_args) { + goto exit; + } + return_value = posonly_varpos_no_fastcall_impl(type, a, b, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static PyObject * +posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, PyObject *args); + +static PyObject * +posonly_req_opt_varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = &PyBaseObject_Type; + PyObject *a; + PyObject *b = Py_False; + PyObject *__clinic_args = NULL; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("TestClass", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 1, PY_SSIZE_T_MAX)) { + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + if (PyTuple_GET_SIZE(args) < 2) { + goto skip_optional; + } + b = PyTuple_GET_ITEM(args, 1); +skip_optional: + __clinic_args = PyTuple_GetSlice(args, 2, PY_SSIZE_T_MAX); + if (!__clinic_args) { + goto exit; + } + return_value = posonly_req_opt_varpos_no_fastcall_impl(type, a, b, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static PyObject * +posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, PyObject *args); + +static PyObject * +posonly_poskw_varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { _Py_LATIN1_CHR('b'), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "b", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "TestClass", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *a; + PyObject *b; + PyObject *__clinic_args = NULL; + + fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + b = fastargs[1]; + __clinic_args = PyTuple_GetSlice(args, 2, PY_SSIZE_T_MAX); + if (!__clinic_args) { + goto exit; + } + return_value = posonly_poskw_varpos_no_fastcall_impl(type, a, b, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +static PyObject * +varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = &PyBaseObject_Type; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("TestClass", kwargs)) { + goto exit; + } + __clinic_args = _PyTuple_ITEMS(args); + args_length = PyTuple_GET_SIZE(args); + return_value = varpos_array_no_fastcall_impl(type, __clinic_args, args_length); + +exit: + return return_value; +} + +static PyObject * +posonly_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +posonly_varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = &PyBaseObject_Type; + PyObject *a; + PyObject *b; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("TestClass", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 2, PY_SSIZE_T_MAX)) { + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + b = PyTuple_GET_ITEM(args, 1); + __clinic_args = _PyTuple_ITEMS(args) + 2; + args_length = PyTuple_GET_SIZE(args) - 2; + return_value = posonly_varpos_array_no_fastcall_impl(type, a, b, __clinic_args, args_length); + +exit: + return return_value; +} + +static PyObject * +posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type, + PyObject *a, PyObject *b, + PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +posonly_req_opt_varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = &PyBaseObject_Type; + PyObject *a; + PyObject *b = Py_False; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("TestClass", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 1, PY_SSIZE_T_MAX)) { + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + if (PyTuple_GET_SIZE(args) < 2) { + goto skip_optional; + } + b = PyTuple_GET_ITEM(args, 1); +skip_optional: + __clinic_args = PyTuple_GET_SIZE(args) > 2 ? _PyTuple_ITEMS(args) + 2 : _PyTuple_ITEMS(args); + args_length = Py_MAX(0, PyTuple_GET_SIZE(args) - 2); + return_value = posonly_req_opt_varpos_array_no_fastcall_impl(type, a, b, __clinic_args, args_length); + +exit: + return return_value; +} + +static PyObject * +posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a, + PyObject *b, + PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +posonly_poskw_varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { _Py_LATIN1_CHR('b'), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "b", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "TestClass", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *a; + PyObject *b; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + b = fastargs[1]; + __clinic_args = PyTuple_GET_SIZE(args) > 2 ? _PyTuple_ITEMS(args) + 2 : _PyTuple_ITEMS(args); + args_length = Py_MAX(0, PyTuple_GET_SIZE(args) - 2); + return_value = posonly_poskw_varpos_array_no_fastcall_impl(type, a, b, __clinic_args, args_length); + +exit: + return return_value; +} +/*[clinic end generated code: output=ed3408af146a746c input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic_depr.c.h b/Modules/clinic/_testclinic_depr.c.h index 95a2cc4cb5e..0e374f100d6 100644 --- a/Modules/clinic/_testclinic_depr.c.h +++ b/Modules/clinic/_testclinic_depr.c.h @@ -9,6 +9,7 @@ preserve #include "pycore_long.h" // _PyLong_UnsignedShort_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_runtime.h" // _Py_ID() +#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(depr_star_new__doc__, "DeprStarNew(a=None)\n" @@ -2393,4 +2394,4 @@ depr_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject * exit: return return_value; } -/*[clinic end generated code: output=ca6da2c7137554be input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5dda27c80df7351e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/gcmodule.c.h b/Modules/clinic/gcmodule.c.h index be3bd35b4ff..34b2a79275c 100644 --- a/Modules/clinic/gcmodule.c.h +++ b/Modules/clinic/gcmodule.c.h @@ -8,6 +8,7 @@ preserve #endif #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(gc_enable__doc__, "enable($module, /)\n" @@ -312,23 +313,24 @@ PyDoc_STRVAR(gc_get_referrers__doc__, {"get_referrers", _PyCFunction_CAST(gc_get_referrers), METH_FASTCALL, gc_get_referrers__doc__}, static PyObject * -gc_get_referrers_impl(PyObject *module, Py_ssize_t nargs, - PyObject *const *args); +gc_get_referrers_impl(PyObject *module, PyObject *objs); static PyObject * gc_get_referrers(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject *objs = NULL; - if (!_PyArg_CheckPositional("get_referrers", nargs, 0, PY_SSIZE_T_MAX)) { + objs = _PyTuple_FromArray(args, nargs); + if (objs == NULL) { goto exit; } - __clinic_args = args + 0; - return_value = gc_get_referrers_impl(module, nvararg, __clinic_args); + return_value = gc_get_referrers_impl(module, objs); exit: + /* Cleanup for objs */ + Py_XDECREF(objs); + return return_value; } @@ -342,23 +344,24 @@ PyDoc_STRVAR(gc_get_referents__doc__, {"get_referents", _PyCFunction_CAST(gc_get_referents), METH_FASTCALL, gc_get_referents__doc__}, static PyObject * -gc_get_referents_impl(PyObject *module, Py_ssize_t nargs, - PyObject *const *args); +gc_get_referents_impl(PyObject *module, PyObject *objs); static PyObject * gc_get_referents(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject *objs = NULL; - if (!_PyArg_CheckPositional("get_referents", nargs, 0, PY_SSIZE_T_MAX)) { + objs = _PyTuple_FromArray(args, nargs); + if (objs == NULL) { goto exit; } - __clinic_args = args + 0; - return_value = gc_get_referents_impl(module, nvararg, __clinic_args); + return_value = gc_get_referents_impl(module, objs); exit: + /* Cleanup for objs */ + Py_XDECREF(objs); + return return_value; } @@ -575,4 +578,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=f488a0d4d6bd3687 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4f35875870da17c9 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index e4bda8a3e62..461f77183cd 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -18,22 +18,20 @@ PyDoc_STRVAR(math_gcd__doc__, {"gcd", _PyCFunction_CAST(math_gcd), METH_FASTCALL, math_gcd__doc__}, static PyObject * -math_gcd_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); +math_gcd_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length); static PyObject * math_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; - if (!_PyArg_CheckPositional("gcd", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = math_gcd_impl(module, nvararg, __clinic_args); + __clinic_args = args; + args_length = nargs; + return_value = math_gcd_impl(module, __clinic_args, args_length); -exit: return return_value; } @@ -47,22 +45,20 @@ PyDoc_STRVAR(math_lcm__doc__, {"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm__doc__}, static PyObject * -math_lcm_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); +math_lcm_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length); static PyObject * math_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; - if (!_PyArg_CheckPositional("lcm", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = math_lcm_impl(module, nvararg, __clinic_args); + __clinic_args = args; + args_length = nargs; + return_value = math_lcm_impl(module, __clinic_args, args_length); -exit: return return_value; } @@ -430,22 +426,20 @@ PyDoc_STRVAR(math_hypot__doc__, {"hypot", _PyCFunction_CAST(math_hypot), METH_FASTCALL, math_hypot__doc__}, static PyObject * -math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args); +math_hypot_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length); static PyObject * math_hypot(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; - if (!_PyArg_CheckPositional("hypot", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = math_hypot_impl(module, nvararg, __clinic_args); + __clinic_args = args; + args_length = nargs; + return_value = math_hypot_impl(module, __clinic_args, args_length); -exit: return return_value; } @@ -1109,4 +1103,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=ff99a737c18d9210 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cb506f61bc5ef862 input=a9049054013a1b77]*/ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index f5fea5aa4dd..ad13496b06d 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -216,31 +216,21 @@ gc_get_count_impl(PyObject *module) /*[clinic input] gc.get_referrers - *objs as args: object + *objs: tuple Return the list of objects that directly refer to any of 'objs'. [clinic start generated code]*/ static PyObject * -gc_get_referrers_impl(PyObject *module, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=1d44a7695ea25c40 input=bae96961b14a0922]*/ +gc_get_referrers_impl(PyObject *module, PyObject *objs) +/*[clinic end generated code: output=929d6dff26f609b9 input=9102be7ebee69ee3]*/ { - PyObject *varargs = _PyTuple_FromArray(args, nargs); - - if (!varargs) { - return NULL; - } - if (PySys_Audit("gc.get_referrers", "(O)", varargs) < 0) { - Py_DECREF(varargs); + if (PySys_Audit("gc.get_referrers", "(O)", objs) < 0) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); - PyObject *result = _PyGC_GetReferrers(interp, varargs); - - Py_DECREF(varargs); - return result; + return _PyGC_GetReferrers(interp, objs); } /* Append obj to list; return true if error (out of memory), false if OK. */ @@ -274,43 +264,34 @@ append_referrents(PyObject *result, PyObject *args) /*[clinic input] gc.get_referents - *objs as args: object + *objs: tuple Return the list of objects that are directly referred to by 'objs'. [clinic start generated code]*/ static PyObject * -gc_get_referents_impl(PyObject *module, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=e459f3e8c0d19311 input=b3ceab0c34038cbf]*/ +gc_get_referents_impl(PyObject *module, PyObject *objs) +/*[clinic end generated code: output=6dfde40cd1588e1d input=55c078a6d0248fe0]*/ { - PyObject *varargs = _PyTuple_FromArray(args, nargs); - - if (!varargs) { - return NULL; - } - if (PySys_Audit("gc.get_referents", "(O)", varargs) < 0) { - Py_DECREF(varargs); + if (PySys_Audit("gc.get_referents", "(O)", objs) < 0) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *result = PyList_New(0); if (result == NULL) { - Py_DECREF(varargs); return NULL; } // NOTE: stop the world is a no-op in default build _PyEval_StopTheWorld(interp); - int err = append_referrents(result, varargs); + int err = append_referrents(result, objs); _PyEval_StartTheWorld(interp); if (err < 0) { Py_CLEAR(result); } - Py_DECREF(varargs); return result; } diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 77f50a20016..29638114dd9 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -722,22 +722,23 @@ m_log10(double x) /*[clinic input] math.gcd - *integers as args: object + *integers as args: array Greatest Common Divisor. [clinic start generated code]*/ static PyObject * -math_gcd_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=b57687fcf431c1b8 input=94e675b7ceeaf0c9]*/ +math_gcd_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=a26c95907374ffb4 input=ded7f0ea3850c05c]*/ { // Fast-path for the common case: gcd(int, int) - if (nargs == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1])) + if (args_length == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1])) { return _PyLong_GCD(args[0], args[1]); } - if (nargs == 0) { + if (args_length == 0) { return PyLong_FromLong(0); } @@ -745,13 +746,13 @@ math_gcd_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) if (res == NULL) { return NULL; } - if (nargs == 1) { + if (args_length == 1) { Py_SETREF(res, PyNumber_Absolute(res)); return res; } PyObject *one = _PyLong_GetOne(); // borrowed ref - for (Py_ssize_t i = 1; i < nargs; i++) { + for (Py_ssize_t i = 1; i < args_length; i++) { PyObject *x = _PyNumber_Index(args[i]); if (x == NULL) { Py_DECREF(res); @@ -804,32 +805,33 @@ long_lcm(PyObject *a, PyObject *b) /*[clinic input] math.lcm - *integers as args: object + *integers as args: array Least Common Multiple. [clinic start generated code]*/ static PyObject * -math_lcm_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=f3eff0c25e4d7030 input=e64c33e85f4c47c6]*/ +math_lcm_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=c8a59a5c2e55c816 input=3e4f4b7cdf948a98]*/ { PyObject *res, *x; Py_ssize_t i; - if (nargs == 0) { + if (args_length == 0) { return PyLong_FromLong(1); } res = PyNumber_Index(args[0]); if (res == NULL) { return NULL; } - if (nargs == 1) { + if (args_length == 1) { Py_SETREF(res, PyNumber_Absolute(res)); return res; } PyObject *zero = _PyLong_GetZero(); // borrowed ref - for (i = 1; i < nargs; i++) { + for (i = 1; i < args_length; i++) { x = PyNumber_Index(args[i]); if (x == NULL) { Py_DECREF(res); @@ -2629,7 +2631,7 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q) /*[clinic input] math.hypot - *coordinates as args: object + *coordinates as args: array Multidimensional Euclidean distance from the origin to a point. @@ -2646,8 +2648,9 @@ For example, the hypotenuse of a 3/4/5 right triangle is: [clinic start generated code]*/ static PyObject * -math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=dcb6d4b7a1102ee1 input=5c0061a2d11235ed]*/ +math_hypot_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=c9de404e24370068 input=1bceaf7d4fdcd9c2]*/ { Py_ssize_t i; PyObject *item; @@ -2657,13 +2660,13 @@ math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) double coord_on_stack[NUM_STACK_ELEMS]; double *coordinates = coord_on_stack; - if (nargs > NUM_STACK_ELEMS) { - coordinates = (double *) PyMem_Malloc(nargs * sizeof(double)); + if (args_length > NUM_STACK_ELEMS) { + coordinates = (double *) PyMem_Malloc(args_length * sizeof(double)); if (coordinates == NULL) { return PyErr_NoMemory(); } } - for (i = 0; i < nargs; i++) { + for (i = 0; i < args_length; i++) { item = args[i]; ASSIGN_DOUBLE(x, item, error_exit); x = fabs(x); @@ -2673,7 +2676,7 @@ math_hypot_impl(PyObject *module, Py_ssize_t nargs, PyObject *const *args) max = x; } } - result = vector_norm(nargs, coordinates, max, found_nan); + result = vector_norm(args_length, coordinates, max, found_nan); if (coordinates != coord_on_stack) { PyMem_Free(coordinates); } diff --git a/Objects/clinic/setobject.c.h b/Objects/clinic/setobject.c.h index d6e381a9975..986993b4aa9 100644 --- a/Objects/clinic/setobject.c.h +++ b/Objects/clinic/setobject.c.h @@ -3,7 +3,6 @@ preserve [clinic start generated code]*/ #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() -#include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(set_pop__doc__, "pop($self, /)\n" @@ -41,22 +40,20 @@ PyDoc_STRVAR(set_update__doc__, {"update", _PyCFunction_CAST(set_update), METH_FASTCALL, set_update__doc__}, static PyObject * -set_update_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args); +set_update_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length); static PyObject * set_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *others; + Py_ssize_t others_length; - if (!_PyArg_CheckPositional("update", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = set_update_impl(so, nvararg, __clinic_args); + others = args; + others_length = nargs; + return_value = set_update_impl(so, others, others_length); -exit: return return_value; } @@ -142,22 +139,20 @@ PyDoc_STRVAR(set_union__doc__, {"union", _PyCFunction_CAST(set_union), METH_FASTCALL, set_union__doc__}, static PyObject * -set_union_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args); +set_union_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length); static PyObject * set_union(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *others; + Py_ssize_t others_length; - if (!_PyArg_CheckPositional("union", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = set_union_impl(so, nvararg, __clinic_args); + others = args; + others_length = nargs; + return_value = set_union_impl(so, others, others_length); -exit: return return_value; } @@ -171,23 +166,20 @@ PyDoc_STRVAR(set_intersection_multi__doc__, {"intersection", _PyCFunction_CAST(set_intersection_multi), METH_FASTCALL, set_intersection_multi__doc__}, static PyObject * -set_intersection_multi_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args); +set_intersection_multi_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length); static PyObject * set_intersection_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *others; + Py_ssize_t others_length; - if (!_PyArg_CheckPositional("intersection", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = set_intersection_multi_impl(so, nvararg, __clinic_args); + others = args; + others_length = nargs; + return_value = set_intersection_multi_impl(so, others, others_length); -exit: return return_value; } @@ -201,23 +193,20 @@ PyDoc_STRVAR(set_intersection_update_multi__doc__, {"intersection_update", _PyCFunction_CAST(set_intersection_update_multi), METH_FASTCALL, set_intersection_update_multi__doc__}, static PyObject * -set_intersection_update_multi_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args); +set_intersection_update_multi_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length); static PyObject * set_intersection_update_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *others; + Py_ssize_t others_length; - if (!_PyArg_CheckPositional("intersection_update", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = set_intersection_update_multi_impl(so, nvararg, __clinic_args); + others = args; + others_length = nargs; + return_value = set_intersection_update_multi_impl(so, others, others_length); -exit: return return_value; } @@ -255,23 +244,20 @@ PyDoc_STRVAR(set_difference_update__doc__, {"difference_update", _PyCFunction_CAST(set_difference_update), METH_FASTCALL, set_difference_update__doc__}, static PyObject * -set_difference_update_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args); +set_difference_update_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length); static PyObject * set_difference_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *others; + Py_ssize_t others_length; - if (!_PyArg_CheckPositional("difference_update", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = set_difference_update_impl(so, nvararg, __clinic_args); + others = args; + others_length = nargs; + return_value = set_difference_update_impl(so, others, others_length); -exit: return return_value; } @@ -285,23 +271,20 @@ PyDoc_STRVAR(set_difference_multi__doc__, {"difference", _PyCFunction_CAST(set_difference_multi), METH_FASTCALL, set_difference_multi__doc__}, static PyObject * -set_difference_multi_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args); +set_difference_multi_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length); static PyObject * set_difference_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t nvararg = nargs - 0; - PyObject *const *__clinic_args = NULL; + PyObject * const *others; + Py_ssize_t others_length; - if (!_PyArg_CheckPositional("difference", nargs, 0, PY_SSIZE_T_MAX)) { - goto exit; - } - __clinic_args = args + 0; - return_value = set_difference_multi_impl(so, nvararg, __clinic_args); + others = args; + others_length = nargs; + return_value = set_difference_multi_impl(so, others, others_length); -exit: return return_value; } @@ -536,4 +519,4 @@ set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored)) return return_value; } -/*[clinic end generated code: output=9d4b41191b2c602f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4b65e7709927f31f input=a9049054013a1b77]*/ diff --git a/Objects/clinic/typevarobject.c.h b/Objects/clinic/typevarobject.c.h index 0ba4ff48bc8..3f439a78ded 100644 --- a/Objects/clinic/typevarobject.c.h +++ b/Objects/clinic/typevarobject.c.h @@ -49,7 +49,7 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[7]; + PyObject *argsbuf[6]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; @@ -61,7 +61,7 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) int contravariant = 0; int infer_variance = 0; - fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, 1, argsbuf); + fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); if (!fastargs) { goto exit; } @@ -70,24 +70,23 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto exit; } name = fastargs[0]; - constraints = fastargs[1]; if (!noptargs) { goto skip_optional_kwonly; } + if (fastargs[1]) { + bound = fastargs[1]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } if (fastargs[2]) { - bound = fastargs[2]; + default_value = fastargs[2]; if (!--noptargs) { goto skip_optional_kwonly; } } if (fastargs[3]) { - default_value = fastargs[3]; - if (!--noptargs) { - goto skip_optional_kwonly; - } - } - if (fastargs[4]) { - covariant = PyObject_IsTrue(fastargs[4]); + covariant = PyObject_IsTrue(fastargs[3]); if (covariant < 0) { goto exit; } @@ -95,8 +94,8 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto skip_optional_kwonly; } } - if (fastargs[5]) { - contravariant = PyObject_IsTrue(fastargs[5]); + if (fastargs[4]) { + contravariant = PyObject_IsTrue(fastargs[4]); if (contravariant < 0) { goto exit; } @@ -104,15 +103,21 @@ typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto skip_optional_kwonly; } } - infer_variance = PyObject_IsTrue(fastargs[6]); + infer_variance = PyObject_IsTrue(fastargs[5]); if (infer_variance < 0) { goto exit; } skip_optional_kwonly: + constraints = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX); + if (!constraints) { + goto exit; + } return_value = typevar_new_impl(type, name, constraints, bound, default_value, covariant, contravariant, infer_variance); exit: + /* Cleanup for constraints */ Py_XDECREF(constraints); + return return_value; } @@ -695,4 +700,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=73b39e550e4e336c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32b9e6ced80d3fb0 input=a9049054013a1b77]*/ diff --git a/Objects/setobject.c b/Objects/setobject.c index 66d7fc730c5..2671792190d 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1054,19 +1054,20 @@ set_update_internal(PySetObject *so, PyObject *other) /*[clinic input] set.update so: setobject - *others as args: object + *others: array Update the set, adding elements from all others. [clinic start generated code]*/ static PyObject * -set_update_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=050e2a21f8d7d16a input=df4fe486e38cd337]*/ +set_update_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length) +/*[clinic end generated code: output=017c781c992d5c23 input=ed5d78885b076636]*/ { Py_ssize_t i; - for (i = 0; i < nargs; i++) { - PyObject *other = args[i]; + for (i = 0; i < others_length; i++) { + PyObject *other = others[i]; if (set_update_internal(so, other)) return NULL; } @@ -1283,14 +1284,15 @@ set_clear_impl(PySetObject *so) /*[clinic input] set.union so: setobject - *others as args: object + *others: array Return a new set with elements from the set and all others. [clinic start generated code]*/ static PyObject * -set_union_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args) -/*[clinic end generated code: output=f68ec24d5c19d404 input=ddf088706e9577b2]*/ +set_union_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length) +/*[clinic end generated code: output=b1bfa3d74065f27e input=55a2e81db6347a4f]*/ { PySetObject *result; PyObject *other; @@ -1300,8 +1302,8 @@ set_union_impl(PySetObject *so, Py_ssize_t nargs, PyObject *const *args) if (result == NULL) return NULL; - for (i = 0; i < nargs; i++) { - other = args[i]; + for (i = 0; i < others_length; i++) { + other = others[i]; if ((PyObject *)so == other) continue; if (set_update_local(result, other)) { @@ -1434,25 +1436,25 @@ set_intersection(PySetObject *so, PyObject *other) /*[clinic input] set.intersection as set_intersection_multi so: setobject - *others as args: object + *others: array Return a new set with elements common to the set and all others. [clinic start generated code]*/ static PyObject * -set_intersection_multi_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=ef0756ddb5f2dee9 input=0d9f3805ccbba6a4]*/ +set_intersection_multi_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length) +/*[clinic end generated code: output=db9ff9f875132b6b input=36c7b615694cadae]*/ { Py_ssize_t i; - if (nargs == 0) { + if (others_length == 0) { return set_copy(so, NULL); } PyObject *result = Py_NewRef(so); - for (i = 0; i < nargs; i++) { - PyObject *other = args[i]; + for (i = 0; i < others_length; i++) { + PyObject *other = others[i]; PyObject *newresult; Py_BEGIN_CRITICAL_SECTION2(result, other); newresult = set_intersection((PySetObject *)result, other); @@ -1482,19 +1484,19 @@ set_intersection_update(PySetObject *so, PyObject *other) /*[clinic input] set.intersection_update as set_intersection_update_multi so: setobject - *others as args: object + *others: array Update the set, keeping only elements found in it and all others. [clinic start generated code]*/ static PyObject * -set_intersection_update_multi_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=808d7ad1935b1dfe input=223c1e086aa669a9]*/ +set_intersection_update_multi_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length) +/*[clinic end generated code: output=d768b5584675b48d input=782e422fc370e4fc]*/ { PyObject *tmp; - tmp = set_intersection_multi_impl(so, nargs, args); + tmp = set_intersection_multi_impl(so, others, others_length); if (tmp == NULL) return NULL; Py_BEGIN_CRITICAL_SECTION(so); @@ -1672,20 +1674,20 @@ set_difference_update_internal(PySetObject *so, PyObject *other) /*[clinic input] set.difference_update so: setobject - *others as args: object + *others: array Update the set, removing elements found in others. [clinic start generated code]*/ static PyObject * -set_difference_update_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=55f850c27748d312 input=024e6baa6fbcbb3d]*/ +set_difference_update_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length) +/*[clinic end generated code: output=04a22179b322cfe6 input=93ac28ba5b233696]*/ { Py_ssize_t i; - for (i = 0; i < nargs; i++) { - PyObject *other = args[i]; + for (i = 0; i < others_length; i++) { + PyObject *other = others[i]; int rv; Py_BEGIN_CRITICAL_SECTION2(so, other); rv = set_difference_update_internal(so, other); @@ -1790,32 +1792,32 @@ set_difference(PySetObject *so, PyObject *other) /*[clinic input] set.difference as set_difference_multi so: setobject - *others as args: object + *others: array Return a new set with elements in the set that are not in the others. [clinic start generated code]*/ static PyObject * -set_difference_multi_impl(PySetObject *so, Py_ssize_t nargs, - PyObject *const *args) -/*[clinic end generated code: output=8150d008c00523f3 input=ba78ea5f099e58df]*/ +set_difference_multi_impl(PySetObject *so, PyObject * const *others, + Py_ssize_t others_length) +/*[clinic end generated code: output=b0d33fb05d5477a7 input=c1eb448d483416ad]*/ { Py_ssize_t i; PyObject *result, *other; - if (nargs == 0) { + if (others_length == 0) { return set_copy(so, NULL); } - other = args[0]; + other = others[0]; Py_BEGIN_CRITICAL_SECTION2(so, other); result = set_difference(so, other); Py_END_CRITICAL_SECTION2(); if (result == NULL) return NULL; - for (i = 1; i < nargs; i++) { - other = args[i]; + for (i = 1; i < others_length; i++) { + other = others[i]; int rv; Py_BEGIN_CRITICAL_SECTION(other); rv = set_difference_update_internal((PySetObject *)result, other); diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index f75a8d4ac0c..b47279686cc 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -7,6 +7,7 @@ preserve # include "pycore_runtime.h" // _Py_ID() #endif #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(builtin___import____doc__, "__import__($module, /, name, globals=None, locals=None, fromlist=(),\n" @@ -933,7 +934,8 @@ builtin_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[5]; + PyObject *argsbuf[4]; + PyObject * const *fastargs; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *__clinic_args = NULL; PyObject *sep = Py_None; @@ -941,41 +943,46 @@ builtin_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec PyObject *file = Py_None; int flush = 0; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); - if (!args) { + fastargs = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); + if (!fastargs) { goto exit; } - __clinic_args = args[0]; if (!noptargs) { goto skip_optional_kwonly; } - if (args[1]) { - sep = args[1]; + if (fastargs[0]) { + sep = fastargs[0]; if (!--noptargs) { goto skip_optional_kwonly; } } - if (args[2]) { - end = args[2]; + if (fastargs[1]) { + end = fastargs[1]; if (!--noptargs) { goto skip_optional_kwonly; } } - if (args[3]) { - file = args[3]; + if (fastargs[2]) { + file = fastargs[2]; if (!--noptargs) { goto skip_optional_kwonly; } } - flush = PyObject_IsTrue(args[4]); + flush = PyObject_IsTrue(fastargs[3]); if (flush < 0) { goto exit; } skip_optional_kwonly: + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } return_value = builtin_print_impl(module, __clinic_args, sep, end, file, flush); exit: + /* Cleanup for args */ Py_XDECREF(__clinic_args); + return return_value; } @@ -1228,4 +1235,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=435d3f286a863c49 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=76b27cf4164f257e input=a9049054013a1b77]*/ diff --git a/Python/getargs.c b/Python/getargs.c index a764343ea9e..d529994ad3a 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -2308,13 +2308,11 @@ vgetargskeywordsfast(PyObject *args, PyObject *keywords, } -#undef _PyArg_UnpackKeywords - PyObject * const * -_PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, +_PyArg_UnpackKeywordsEx(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, - int minpos, int maxpos, int minkw, + int minpos, int maxpos, int minkw, int varpos, PyObject **buf) { PyObject *kwtuple; @@ -2360,11 +2358,11 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, else { nkwargs = 0; } - if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) { + if (nkwargs == 0 && minkw == 0 && minpos <= nargs && (varpos || nargs <= maxpos)) { /* Fast path. */ return args; } - if (nargs + nkwargs > maxargs) { + if (!varpos && nargs + nkwargs > maxargs) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, @@ -2377,7 +2375,7 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, nargs + nkwargs); return NULL; } - if (nargs > maxpos) { + if (!varpos && nargs > maxpos) { if (maxpos == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", @@ -2402,13 +2400,16 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", - minposonly < maxpos ? "at least" : "exactly", + (varpos || minposonly < maxpos) ? "at least" : "exactly", minposonly, minposonly == 1 ? "" : "s", nargs); return NULL; } + if (varpos) { + nargs = Py_MIN(maxpos, nargs); + } /* copy tuple args */ for (i = 0; i < nargs; i++) { buf[i] = args[i]; @@ -2486,157 +2487,6 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, return buf; } -PyObject * const * -_PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, - PyObject *kwargs, PyObject *kwnames, - struct _PyArg_Parser *parser, - int minpos, int maxpos, int minkw, - int vararg, PyObject **buf) -{ - PyObject *kwtuple; - PyObject *keyword; - Py_ssize_t varargssize = 0; - int i, posonly, minposonly, maxargs; - int reqlimit = minkw ? maxpos + minkw : minpos; - Py_ssize_t nkwargs; - PyObject * const *kwstack = NULL; - - assert(kwargs == NULL || PyDict_Check(kwargs)); - assert(kwargs == NULL || kwnames == NULL); - - if (parser == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - - if (kwnames != NULL && !PyTuple_Check(kwnames)) { - PyErr_BadInternalCall(); - return NULL; - } - - if (args == NULL && nargs == 0) { - args = buf; - } - - if (parser_init(parser) < 0) { - return NULL; - } - - kwtuple = parser->kwtuple; - posonly = parser->pos; - minposonly = Py_MIN(posonly, minpos); - maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple); - if (kwargs != NULL) { - nkwargs = PyDict_GET_SIZE(kwargs); - } - else if (kwnames != NULL) { - nkwargs = PyTuple_GET_SIZE(kwnames); - kwstack = args + nargs; - } - else { - nkwargs = 0; - } - if (nargs < minposonly) { - PyErr_Format(PyExc_TypeError, - "%.200s%s takes %s %d positional argument%s" - " (%zd given)", - (parser->fname == NULL) ? "function" : parser->fname, - (parser->fname == NULL) ? "" : "()", - minposonly < maxpos ? "at least" : "exactly", - minposonly, - minposonly == 1 ? "" : "s", - nargs); - return NULL; - } - - /* create varargs tuple */ - varargssize = nargs - maxpos; - if (varargssize < 0) { - varargssize = 0; - } - buf[vararg] = PyTuple_New(varargssize); - if (!buf[vararg]) { - return NULL; - } - - /* copy tuple args */ - for (i = 0; i < nargs; i++) { - if (i >= vararg) { - PyTuple_SET_ITEM(buf[vararg], i - vararg, Py_NewRef(args[i])); - continue; - } - else { - buf[i] = args[i]; - } - } - - /* copy keyword args using kwtuple to drive process */ - for (i = Py_MAX((int)nargs, posonly) - Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) { - PyObject *current_arg; - if (nkwargs) { - keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); - if (kwargs != NULL) { - if (PyDict_GetItemRef(kwargs, keyword, ¤t_arg) < 0) { - goto exit; - } - } - else { - current_arg = find_keyword(kwnames, kwstack, keyword); - } - } - else { - current_arg = NULL; - } - - /* If an arguments is passed in as a keyword argument, - * it should be placed before `buf[vararg]`. - * - * For example: - * def f(a, /, b, *args): - * pass - * f(1, b=2) - * - * This `buf` array should be: [1, 2, NULL]. - * In this case, nargs < vararg. - * - * Otherwise, we leave a place at `buf[vararg]` for vararg tuple - * so the index is `i + 1`. */ - if (i < vararg) { - buf[i] = current_arg; - } - else { - buf[i + 1] = current_arg; - } - - if (current_arg) { - Py_DECREF(current_arg); - --nkwargs; - } - else if (i < minpos || (maxpos <= i && i < reqlimit)) { - /* Less arguments than required */ - keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); - PyErr_Format(PyExc_TypeError, "%.200s%s missing required " - "argument '%U' (pos %d)", - (parser->fname == NULL) ? "function" : parser->fname, - (parser->fname == NULL) ? "" : "()", - keyword, i+1); - goto exit; - } - } - - if (nkwargs > 0) { - error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); - goto exit; - } - - return buf; - -exit: - Py_XDECREF(buf[vararg]); - return NULL; -} - - static const char * skipitem(const char **p_format, va_list *p_va, int flags) { diff --git a/Tools/c-analyzer/c_parser/parser/__init__.py b/Tools/c-analyzer/c_parser/parser/__init__.py index 4227e938d7f..ff4f303c4a2 100644 --- a/Tools/c-analyzer/c_parser/parser/__init__.py +++ b/Tools/c-analyzer/c_parser/parser/__init__.py @@ -164,7 +164,7 @@ def _parse(srclines, anon_name, **srckwargs): # We use defaults that cover most files. Files with bigger declarations # are covered elsewhere (MAX_SIZES in cpython/_parser.py). -def _iter_source(lines, *, maxtext=10_000, maxlines=200, showtext=False): +def _iter_source(lines, *, maxtext=11_000, maxlines=200, showtext=False): maxtext = maxtext if maxtext and maxtext > 0 else None maxlines = maxlines if maxlines and maxlines > 0 else None filestack = [] diff --git a/Tools/clinic/libclinic/clanguage.py b/Tools/clinic/libclinic/clanguage.py index 32aba81ab8a..32d2c045b06 100644 --- a/Tools/clinic/libclinic/clanguage.py +++ b/Tools/clinic/libclinic/clanguage.py @@ -15,7 +15,7 @@ from libclinic.function import ( Module, Class, Function, Parameter, permute_optional_groups, GETTER, SETTER, METHOD_INIT) -from libclinic.converters import defining_class_converter, self_converter +from libclinic.converters import self_converter from libclinic.parse_args import ParseArgsCodeGen if TYPE_CHECKING: from libclinic.app import Clinic @@ -396,12 +396,6 @@ class CLanguage(Language): first_optional = len(selfless) positional = selfless and selfless[-1].is_positional_only() has_option_groups = False - requires_defining_class = (len(selfless) - and isinstance(selfless[0].converter, - defining_class_converter)) - pass_vararg_directly = (all(p.is_positional_only() or p.is_vararg() - for p in selfless) - and not requires_defining_class) # offset i by -1 because first_optional needs to ignore self for i, p in enumerate(parameters, -1): @@ -410,9 +404,6 @@ class CLanguage(Language): if (i != -1) and (p.default is not unspecified): first_optional = min(first_optional, i) - if p.is_vararg() and not pass_vararg_directly: - data.cleanup.append(f"Py_XDECREF({c.parser_name});") - # insert group variable group = p.group if last_group != group: @@ -424,11 +415,6 @@ class CLanguage(Language): data.impl_parameters.append("int " + group_name) has_option_groups = True - if p.is_vararg() and pass_vararg_directly: - data.impl_arguments.append('nvararg') - data.impl_parameters.append('Py_ssize_t nargs') - p.converter.type = 'PyObject *const *' - c.render(p, data) if has_option_groups and (not positional): diff --git a/Tools/clinic/libclinic/converter.py b/Tools/clinic/libclinic/converter.py index 86853bb4fba..2c93dda3541 100644 --- a/Tools/clinic/libclinic/converter.py +++ b/Tools/clinic/libclinic/converter.py @@ -312,7 +312,7 @@ class CConverter(metaclass=CConverterAutoRegister): def length_name(self) -> str: """Computes the name of the associated "length" variable.""" assert self.length is not None - return self.parser_name + "_length" + return self.name + "_length" # Why is this one broken out separately? # For "positional-only" function parsing, diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index bd5c2a2b73b..2d103c941cb 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -1228,3 +1228,30 @@ class self_converter(CConverter): type_object = cls.type_object type_ptr = f'PyTypeObject *base_tp = {type_object};' template_dict['base_type_ptr'] = type_ptr + + +# Converters for var-positional parameter. + +class varpos_tuple_converter(CConverter): + type = 'PyObject *' + format_unit = '' + c_default = 'NULL' + + def cleanup(self) -> str: + return f"""Py_XDECREF({self.parser_name});\n""" + + def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + raise AssertionError('should never be called') + +class varpos_array_converter(CConverter): + type = 'PyObject * const *' + format_unit = '' + length = True + c_ignored_default = '' + + def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + raise AssertionError('should never be called') + +# XXX: temporary +class varpos_object_converter(varpos_tuple_converter): + pass diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py index 5ca3bd5cb6c..4b4a8b9969d 100644 --- a/Tools/clinic/libclinic/dsl_parser.py +++ b/Tools/clinic/libclinic/dsl_parser.py @@ -925,16 +925,17 @@ class DSLParser: parameter_name = parameter.arg name, legacy, kwargs = self.parse_converter(parameter.annotation) + if is_vararg: + name = 'varpos_' + name value: object if not default: - if self.parameter_state is ParamState.OPTIONAL: - fail(f"Can't have a parameter without a default ({parameter_name!r}) " - "after a parameter with a default!") if is_vararg: value = NULL - kwargs.setdefault('c_default', "NULL") else: + if self.parameter_state is ParamState.OPTIONAL: + fail(f"Can't have a parameter without a default ({parameter_name!r}) " + "after a parameter with a default!") value = unspecified if 'py_default' in kwargs: fail("You can't specify py_default without specifying a default value!") diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index 559d4fbdd09..2ce4e751214 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -217,8 +217,7 @@ class ParseArgsCodeGen: min_pos: int = 0 max_pos: int = 0 min_kw_only: int = 0 - pseudo_args: int = 0 - vararg: int | str = NO_VARARG + varpos: Parameter | None = None docstring_prototype: str docstring_definition: str @@ -246,6 +245,13 @@ class ParseArgsCodeGen: if self.parameters and isinstance(self.parameters[0].converter, defining_class_converter): self.requires_defining_class = True del self.parameters[0] + + for i, p in enumerate(self.parameters): + if p.is_vararg(): + self.varpos = p + del self.parameters[i] + break + self.converters = [p.converter for p in self.parameters] if self.func.critical_section: @@ -257,18 +263,13 @@ class ParseArgsCodeGen: self.min_pos = 0 self.max_pos = 0 self.min_kw_only = 0 - self.pseudo_args = 0 for i, p in enumerate(self.parameters, 1): if p.is_keyword_only(): assert not p.is_positional_only() if not p.is_optional(): - self.min_kw_only = i - self.max_pos - int(self.vararg != NO_VARARG) - elif p.is_vararg(): - self.pseudo_args += 1 - self.vararg = i - 1 + self.min_kw_only = i - self.max_pos else: - if self.vararg == NO_VARARG: - self.max_pos = i + self.max_pos = i if p.is_positional_only(): self.pos_only = i if not p.is_optional(): @@ -285,6 +286,7 @@ class ParseArgsCodeGen: return (len(self.parameters) == 1 and self.parameters[0].is_positional_only() and not self.converters[0].is_optional() + and not self.varpos and not self.requires_defining_class and not self.is_new_or_init()) @@ -315,7 +317,8 @@ class ParseArgsCodeGen: def init_limited_capi(self) -> None: self.limited_capi = self.codegen.limited_capi - if self.limited_capi and (self.pseudo_args or + if self.limited_capi and ( + (self.varpos and self.pos_only < len(self.parameters)) or (any(p.is_optional() for p in self.parameters) and any(p.is_keyword_only() and not p.is_optional() for p in self.parameters)) or any(c.broken_limited_capi for c in self.converters)): @@ -447,6 +450,74 @@ class ParseArgsCodeGen: parser_code = ' {option_group_parsing}' self.parser_body(parser_code) + def _parse_vararg(self) -> str: + assert self.varpos is not None + paramname = self.varpos.converter.parser_name + if self.varpos.converter.length: + if not self.fastcall: + self.codegen.add_include('pycore_tuple.h', + '_PyTuple_ITEMS()') + start = 'args' if self.fastcall else '_PyTuple_ITEMS(args)' + size = 'nargs' if self.fastcall else 'PyTuple_GET_SIZE(args)' + if self.max_pos: + if min(self.pos_only, self.min_pos) < self.max_pos: + start = f'{size} > {self.max_pos} ? {start} + {self.max_pos} : {start}' + size = f'Py_MAX(0, {size} - {self.max_pos})' + else: + start = f'{start} + {self.max_pos}' + size = f'{size} - {self.max_pos}' + return f""" + {paramname} = {start}; + {self.varpos.converter.length_name} = {size}; + """ + + if self.fastcall: + if self.limited_capi: + if min(self.pos_only, self.min_pos) < self.max_pos: + size = f'Py_MAX(nargs - {self.max_pos}, 0)' + else: + size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs' + return f""" + {paramname} = PyTuple_New({size}); + if (!{paramname}) {{{{ + goto exit; + }}}} + for (Py_ssize_t i = {self.max_pos}; i < nargs; ++i) {{{{ + PyTuple_SET_ITEM({paramname}, i - {self.max_pos}, Py_NewRef(args[i])); + }}}} + """ + else: + self.codegen.add_include('pycore_tuple.h', + '_PyTuple_FromArray()') + if min(self.pos_only, self.min_pos) < self.max_pos: + return f""" + {paramname} = nargs > {self.max_pos} + ? _PyTuple_FromArray(args + {self.max_pos}, nargs - {self.max_pos}) + : PyTuple_New(0); + if ({paramname} == NULL) {{{{ + goto exit; + }}}} + """ + else: + start = f'args + {self.max_pos}' if self.max_pos else 'args' + size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs' + return f""" + {paramname} = _PyTuple_FromArray({start}, {size}); + if ({paramname} == NULL) {{{{ + goto exit; + }}}} + """ + else: + if self.max_pos: + return f""" + {paramname} = PyTuple_GetSlice(args, {self.max_pos}, PY_SSIZE_T_MAX); + if (!{paramname}) {{{{ + goto exit; + }}}} + """ + else: + return f"{paramname} = Py_NewRef(args);\n" + def parse_pos_only(self) -> None: if self.fastcall: # positional-only, but no option groups @@ -469,14 +540,9 @@ class ParseArgsCodeGen: nargs = 'PyTuple_GET_SIZE(args)' argname_fmt = 'PyTuple_GET_ITEM(args, %d)' - if self.vararg != NO_VARARG: - self.declarations = f"Py_ssize_t nvararg = {nargs} - {self.max_pos};" - else: - self.declarations = "" - - max_args = NO_VARARG if (self.vararg != NO_VARARG) else self.max_pos + parser_code = [] + max_args = NO_VARARG if self.varpos else self.max_pos if self.limited_capi: - parser_code = [] if nargs != 'nargs': nargs_def = f'Py_ssize_t nargs = {nargs};' parser_code.append(libclinic.normalize_snippet(nargs_def, indent=4)) @@ -509,33 +575,27 @@ class ParseArgsCodeGen: }}}} """, indent=4)) - else: + elif self.min_pos or max_args != NO_VARARG: self.codegen.add_include('pycore_modsupport.h', '_PyArg_CheckPositional()') - parser_code = [libclinic.normalize_snippet(f""" + parser_code.append(libclinic.normalize_snippet(f""" if (!_PyArg_CheckPositional("{{name}}", {nargs}, {self.min_pos}, {max_args})) {{{{ goto exit; }}}} - """, indent=4)] + """, indent=4)) has_optional = False use_parser_code = True for i, p in enumerate(self.parameters): - if p.is_vararg(): - var = p.converter.parser_name - if self.fastcall: - code = f"{var} = args + {self.vararg};" - else: - code = f"{var} = _PyTuple_CAST(args)->ob_item;" - formatted_code = libclinic.normalize_snippet(code, indent=4) - parser_code.append(formatted_code) - continue - displayname = p.get_displayname(i+1) argname = argname_fmt % i parsearg: str | None parsearg = p.converter.parse_arg(argname, displayname, limited_capi=self.limited_capi) if parsearg is None: + if self.varpos: + raise ValueError( + f"Using converter {p.converter} is not supported " + f"in function with var-positional parameter") use_parser_code = False parser_code = [] break @@ -551,6 +611,8 @@ class ParseArgsCodeGen: if use_parser_code: if has_optional: parser_code.append("skip_optional:") + if self.varpos: + parser_code.append(libclinic.normalize_snippet(self._parse_vararg(), indent=4)) else: for parameter in self.parameters: parameter.converter.use_converter() @@ -575,7 +637,7 @@ class ParseArgsCodeGen: goto exit; }} """, indent=4)] - self.parser_body(*parser_code, declarations=self.declarations) + self.parser_body(*parser_code) def parse_general(self, clang: CLanguage) -> None: parsearg: str | None @@ -589,7 +651,7 @@ class ParseArgsCodeGen: has_optional_kw = ( max(self.pos_only, self.min_pos) + self.min_kw_only - < len(self.converters) - int(self.vararg != NO_VARARG) + < len(self.converters) ) use_parser_code = True @@ -598,57 +660,53 @@ class ParseArgsCodeGen: use_parser_code = False self.fastcall = False else: - if self.vararg == NO_VARARG: + if not self.varpos: self.codegen.add_include('pycore_modsupport.h', '_PyArg_UnpackKeywords()') - args_declaration = "_PyArg_UnpackKeywords", "%s, %s, %s" % ( - self.min_pos, - self.max_pos, - self.min_kw_only - ) + unpack_func = '_PyArg_UnpackKeywords' nargs = "nargs" else: self.codegen.add_include('pycore_modsupport.h', '_PyArg_UnpackKeywordsWithVararg()') - args_declaration = "_PyArg_UnpackKeywordsWithVararg", "%s, %s, %s, %s" % ( - self.min_pos, - self.max_pos, - self.min_kw_only, - self.vararg - ) + unpack_func = '_PyArg_UnpackKeywordsWithVararg' nargs = f"Py_MIN(nargs, {self.max_pos})" if self.max_pos else "0" if self.fastcall: self.flags = "METH_FASTCALL|METH_KEYWORDS" self.parser_prototype = PARSER_PROTOTYPE_FASTCALL_KEYWORDS - argname_fmt = 'args[%d]' self.declarations = declare_parser(self.func, codegen=self.codegen) - self.declarations += "\nPyObject *argsbuf[%s];" % len(self.converters) + self.declarations += "\nPyObject *argsbuf[%s];" % (len(self.converters) or 1) + if self.varpos: + self.declarations += "\nPyObject * const *fastargs;" + argsname = 'fastargs' + argname_fmt = 'fastargs[%d]' + else: + argsname = 'args' + argname_fmt = 'args[%d]' if has_optional_kw: self.declarations += "\nPy_ssize_t noptargs = %s + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (nargs, self.min_pos + self.min_kw_only) - parser_code = [libclinic.normalize_snippet(""" - args = %s(args, nargs, NULL, kwnames, &_parser, %s, argsbuf); - if (!args) {{ - goto exit; - }} - """ % args_declaration, indent=4)] + unpack_args = 'args, nargs, NULL, kwnames' else: # positional-or-keyword arguments self.flags = "METH_VARARGS|METH_KEYWORDS" self.parser_prototype = PARSER_PROTOTYPE_KEYWORD + argsname = 'fastargs' argname_fmt = 'fastargs[%d]' self.declarations = declare_parser(self.func, codegen=self.codegen) - self.declarations += "\nPyObject *argsbuf[%s];" % len(self.converters) + self.declarations += "\nPyObject *argsbuf[%s];" % (len(self.converters) or 1) self.declarations += "\nPyObject * const *fastargs;" self.declarations += "\nPy_ssize_t nargs = PyTuple_GET_SIZE(args);" if has_optional_kw: self.declarations += "\nPy_ssize_t noptargs = %s + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (nargs, self.min_pos + self.min_kw_only) - parser_code = [libclinic.normalize_snippet(""" - fastargs = %s(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %s, argsbuf); - if (!fastargs) {{ - goto exit; - }} - """ % args_declaration, indent=4)] + unpack_args = '_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL' + unpack_args += (f', &_parser, {self.min_pos}, {self.max_pos}, ' + f'{self.min_kw_only}, argsbuf') + parser_code = [libclinic.normalize_snippet(f""" + {argsname} = {unpack_func}({unpack_args}); + if (!{argsname}) {{{{ + goto exit; + }}}} + """, indent=4)] if self.requires_defining_class: self.flags = 'METH_METHOD|' + self.flags @@ -697,8 +755,6 @@ class ParseArgsCodeGen: else: label = 'skip_optional_kwonly' first_opt = self.max_pos + self.min_kw_only - if self.vararg != NO_VARARG: - first_opt += 1 if i == first_opt: add_label = label parser_code.append(libclinic.normalize_snippet(""" @@ -724,6 +780,8 @@ class ParseArgsCodeGen: if use_parser_code: if add_label: parser_code.append("%s:" % add_label) + if self.varpos: + parser_code.append(libclinic.normalize_snippet(self._parse_vararg(), indent=4)) else: for parameter in self.parameters: parameter.converter.use_converter() @@ -914,14 +972,14 @@ class ParseArgsCodeGen: # previous call to parser_body. this is used for an awful hack. self.parser_body_fields: tuple[str, ...] = () - if not self.parameters: + if not self.parameters and not self.varpos: self.parse_no_args() elif self.use_meth_o(): self.parse_one_arg() elif self.has_option_groups(): self.parse_option_groups() elif (not self.requires_defining_class - and self.pos_only == len(self.parameters) - self.pseudo_args): + and self.pos_only == len(self.parameters)): self.parse_pos_only() else: self.parse_general(clang)