From ec8c0804f1a847e7f9b92210d756507afb6ae9b3 Mon Sep 17 00:00:00 2001 From: da-woods Date: Sat, 7 Aug 2021 09:28:31 +0100 Subject: Restore error when using arbitrary decorators on cdef functions (GH-4323) These were lost when cdef properties (for extern types) were introduced. Closes #4322 (based on my interpretation of the problem as an error-reporting issue) --- Cython/Compiler/ParseTreeTransforms.py | 10 ++++++++- tests/errors/cdef_func_decorators.pyx | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/errors/cdef_func_decorators.pyx diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index a959c880e..0eb91163a 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -1123,6 +1123,7 @@ class InterpretCompilerDirectives(CythonTransform): realdecs.append(dec) if realdecs and (scope_name == 'cclass' or isinstance(node, (Nodes.CClassDefNode, Nodes.CVarDefNode))): + # Note - arbitrary C function decorators are caught later in DecoratorTransform raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.") node.decorators = realdecs[::-1] + both[::-1] # merge or override repeated directives @@ -1438,7 +1439,14 @@ class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations): def visit_CFuncDefNode(self, node): node = self.visit_FuncDefNode(node) - if self.scope_type != 'cclass' or self.scope_node.visibility != "extern" or not node.decorators: + if not node.decorators: + return node + elif self.scope_type != 'cclass' or self.scope_node.visibility != "extern": + # at the moment cdef functions are very restricted in what decorators they can take + # so it's simple to test for the small number of allowed decorators.... + if not (len(node.decorators) == 1 and node.decorators[0].decorator.is_name and + node.decorators[0].decorator.name == "staticmethod"): + error(node.decorators[0].pos, "Cdef functions cannot take arbitrary decorators.") return node ret_node = node diff --git a/tests/errors/cdef_func_decorators.pyx b/tests/errors/cdef_func_decorators.pyx new file mode 100644 index 000000000..e249b2e97 --- /dev/null +++ b/tests/errors/cdef_func_decorators.pyx @@ -0,0 +1,39 @@ +# mode: error +# tag: decorator + +from functools import wraps + +@wraps +cdef cant_be_decoratored(): + pass + +@wraps +cpdef also_cant_be_decorated(): + pass + +cdef class C: + @wraps + cdef still_cant_be_decorated(self): + pass + + @property + cdef property_only_works_for_extern_classes(self): + pass + + @wraps + cpdef also_still_cant_be_decorated(self): + pass + + @wraps + @wraps + cdef two_is_just_as_bad_as_one(self): + pass + +_ERRORS = """ +6:0: Cdef functions cannot take arbitrary decorators. +10:0: Cdef functions cannot take arbitrary decorators. +15:4: Cdef functions cannot take arbitrary decorators. +19:4: Cdef functions cannot take arbitrary decorators. +23:4: Cdef functions cannot take arbitrary decorators. +27:4: Cdef functions cannot take arbitrary decorators. +""" -- cgit v1.2.1