diff options
author | da-woods <dw-git@d-woods.co.uk> | 2022-07-29 06:32:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-29 07:32:01 +0200 |
commit | a4be069c6bb0de91c98db5c6378ed2947ff46a45 (patch) | |
tree | 1a0edefc8d83292e796d18edbb5c5db1ccabcfdb | |
parent | 67c44be9dd01a7a5bdde8df928f0cd4139570e0e (diff) | |
download | cython-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.py | 8 | ||||
-rw-r--r-- | tests/memoryview/memslice.pyx | 19 |
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]) |