From 4b4d3f43386b13b357d46438e2dd250c3c92c65b Mon Sep 17 00:00:00 2001 From: Dag Sverre Seljebotn Date: Thu, 27 Nov 2008 19:29:12 +0100 Subject: [PATCH] Inline function definitions in pxd files --- Cython/Compiler/ModuleNode.py | 4 +- Cython/Compiler/Nodes.py | 6 ++- Cython/Compiler/ParseTreeTransforms.py | 51 ++++++++++++++++---------- Cython/Compiler/Symtab.py | 3 ++ tests/errors/e_func_in_pxd.pyx | 4 +- tests/errors/e_func_in_pxd_support.pxd | 6 +++ tests/run/inlinepxd.pxd | 3 ++ tests/run/inlinepxd.pyx | 20 ++++++++++ tests/run/inlinepxd_support.pxd | 3 ++ 9 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 tests/run/inlinepxd.pxd create mode 100644 tests/run/inlinepxd.pyx create mode 100644 tests/run/inlinepxd_support.pxd diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 6dcff848..cffc0b6a 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -757,8 +757,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_cfunction_predeclarations(self, env, code, definition): for entry in env.cfunc_entries: - if not entry.in_cinclude and (definition - or entry.defined_in_pxd or entry.visibility == 'extern'): + if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition + or entry.defined_in_pxd or entry.visibility == 'extern')): if entry.visibility in ('public', 'extern'): dll_linkage = "DL_EXPORT" else: diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 5cf0e39d..7982bfb5 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1212,9 +1212,12 @@ class CFuncDefNode(FuncDefNode): # type CFuncType # py_func wrapper for calling from Python # overridable whether or not this is a cpdef function + # inline_in_pxd whether this is an inline function in a pxd file child_attrs = ["base_type", "declarator", "body", "py_func"] - + + inline_in_pxd = False + def unqualified_name(self): return self.entry.name @@ -1251,6 +1254,7 @@ class CFuncDefNode(FuncDefNode): cname = cname, visibility = self.visibility, defining = self.body is not None, api = self.api, modifiers = self.modifiers) + self.entry.inline_func_in_pxd = self.inline_in_pxd self.return_type = type.return_type if self.overridable: diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 32669ff1..b9e03d15 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -212,8 +212,12 @@ class PxdPostParse(CythonTransform): - "def" functions are let through only if they fill the getbuffer/releasebuffer slots + + - cdef functions are let through only if they are on the + top level and are declared "inline" """ - ERR_FUNCDEF_NOT_ALLOWED = 'function definition not allowed here' + ERR_INLINE_ONLY = "function definition in pxd file must be declared 'cdef inline'" + ERR_NOGO_WITH_INLINE = "inline function definition in pxd file cannot be '%s'" def __call__(self, node): self.scope_type = 'pxd' @@ -229,30 +233,37 @@ class PxdPostParse(CythonTransform): def visit_FuncDefNode(self, node): # FuncDefNode always come with an implementation (without # an imp they are CVarDefNodes..) - ok = False + err = self.ERR_INLINE_ONLY if (isinstance(node, DefNode) and self.scope_type == 'cclass' and node.name in ('__getbuffer__', '__releasebuffer__')): - ok = True + err = None # allow these slots if isinstance(node, CFuncDefNode): - ok = True - for stat in node.body.stats: - if not isinstance(stat, CVarDefNode): - ok = False - break - node = CVarDefNode(node.pos, - visibility = node.visibility, - base_type = node.base_type, - declarators = [node.declarator], - in_pxd = True, - api = node.api, - overridable = node.overridable, - pxd_locals = node.body.stats) - - if not ok: - self.context.nonfatal_error(PostParseError(node.pos, - self.ERR_FUNCDEF_NOT_ALLOWED)) + if u'inline' in node.modifiers and self.scope_type == 'pxd': + node.inline_in_pxd = True + if node.visibility != 'private': + err = self.ERR_NOGO_WITH_INLINE % node.visibility + elif node.api: + err = self.ERR_NOGO_WITH_INLINE % 'api' + else: + err = None # allow inline function + else: + err = None + for stat in node.body.stats: + if not isinstance(stat, CVarDefNode): + err = self.ERR_INLINE_ONLY + break + node = CVarDefNode(node.pos, + visibility = node.visibility, + base_type = node.base_type, + declarators = [node.declarator], + in_pxd = True, + api = node.api, + overridable = node.overridable, + pxd_locals = node.body.stats) + if err: + self.context.nonfatal_error(PostParseError(node.pos, err)) return None else: return node diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 8dbf8b61..0f3388d1 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -97,7 +97,10 @@ class Entry: # utility_code string Utility code needed when this entry is used # # buffer_aux BufferAux or None Extra information needed for buffer variables + # inline_func_in_pxd boolean Hacky special case for inline function in pxd file. + # Ideally this should not be necesarry. + inline_func_in_pxd = False borrowed = 0 init = "" visibility = 'private' diff --git a/tests/errors/e_func_in_pxd.pyx b/tests/errors/e_func_in_pxd.pyx index beef5a0e..e8a158c3 100644 --- a/tests/errors/e_func_in_pxd.pyx +++ b/tests/errors/e_func_in_pxd.pyx @@ -1,5 +1,7 @@ cimport e_func_in_pxd_support _ERRORS = u""" -1:5: function definition not allowed here +1:5: function definition in pxd file must be declared 'cdef inline' +4:5: inline function definition in pxd file cannot be 'public' +7:5: inline function definition in pxd file cannot be 'api' """ diff --git a/tests/errors/e_func_in_pxd_support.pxd b/tests/errors/e_func_in_pxd_support.pxd index 001e0701..e5c6abae 100644 --- a/tests/errors/e_func_in_pxd_support.pxd +++ b/tests/errors/e_func_in_pxd_support.pxd @@ -1,2 +1,8 @@ cdef foo(): return 1 + +cdef public inline foo2(): + return 1 + +cdef api inline foo3(): + return 1 diff --git a/tests/run/inlinepxd.pxd b/tests/run/inlinepxd.pxd new file mode 100644 index 00000000..1b84405a --- /dev/null +++ b/tests/run/inlinepxd.pxd @@ -0,0 +1,3 @@ + +cdef inline int my_add(int a, int b): + return a + b diff --git a/tests/run/inlinepxd.pyx b/tests/run/inlinepxd.pyx new file mode 100644 index 00000000..8220fa08 --- /dev/null +++ b/tests/run/inlinepxd.pyx @@ -0,0 +1,20 @@ +""" +>>> f() +3 +>>> g() +6 +>>> h() +6 +""" + +cimport inlinepxd_support +from inlinepxd_support cimport my_add as my_add3 + +def f(): + return my_add(1, 2) + +def g(): + return inlinepxd_support.my_add(1, 2, 3) + +def h(): + return my_add3(1, 2, 3) diff --git a/tests/run/inlinepxd_support.pxd b/tests/run/inlinepxd_support.pxd new file mode 100644 index 00000000..e7b745d6 --- /dev/null +++ b/tests/run/inlinepxd_support.pxd @@ -0,0 +1,3 @@ + +cdef inline int my_add(int a, int b, int c): + return a + b + c -- 2.26.2