Inline function definitions in pxd files
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Thu, 27 Nov 2008 18:29:12 +0000 (19:29 +0100)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Thu, 27 Nov 2008 18:29:12 +0000 (19:29 +0100)
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Symtab.py
tests/errors/e_func_in_pxd.pyx
tests/errors/e_func_in_pxd_support.pxd
tests/run/inlinepxd.pxd [new file with mode: 0644]
tests/run/inlinepxd.pyx [new file with mode: 0644]
tests/run/inlinepxd_support.pxd [new file with mode: 0644]

index 6dcff8482c8d0513a1646a4f9c65bcac3ce47311..cffc0b6a06df29e67b6aca0d83527ccae1836871 100644 (file)
@@ -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:
index 5cf0e39d177030d779c7c9c9ff5c8e209dc06858..7982bfb584c40cc0e2850e45db84b141eae55fa2 100644 (file)
@@ -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:
index 32669ff102b1358cd7a887c66e79eeb34909ef53..b9e03d15a67689fbc73118e0c75fb34436f9d98d 100644 (file)
@@ -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
index 8dbf8b611e5d5dddfaf4720e25dad50701aaef94..0f3388d171907c98bb0d7c699cd94c47e71706ae 100644 (file)
@@ -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'
index beef5a0ec75efb1824e430609e9265c29b33203b..e8a158c393ce726a7d25feea20f9ffba168432a2 100644 (file)
@@ -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'
 """
index 001e07017466ca60664ffb63e984eb548fc07787..e5c6abae4d00b6e358384d267d25dded1f2cc03e 100644 (file)
@@ -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 (file)
index 0000000..1b84405
--- /dev/null
@@ -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 (file)
index 0000000..8220fa0
--- /dev/null
@@ -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 (file)
index 0000000..e7b745d
--- /dev/null
@@ -0,0 +1,3 @@
+
+cdef inline int my_add(int a, int b, int c):
+    return a + b + c