Description
Bug report
Bug description:
Generated code for argument parsing contains redundant gotos when there are both positional and keyword-only arguments with default values. Take this example:
/*[clinic input]
test.func -> int
x: object
y: object = None
*
z: object = None
Test function
[clinic start generated code]*/
This produces
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
if (!args) {
goto exit;
}
x = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
if (args[1]) {
y = args[1];
if (!--noptargs) {
goto skip_optional_pos;
}
}
skip_optional_pos:
if (!noptargs) {
goto skip_optional_kwonly;
}
z = args[2];
skip_optional_kwonly:
_return_value = test_func_impl(module, x, y, z);
Note that all gotos to skip_optional_pos
happen only when !noptargs
, but skip_optional_pos
first checks the exact same condition and immediately jumps to skip_optional_kwonly
. We can remove this double jump and extra check and instead generate simpler code:
x = args[0];
if (!noptargs) {
goto skip_optional;
}
if (args[1]) {
y = args[1];
if (!--noptargs) {
goto skip_optional;
}
}
z = args[2];
skip_optional:
This code is generated if z
is not keyword-only but a regular positional argument.
In general, it does not seem to make sense to have separate skip_optional_pos
and skip_optional_kwonly
, since there is no way to tell them apart. We only have the combined number of optional arguments (noptargs
), which includes both positional and keyword only. (This is unlike positional-only arguments, where we can also check nargs
.)
CC @erlend-aasland @AlexWaygood @serhiy-storchaka
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux