summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2022-07-29 06:32:01 +0100
committerGitHub <noreply@github.com>2022-07-29 07:32:01 +0200
commita4be069c6bb0de91c98db5c6378ed2947ff46a45 (patch)
tree1a0edefc8d83292e796d18edbb5c5db1ccabcfdb
parent67c44be9dd01a7a5bdde8df928f0cd4139570e0e (diff)
downloadcython-a4be069c6bb0de91c98db5c6378ed2947ff46a45.tar.gz
Reallow capture of memoryview arguments (GH-4929)
It was actually OK in def functions. It only looks very dodgy: ``` __Pyx_XDEC_MEMVIEW(closure->arg) ``` This gets called twice and `INC` gets called once. However this is actually OK since XDEC really means "clear" Fixes https://github.com/cython/cython/issues/4798 for 0.29.x (completely I think)
-rw-r--r--Cython/Compiler/Nodes.py8
-rw-r--r--tests/memoryview/memslice.pyx19
2 files changed, 19 insertions, 8 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 743d6959b..c5ddad0a6 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -3237,14 +3237,6 @@ 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 3a5943aa3..2d496821f 100644
--- a/tests/memoryview/memslice.pyx
+++ b/tests/memoryview/memslice.pyx
@@ -2556,6 +2556,25 @@ def test_const_buffer(const int[:] a):
print(a[0])
print(c[-1])
+
+@testcase
+def test_arg_in_closure(int [:] a):
+ """
+ >>> A = IntMockBuffer("A", range(6), shape=(6,))
+ >>> inner = test_arg_in_closure(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
+ """
+ def inner():
+ return (a[0], a[1])
+ return inner
+
+
cdef arg_in_closure_cdef(int [:] a):
def inner():
return (a[0], a[1])