From 85e6e61835b08dc7c54c2b0aa0081b00612f3c45 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 6 Aug 2026 11:41:11 +0300 Subject: [PATCH] gh-64660: Do not hardcode the name of the returned variable Return converters had to hardcode "return_value", because declare() sets data.return_value to the variable which receives the value returned by the impl. The name of the variable returned by the parsing function is now available as data.parser_retval. --- .../2026-08-06-11-40-49.gh-issue-64660.MswRQB.rst | 3 +++ PC/msvcrtmodule.c | 7 ++++--- Tools/clinic/libclinic/clanguage.py | 1 + Tools/clinic/libclinic/codegen.py | 7 +++++-- Tools/clinic/libclinic/parse_args.py | 8 ++++---- Tools/clinic/libclinic/return_converters.py | 9 ++++++--- 6 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-08-06-11-40-49.gh-issue-64660.MswRQB.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-08-06-11-40-49.gh-issue-64660.MswRQB.rst b/Misc/NEWS.d/next/Tools-Demos/2026-08-06-11-40-49.gh-issue-64660.MswRQB.rst new file mode 100644 index 00000000000000..aa0410b39b1127 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-08-06-11-40-49.gh-issue-64660.MswRQB.rst @@ -0,0 +1,3 @@ +Argument Clinic return converters no longer need to hardcode the name of the +variable returned by the parsing function. +It is now available as ``data.parser_retval``. diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 02f16d41b1457b..26d7547c387f5f 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -65,7 +65,7 @@ class byte_char_return_converter(CReturnConverter): data.declarations.append('char s[1];') data.return_value = 's[0]' data.return_conversion.append( - 'return_value = PyBytes_FromStringAndSize(s, 1);\n') + f'{data.parser_retval} = PyBytes_FromStringAndSize(s, 1);\n') class wchar_t_return_converter(CReturnConverter): type = 'wchar_t' @@ -73,9 +73,10 @@ class wchar_t_return_converter(CReturnConverter): def render(self, function, data): self.declare(data) data.return_conversion.append( - 'return_value = PyUnicode_FromOrdinal(_return_value);\n') + f'{data.parser_retval} = ' + f'PyUnicode_FromOrdinal({data.converter_retval});\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=ff031be44ab3250d]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=ed7a4a045a6d0496]*/ /*[clinic input] module msvcrt diff --git a/Tools/clinic/libclinic/clanguage.py b/Tools/clinic/libclinic/clanguage.py index 1581a19a4fd78a..a8473dba051246 100644 --- a/Tools/clinic/libclinic/clanguage.py +++ b/Tools/clinic/libclinic/clanguage.py @@ -525,6 +525,7 @@ def render_function( template_dict['cleanup'] = libclinic.format_escape("".join(data.cleanup)) template_dict['return_value'] = data.return_value + template_dict['parser_retval'] = data.parser_retval template_dict['lock'] = "\n".join(data.lock) template_dict['unlock'] = "\n".join(data.unlock) diff --git a/Tools/clinic/libclinic/codegen.py b/Tools/clinic/libclinic/codegen.py index b2f1db6f8ef8da..3ca8c4a1b6859d 100644 --- a/Tools/clinic/libclinic/codegen.py +++ b/Tools/clinic/libclinic/codegen.py @@ -47,14 +47,17 @@ def __init__(self) -> None: # The arguments to the impl function at the time it's called. self.impl_arguments: list[str] = [] + # The name of the variable which is returned by the parser. + self.parser_retval = "return_value" + # For return converters: the name of the variable that # should receive the value returned by the impl. self.return_value = "return_value" # For return converters: the code to convert the return # value from the parse function. This is also where - # you should check the _return_value for errors, and - # "goto exit" if there are any. + # you should check the value returned by the impl for errors, + # and "goto exit" if there are any. self.return_conversion: list[str] = [] self.converter_retval = "_return_value" diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index bca87ecd75100c..6fca10f4bec180 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -319,7 +319,7 @@ def select_prototypes(self) -> None: self.docstring_prototype = '' self.docstring_definition = '' self.methoddef_define = METHODDEF_PROTOTYPE_DEFINE - self.return_value_declaration = "PyObject *return_value = NULL;" + self.return_value_declaration = "PyObject *{parser_retval} = NULL;" if self.is_new_or_init() and not self.func.docstring: pass @@ -330,7 +330,7 @@ def select_prototypes(self) -> None: elif self.func.kind is SETTER: if self.func.docstring: fail("docstrings are only supported for @getter, not @setter") - self.return_value_declaration = "int {return_value};" + self.return_value_declaration = "int {parser_retval};" self.methoddef_define = SETTERDEF_PROTOTYPE_DEFINE else: self.docstring_prototype = DOCSTRING_PROTOTYPE_VAR @@ -371,7 +371,7 @@ def parser_body( {exit_label} {cleanup} - return return_value; + return {parser_retval}; }} """) for field in preamble, *fields, finale: @@ -860,7 +860,7 @@ def handle_new_or_init(self) -> None: if self.func.kind is METHOD_NEW: self.parser_prototype = PARSER_PROTOTYPE_KEYWORD else: - self.return_value_declaration = "int return_value = -1;" + self.return_value_declaration = "int {parser_retval} = -1;" self.parser_prototype = PARSER_PROTOTYPE_KEYWORD___INIT__ fields: list[str] = list(self.parser_body_fields) diff --git a/Tools/clinic/libclinic/return_converters.py b/Tools/clinic/libclinic/return_converters.py index b41e053bae5f3a..4134d8e065ec43 100644 --- a/Tools/clinic/libclinic/return_converters.py +++ b/Tools/clinic/libclinic/return_converters.py @@ -110,7 +110,8 @@ def render(self, function: Function, data: CRenderData) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == -1", data) data.return_conversion.append( - f'return_value = PyBool_FromLong((long){data.converter_retval});\n' + f'{data.parser_retval} = ' + f'PyBool_FromLong((long){data.converter_retval});\n' ) @@ -124,7 +125,8 @@ def render(self, function: Function, data: CRenderData) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data) data.return_conversion.append( - f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n' + f'{data.parser_retval} = ' + f'{self.conversion_fn}({self.cast}{data.converter_retval});\n' ) @@ -164,7 +166,8 @@ def render(self, function: Function, data: CRenderData) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == -1.0", data) data.return_conversion.append( - f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n' + f'{data.parser_retval} = ' + f'PyFloat_FromDouble({self.cast}{data.converter_retval});\n' )