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".
This commit is contained in:
Serhiy Storchaka 2024-11-07 23:40:03 +02:00 committed by GitHub
parent 09d6f5dc78
commit 1f777396f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1597 additions and 662 deletions

View File

@ -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
}

View File

@ -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);

View File

@ -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]

View File

@ -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)))

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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]*/

View File

@ -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]*/

View File

@ -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]*/

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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]*/

View File

@ -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]*/

View File

@ -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);

View File

@ -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]*/

View File

@ -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, &current_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)
{

View File

@ -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 = []

View File

@ -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):

View File

@ -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,

View File

@ -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

View File

@ -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!")

View File

@ -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)