summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2023-04-24 12:48:42 +0200
committerStefan Behnel <stefan_ml@behnel.de>2023-04-24 18:57:14 +0200
commitd88426829e413ea02780c6502c686de099eb368b (patch)
treef43df5620d34a1eff9ee51890d8e9316da6661df
parent91b08978873bd49360afeb9d298c874c11cb963e (diff)
downloadcython-d88426829e413ea02780c6502c686de099eb368b.tar.gz
Disallow @cfunc being applied to a @ufunc.
Closes https://github.com/cython/cython/issues/5399
-rw-r--r--Cython/Compiler/ParseTreeTransforms.py7
-rw-r--r--docs/examples/userguide/numpy_ufuncs/ufunc.py2
-rw-r--r--docs/examples/userguide/numpy_ufuncs/ufunc_ctuple.py2
-rw-r--r--docs/examples/userguide/numpy_ufuncs/ufunc_fused.py2
-rw-r--r--tests/errors/pure_errors.py7
5 files changed, 16 insertions, 4 deletions
diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py
index 6c4275dbd..987142f37 100644
--- a/Cython/Compiler/ParseTreeTransforms.py
+++ b/Cython/Compiler/ParseTreeTransforms.py
@@ -1315,6 +1315,8 @@ class InterpretCompilerDirectives(CythonTransform):
directives = []
realdecs = []
both = []
+ current_opt_dict = dict(self.directives)
+ missing = object()
# Decorators coming first take precedence.
for dec in node.decorators[::-1]:
new_directives = self.try_to_parse_directives(dec.decorator)
@@ -1322,8 +1324,11 @@ class InterpretCompilerDirectives(CythonTransform):
for directive in new_directives:
if self.check_directive_scope(node.pos, directive[0], scope_name):
name, value = directive
- if self.directives.get(name, object()) != value:
+ if current_opt_dict.get(name, missing) != value:
+ if name == 'cfunc' and 'ufunc' in current_opt_dict:
+ error(dec.pos, "Cannot apply @cfunc to @ufunc, please reverse the decorators.")
directives.append(directive)
+ current_opt_dict[name] = value
if directive[0] == 'staticmethod':
both.append(dec)
# Adapt scope type based on decorators that change it.
diff --git a/docs/examples/userguide/numpy_ufuncs/ufunc.py b/docs/examples/userguide/numpy_ufuncs/ufunc.py
index adbb49e8d..874183c84 100644
--- a/docs/examples/userguide/numpy_ufuncs/ufunc.py
+++ b/docs/examples/userguide/numpy_ufuncs/ufunc.py
@@ -1,8 +1,8 @@
# tag: numpy
import cython
-@cython.cfunc
@cython.ufunc
+@cython.cfunc
def add_one(x: cython.double) -> cython.double:
# of course, this simple operation can already by done efficiently in Numpy!
return x+1
diff --git a/docs/examples/userguide/numpy_ufuncs/ufunc_ctuple.py b/docs/examples/userguide/numpy_ufuncs/ufunc_ctuple.py
index 1bae902f9..b3f4fb6de 100644
--- a/docs/examples/userguide/numpy_ufuncs/ufunc_ctuple.py
+++ b/docs/examples/userguide/numpy_ufuncs/ufunc_ctuple.py
@@ -1,7 +1,7 @@
# tag: numpy
import cython
-@cython.cfunc
@cython.ufunc
+@cython.cfunc
def add_one_add_two(x: cython.int) -> tuple[cython.int, cython.int]:
return x+1, x+2
diff --git a/docs/examples/userguide/numpy_ufuncs/ufunc_fused.py b/docs/examples/userguide/numpy_ufuncs/ufunc_fused.py
index dd01a508e..01cc3bc57 100644
--- a/docs/examples/userguide/numpy_ufuncs/ufunc_fused.py
+++ b/docs/examples/userguide/numpy_ufuncs/ufunc_fused.py
@@ -1,7 +1,7 @@
# tag: numpy
import cython
-@cython.cfunc
@cython.ufunc
+@cython.cfunc
def generic_add_one(x: cython.numeric) -> cython.numeric:
return x+1
diff --git a/tests/errors/pure_errors.py b/tests/errors/pure_errors.py
index a480d7abe..75682a5a1 100644
--- a/tests/errors/pure_errors.py
+++ b/tests/errors/pure_errors.py
@@ -68,6 +68,12 @@ def test_contradicting_decorators2(x: object) -> object:
return x
+@cython.cfunc
+@cython.ufunc
+def add_one(x: cython.double) -> cython.double:
+ return x+1
+
+
_ERRORS = """
44:22: Calling gil-requiring function not allowed without gil
45:24: Calling gil-requiring function not allowed without gil
@@ -75,6 +81,7 @@ _ERRORS = """
53:0: Exception clause not allowed for function returning Python object
59:0: cfunc and ccall directives cannot be combined
65:0: cfunc and ccall directives cannot be combined
+71:0: Cannot apply @cfunc to @ufunc, please reverse the decorators.
"""
_WARNINGS = """