From 28b64adade66442bfb02c6ff2bc7c76cff2501bc Mon Sep 17 00:00:00 2001 From: da-woods Date: Fri, 8 Dec 2023 19:46:50 +0000 Subject: [PATCH] Fix an issue trying list.index indexing in FusedNode (#5896) * Fix an issue trying list.index indexing in FusedNode In some Python versions, generating the error message when .index fails to find an index leads to a compiler crash. Fix this by not relying on type being fully set up while generating __str__. Fixes #5894 and #5588 * Check "in" before indexing --- Cython/Compiler/FusedNode.py | 7 +++---- Cython/Compiler/PyrexTypes.py | 7 ++++++- tests/run/fused_cpdef.pxd | 4 ++++ tests/run/fused_cpdef.pyx | 13 +++++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 tests/run/fused_cpdef.pxd diff --git a/Cython/Compiler/FusedNode.py b/Cython/Compiler/FusedNode.py index 94e856babd9..2202aed8f1a 100644 --- a/Cython/Compiler/FusedNode.py +++ b/Cython/Compiler/FusedNode.py @@ -196,12 +196,11 @@ def copy_cdef(self, env): break # replace old entry with new entries - try: + if self.node.entry in env.cfunc_entries: cindex = env.cfunc_entries.index(self.node.entry) - except ValueError: - env.cfunc_entries.extend(new_cfunc_entries) - else: env.cfunc_entries[cindex:cindex+1] = new_cfunc_entries + else: + env.cfunc_entries.extend(new_cfunc_entries) if orig_py_func: self.py_func = self.make_fused_cpdef(orig_py_func, env, diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index b6af4a5ab3f..1fd46754e06 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -3294,7 +3294,12 @@ def declaration_code(self, entity_code, if self.is_overridable: arg_decl_list.append("int %s" % Naming.skip_dispatch_cname) if self.optional_arg_count: - arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname)) + if self.op_arg_struct: + arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname)) + else: + # op_arg_struct may not be initialized at this point if this class is being used + # to prepare a Python error message or similar. In this case, just omit the args. + assert for_display if self.has_varargs: arg_decl_list.append("...") arg_decl_code = ", ".join(arg_decl_list) diff --git a/tests/run/fused_cpdef.pxd b/tests/run/fused_cpdef.pxd new file mode 100644 index 00000000000..e4f4a600dd6 --- /dev/null +++ b/tests/run/fused_cpdef.pxd @@ -0,0 +1,4 @@ +cimport cython + +cdef class C: + cpdef object has_default_struct(self, cython.floating x, a=?) diff --git a/tests/run/fused_cpdef.pyx b/tests/run/fused_cpdef.pyx index 3979570b75c..4f569c24c3e 100644 --- a/tests/run/fused_cpdef.pyx +++ b/tests/run/fused_cpdef.pyx @@ -205,3 +205,16 @@ def test_defaults(): >>> mutable_default(3,[]) [3] """ + +cdef class C: + cpdef object has_default_struct(self, cython.floating x, a=None): + return x, a + +# https://github.com/cython/cython/issues/5588 +# On some Python versions this was causing a compiler crash +def test_call_has_default_struct(C c, double x): + """ + >>> test_call_has_default_struct(C(), 5.) + (5.0, None) + """ + return c.has_default_struct(x)