From e4ef0c1e807aab8c20fb08b638550c912c166be3 Mon Sep 17 00:00:00 2001 From: da-woods Date: Tue, 12 Jul 2022 19:00:58 +0100 Subject: Error on memoryview argument capture on 0.29.x (GH-4849) I don't believe it's easy to fix https://github.com/cython/cython/issues/4798 on 0.29.x Therefore, generate an error message that explains two possible workarounds. This at least makes sure that people don't end up with mysterious crashes. --- Cython/Compiler/Nodes.py | 15 +++++++++++++-- tests/memoryview/memslice.pyx | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 339b1fa04..743d6959b 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -2637,8 +2637,11 @@ class CFuncDefNode(FuncDefNode): def put_into_closure(entry): if entry.in_closure and not arg.default: code.putln('%s = %s;' % (entry.cname, entry.original_cname)) - code.put_var_incref(entry) - code.put_var_giveref(entry) + if entry.type.is_memoryviewslice: + code.put_incref_memoryviewslice(entry.cname, have_gil=True) + else: + code.put_var_incref(entry) + code.put_var_giveref(entry) for arg in self.args: put_into_closure(scope.lookup_here(arg.name)) @@ -3234,6 +3237,14 @@ class DefNode(FuncDefNode): # Move arguments into closure if required def put_into_closure(entry): if entry.in_closure: + if entry.type.is_memoryviewslice: + error( + self.pos, + "Referring to a memoryview typed argument directly in a nested closure function " + "is not supported in Cython 0.x. " + "Either upgrade to Cython 3, or assign the argument to a local variable " + "and use that in the nested function." + ) code.putln('%s = %s;' % (entry.cname, entry.original_cname)) if entry.xdecref_cleanup: # mostly applies to the starstar arg - this can sometimes be NULL diff --git a/tests/memoryview/memslice.pyx b/tests/memoryview/memslice.pyx index 24af61e17..ccf760c21 100644 --- a/tests/memoryview/memslice.pyx +++ b/tests/memoryview/memslice.pyx @@ -2549,3 +2549,23 @@ def test_const_buffer(const int[:] a): cdef const int[:] c = a print(a[0]) print(c[-1]) + +cdef arg_in_closure_cdef(int [:] a): + def inner(): + return (a[0], a[1]) + return inner + +def test_arg_in_closure_cdef(a): + """ + >>> A = IntMockBuffer("A", range(6), shape=(6,)) + >>> inner = test_arg_in_closure_cdef(A) + acquired A + >>> inner() + (0, 1) + + The assignment below is just to avoid printing what was collected + >>> del inner; ignore_me = gc.collect() + released A + """ + return arg_in_closure_cdef(a) + -- cgit v1.2.1