Skip to content

Commit 1b1c79c

Browse files
[3.9] gh-91583: AC: Fix regression for functions with defining_class (GH-91739) (GH-92080)
Argument Clinic now generates the same efficient code as before adding the defining_class parameter. (cherry picked from commit a055dac)
1 parent 7e55730 commit 1b1c79c

File tree

4 files changed

+120
-57
lines changed

4 files changed

+120
-57
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix regression in the code generated by Argument Clinic for functions with
2+
the ``defining_class`` parameter.

Modules/clinic/_testmultiphase.c.h

+40-26
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/posixmodule.c.h

+42-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/clinic/clinic.py

+36-17
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,10 @@ def output_templates(self, f):
636636
assert parameters
637637
assert isinstance(parameters[0].converter, self_converter)
638638
del parameters[0]
639+
requires_defining_class = False
640+
if parameters and isinstance(parameters[0].converter, defining_class_converter):
641+
requires_defining_class = True
642+
del parameters[0]
639643
converters = [p.converter for p in parameters]
640644

641645
has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
@@ -657,10 +661,6 @@ def output_templates(self, f):
657661
if not p.is_optional():
658662
min_pos = i
659663

660-
requires_defining_class = any(
661-
isinstance(p.converter, defining_class_converter)
662-
for p in parameters)
663-
664664
meth_o = (len(parameters) == 1 and
665665
parameters[0].is_positional_only() and
666666
not converters[0].is_optional() and
@@ -763,24 +763,40 @@ def parser_body(prototype, *fields, declarations=''):
763763
return linear_format(output(), parser_declarations=declarations)
764764

765765
if not parameters:
766-
# no parameters, METH_NOARGS
766+
if not requires_defining_class:
767+
# no parameters, METH_NOARGS
768+
flags = "METH_NOARGS"
767769

768-
flags = "METH_NOARGS"
770+
parser_prototype = normalize_snippet("""
771+
static PyObject *
772+
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
773+
""")
774+
parser_code = []
769775

770-
parser_prototype = normalize_snippet("""
771-
static PyObject *
772-
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
773-
""")
774-
parser_definition = parser_prototype
776+
else:
777+
assert not new_or_init
775778

776-
if default_return_converter:
777-
parser_definition = parser_prototype + '\n' + normalize_snippet("""
778-
{{
779-
return {c_basename}_impl({impl_arguments});
779+
flags = "METH_METHOD|METH_FASTCALL|METH_KEYWORDS"
780+
781+
parser_prototype = parser_prototype_def_class
782+
return_error = ('return NULL;' if default_return_converter
783+
else 'goto exit;')
784+
parser_code = [normalize_snippet("""
785+
if (nargs) {{
786+
PyErr_SetString(PyExc_TypeError, "{name}() takes no arguments");
787+
%s
780788
}}
781-
""")
789+
""" % return_error, indent=4)]
790+
791+
if default_return_converter:
792+
parser_definition = '\n'.join([
793+
parser_prototype,
794+
'{{',
795+
*parser_code,
796+
' return {c_basename}_impl({impl_arguments});',
797+
'}}'])
782798
else:
783-
parser_definition = parser_body(parser_prototype)
799+
parser_definition = parser_body(parser_prototype, *parser_code)
784800

785801
elif meth_o:
786802
flags = "METH_O"
@@ -939,6 +955,9 @@ def parser_body(prototype, *fields, declarations=''):
939955

940956
add_label = None
941957
for i, p in enumerate(parameters):
958+
if isinstance(p.converter, defining_class_converter):
959+
raise ValueError("defining_class should be the first "
960+
"parameter (after self)")
942961
displayname = p.get_displayname(i+1)
943962
parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
944963
if parsearg is None:

0 commit comments

Comments
 (0)