Commit 6005320d authored by Stefan Behnel's avatar Stefan Behnel

Give a better parser error message when defining cdef modifiers on def functions.

See #2529.
parent 271d2505
...@@ -182,6 +182,7 @@ cdef p_c_modifiers(PyrexScanner s) ...@@ -182,6 +182,7 @@ cdef p_c_modifiers(PyrexScanner s)
cdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx) cdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
cdef p_ctypedef_statement(PyrexScanner s, ctx) cdef p_ctypedef_statement(PyrexScanner s, ctx)
cdef p_decorators(PyrexScanner s) cdef p_decorators(PyrexScanner s)
cdef _reject_cdef_modifier_in_py(PyrexScanner s, name)
cdef p_def_statement(PyrexScanner s, list decorators=*, bint is_async_def=*) cdef p_def_statement(PyrexScanner s, list decorators=*, bint is_async_def=*)
cdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *) cdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
cdef p_py_arg_decl(PyrexScanner s, bint annotated = *) cdef p_py_arg_decl(PyrexScanner s, bint annotated = *)
......
...@@ -13,7 +13,8 @@ cython.declare(Nodes=object, ExprNodes=object, EncodedString=object, ...@@ -13,7 +13,8 @@ cython.declare(Nodes=object, ExprNodes=object, EncodedString=object,
Future=object, Options=object, error=object, warning=object, Future=object, Options=object, error=object, warning=object,
Builtin=object, ModuleNode=object, Utils=object, _unicode=object, _bytes=object, Builtin=object, ModuleNode=object, Utils=object, _unicode=object, _bytes=object,
re=object, sys=object, _parse_escape_sequences=object, _parse_escape_sequences_raw=object, re=object, sys=object, _parse_escape_sequences=object, _parse_escape_sequences_raw=object,
partial=object, reduce=object, _IS_PY3=cython.bint, _IS_2BYTE_UNICODE=cython.bint) partial=object, reduce=object, _IS_PY3=cython.bint, _IS_2BYTE_UNICODE=cython.bint,
_CDEF_MODIFIERS=tuple)
from io import StringIO from io import StringIO
import re import re
...@@ -35,6 +36,7 @@ from . import Options ...@@ -35,6 +36,7 @@ from . import Options
_IS_PY3 = sys.version_info[0] >= 3 _IS_PY3 = sys.version_info[0] >= 3
_IS_2BYTE_UNICODE = sys.maxunicode == 0xffff _IS_2BYTE_UNICODE = sys.maxunicode == 0xffff
_CDEF_MODIFIERS = ('inline', 'nogil', 'api')
class Ctx(object): class Ctx(object):
...@@ -3350,6 +3352,16 @@ def p_decorators(s): ...@@ -3350,6 +3352,16 @@ def p_decorators(s):
return decorators return decorators
def _reject_cdef_modifier_in_py(s, name):
"""Step over incorrectly placed cdef modifiers (@see _CDEF_MODIFIERS) to provide a good error message for them.
"""
if s.sy == 'IDENT' and name in _CDEF_MODIFIERS:
# Special enough to provide a good error message.
s.error("Cannot use cdef modifier '%s' in Python function signature. Use a decorator instead." % name, fatal=False)
return p_ident(s) # Keep going, in case there are other errors.
return name
def p_def_statement(s, decorators=None, is_async_def=False): def p_def_statement(s, decorators=None, is_async_def=False):
# s.sy == 'def' # s.sy == 'def'
pos = s.position() pos = s.position()
...@@ -3357,16 +3369,16 @@ def p_def_statement(s, decorators=None, is_async_def=False): ...@@ -3357,16 +3369,16 @@ def p_def_statement(s, decorators=None, is_async_def=False):
if is_async_def: if is_async_def:
s.enter_async() s.enter_async()
s.next() s.next()
name = p_ident(s) name = _reject_cdef_modifier_in_py(s, p_ident(s))
s.expect('(') s.expect('(')
args, star_arg, starstar_arg = p_varargslist(s, terminator=')') args, star_arg, starstar_arg = p_varargslist(s, terminator=')')
s.expect(')') s.expect(')')
if p_nogil(s): _reject_cdef_modifier_in_py(s, s.systring)
error(pos, "Python function cannot be declared nogil")
return_type_annotation = None return_type_annotation = None
if s.sy == '->': if s.sy == '->':
s.next() s.next()
return_type_annotation = p_test(s) return_type_annotation = p_test(s)
_reject_cdef_modifier_in_py(s, s.systring)
doc, body = p_suite_with_docstring(s, Ctx(level='function')) doc, body = p_suite_with_docstring(s, Ctx(level='function'))
if is_async_def: if is_async_def:
......
# mode: error
def test() nogil:
pass
_ERRORS = """
3:0: Python function cannot be declared nogil
"""
# mode: error
# tag: syntax
def inline func() -> int:
pass
def api func() -> int:
pass
def nogil func() -> int:
pass
def func() nogil:
pass
_ERRORS = u"""
4:11: Cannot use cdef modifier 'inline' in Python function signature. Use a decorator instead.
7:8: Cannot use cdef modifier 'api' in Python function signature. Use a decorator instead.
10:10: Cannot use cdef modifier 'nogil' in Python function signature. Use a decorator instead.
13:11: Cannot use cdef modifier 'nogil' in Python function signature. Use a decorator instead.
"""
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment