add compiler directive for user-defined function calling conventions
authorLisandro Dalcin <dalcinl@gmail.com>
Sat, 16 May 2009 23:10:35 +0000 (20:10 -0300)
committerLisandro Dalcin <dalcinl@gmail.com>
Sat, 16 May 2009 23:10:35 +0000 (20:10 -0300)
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/Options.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
tests/compile/callingconvention.pyx
tests/errors/e_callspec.pyx [new file with mode: 0644]

index 802cc09bb2b7916dd3b7c4c09b473d614edc7290..32be4c715e26ea1f2c0345ffdc7960d0f949cf10 100644 (file)
@@ -530,6 +530,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln("  #ifndef __cdecl")
         code.putln("    #define __cdecl")
         code.putln("  #endif")
+        code.putln("  #ifndef __fastcall")
+        code.putln("    #define __fastcall")
+        code.putln("  #endif")
         code.putln("#else")
         code.putln("  #define _USE_MATH_DEFINES")
         code.putln("#endif")
index 2a1a18c993a68e87fc53364406e17f879dd3df14..4e1c860617e9d9a50bbf17d44993e334a21eeef6 100644 (file)
@@ -603,6 +603,13 @@ class CFuncDeclaratorNode(CDeclaratorNode):
             nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
         if self.optional_arg_count:
             func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type)
+        callspec = env.directives['callspec']
+        if callspec:
+            current = func_type.calling_convention
+            if current and current != callspec:
+                error(self.pos, "cannot have both '%s' and '%s' "
+                      "calling conventions" % (current, callspec))
+            func_type.calling_convention = callspec
         return self.base.analyse(func_type, env)
 
 
index 52e1331126fc746f5a2ed2abf6e695ca8ba81269..a5d70fd58ae302c2c4e6afb1b60cb86b02fede16 100644 (file)
@@ -66,6 +66,7 @@ option_defaults = {
     'always_allow_keywords': False,
     'wraparound' : True,
     'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this...
+    'callspec' : "",
 }
 
 # Override types possibilities above, if needed
index c0961ef37b232a724f8f689d22d31960038cadc8..1f3bf7d232383df7f34bbfc54f59195915c84c7f 100644 (file)
@@ -435,6 +435,11 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
                         raise PostParseError(dec.function.pos,
                             'The %s option takes one compile-time boolean argument' % optname)
                     return (optname, args[0].value)
+                elif optiontype is str:
+                    if kwds is not None or len(args) != 1 or not isinstance(args[0], StringNode):
+                        raise PostParseError(dec.function.pos,
+                            'The %s option takes one compile-time string argument' % optname)
+                    return (optname, args[0].value)
                 elif optiontype is dict:
                     if len(args) != 0:
                         raise PostParseError(dec.function.pos,
index 7fcf13abe6aec544fa5b1ccd6334bcafbc13ff28..9de6e6f55f39d0fd442476e22ae537fe9b44acd5 100644 (file)
@@ -1675,7 +1675,7 @@ def p_calling_convention(s):
     else:
         return ""
 
-calling_convention_words = ("__stdcall", "__cdecl")
+calling_convention_words = ("__stdcall", "__cdecl", "__fastcall")
 
 def p_c_complex_base_type(s):
     # s.sy == '('
index de089858cde1d50d97ab209f922fd3ec10917b0f..d93249cb1f72cc703c765506fd724dc698d3272f 100644 (file)
@@ -1125,6 +1125,15 @@ class CFuncType(CType):
         return 1
 
     def same_calling_convention_as(self, other):
+        ## XXX Under discussion ...
+        ## callspec_words = ("__stdcall", "__cdecl", "__fastcall")
+        ## cs1 = self.calling_convention
+        ## cs2 = other.calling_convention
+        ## if (cs1 in callspec_words or
+        ##     cs2 in callspec_words):
+        ##     return cs1 == cs2
+        ## else:
+        ##     return True
         sc1 = self.calling_convention == '__stdcall'
         sc2 = other.calling_convention == '__stdcall'
         return sc1 == sc2
index 6befb3664f2bd8a6525f6046836e8c8352d29d2a..cfca6822854ce681243777f12ab264e85aa9fd34 100644 (file)
@@ -1,7 +1,22 @@
-cdef extern int f()
+cdef extern int f1()
 
-cdef extern int __stdcall g()
+cdef extern int __cdecl f2()
 
-cdef extern int __cdecl h()
+cdef extern int __stdcall f3()
 
-cdef extern int (__stdcall *p)()
+cdef extern int __fastcall f4()
+
+
+cdef extern int (*p1)()
+
+cdef extern int (__cdecl *p2)()
+
+cdef extern int (__stdcall *p3)()
+
+cdef extern int (__fastcall *p4)()
+
+
+p1 = f1
+p2 = f2
+p3 = f3
+p4 = f4
diff --git a/tests/errors/e_callspec.pyx b/tests/errors/e_callspec.pyx
new file mode 100644 (file)
index 0000000..b4cd040
--- /dev/null
@@ -0,0 +1,48 @@
+cimport cython
+
+@cython.callspec("")
+cdef void h1(): pass
+
+@cython.callspec("__cdecl")
+cdef void __cdecl h2(): pass
+
+@cython.callspec("__stdcall")
+cdef void __stdcall h3(): pass
+
+@cython.callspec("__fastcall")
+cdef void __fastcall h4(): pass
+
+@cython.callspec("__cdecl")
+cdef void __stdcall h5(): pass # fail
+
+@cython.callspec("__cdecl")
+cdef void __fastcall h6(): pass # fail
+
+cdef void (*p1)()
+cdef void (__cdecl *p2)()
+cdef void (__stdcall *p3)()
+cdef void (__fastcall *p4)()
+
+p1 = h1
+p2 = h2
+p3 = h3
+p4 = h4
+
+#p1 = h2 # fail
+#p1 = h3 # fail
+#p1 = h4 # fail
+
+#p2 = h1 # fail
+#p2 = h3 # fail
+#p2 = h4 # fail
+
+_ERRORS = u"""
+16:22: cannot have both '__stdcall' and '__cdecl' calling conventions
+19:23: cannot have both '__fastcall' and '__cdecl' calling conventions
+"""
+#31:14: Cannot assign type 'void (__cdecl )(void)' to 'void (*)(void)'
+#32:14: Cannot assign type 'void (__stdcall )(void)' to 'void (*)(void)'
+#33:14: Cannot assign type 'void (__fastcall )(void)' to 'void (*)(void)'
+#35:14: Cannot assign type 'void (void)' to 'void (__cdecl *)(void)'
+#36:14: Cannot assign type 'void (__stdcall )(void)' to 'void (__cdecl *)(void)'
+#37:14: Cannot assign type 'void (__fastcall )(void)' to 'void (__cdecl *)(void)'