From: Lisandro Dalcin Date: Sat, 16 May 2009 23:10:35 +0000 (-0300) Subject: add compiler directive for user-defined function calling conventions X-Git-Tag: 0.11.2.rc1~4 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=57f327c1989a4db8dd4f60ea418a87e4e9fbcc9f;p=cython.git add compiler directive for user-defined function calling conventions --- diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 802cc09b..32be4c71 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -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") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 2a1a18c9..4e1c8606 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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) diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 52e13311..a5d70fd5 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -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 diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index c0961ef3..1f3bf7d2 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -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, diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 7fcf13ab..9de6e6f5 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -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 == '(' diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index de089858..d93249cb 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -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 diff --git a/tests/compile/callingconvention.pyx b/tests/compile/callingconvention.pyx index 6befb366..cfca6822 100644 --- a/tests/compile/callingconvention.pyx +++ b/tests/compile/callingconvention.pyx @@ -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 index 00000000..b4cd0409 --- /dev/null +++ b/tests/errors/e_callspec.pyx @@ -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)'