[pypy-commit] cffi cffi-1.0: The ``cffi_modules = ["module:ffi"]`` can now also name a global

arigo noreply at buildbot.pypy.org
Sat May 9 14:27:38 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1946:13a728b641ba
Date: 2015-05-09 14:28 +0200
http://bitbucket.org/cffi/cffi/changeset/13a728b641ba/

Log:	The ``cffi_modules = ["module:ffi"]`` can now also name a global
	function instead of an FFI object; the function is then called with
	no arguments.

diff --git a/_cffi1/recompiler.py b/_cffi1/recompiler.py
--- a/_cffi1/recompiler.py
+++ b/_cffi1/recompiler.py
@@ -386,16 +386,16 @@
             argname = 'arg0'
         else:
             argname = 'args'
+        #
         prnt('#ifndef PYPY_VERSION')        # ------------------------------
+        #
         prnt('static PyObject *')
         prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
         prnt('{')
         #
         context = 'argument of %s' % name
-        arguments = []
         for i, type in enumerate(tp.args):
             arg = type.get_c_name(' x%d' % i, context)
-            arguments.append(arg)
             prnt('  %s;' % arg)
         #
         localvars = set()
@@ -432,8 +432,7 @@
         prnt('  _cffi_restore_errno();')
         call_arguments = ['x%d' % i for i in range(len(tp.args))]
         call_arguments = ', '.join(call_arguments)
-        call_code = '  { %s%s(%s); }' % (result_code, name, call_arguments)
-        prnt(call_code)
+        prnt('  { %s%s(%s); }' % (result_code, name, call_arguments))
         prnt('  _cffi_save_errno();')
         prnt('  Py_END_ALLOW_THREADS')
         prnt()
@@ -448,7 +447,21 @@
             prnt('  Py_INCREF(Py_None);')
             prnt('  return Py_None;')
         prnt('}')
+        #
         prnt('#else')        # ------------------------------
+        #
+        # the PyPy version: need to replace struct/union arguments with
+        # pointers, and if the result is a struct/union, insert a first
+        # arg that is a pointer to the result.
+        arguments = []
+        call_arguments = []
+        for i, type in enumerate(tp.args):
+            indirection = ''
+            if isinstance(type, model.StructOrUnion):
+                indirection = '*'
+            arg = type.get_c_name(' %sx%d' % (indirection, i), context)
+            arguments.append(arg)
+            call_arguments.append('%sx%d' % (indirection, i))
         repr_arguments = ', '.join(arguments)
         repr_arguments = repr_arguments or 'void'
         name_and_arguments = '_cffi_f_%s(%s)' % (name, repr_arguments)
@@ -456,10 +469,12 @@
         prnt('{')
         if result_decl:
             prnt(result_decl)
-        prnt(call_code)
+        call_arguments = ', '.join(call_arguments)
+        prnt('  { %s%s(%s); }' % (result_code, name, call_arguments))
         if result_decl:
             prnt('  return result;')
         prnt('}')
+        #
         prnt('#endif')        # ------------------------------
         prnt()
 
diff --git a/_cffi1/setuptools_ext.py b/_cffi1/setuptools_ext.py
--- a/_cffi1/setuptools_ext.py
+++ b/_cffi1/setuptools_ext.py
@@ -34,6 +34,8 @@
         error("%r: object %r not found in module" % (mod_spec,
                                                      ffi_var_name))
     if not isinstance(ffi, FFI):
+        ffi = ffi()      # maybe it's a function instead of directly an ffi
+    if not isinstance(ffi, FFI):
         error("%r is not an FFI instance (got %r)" % (mod_spec,
                                                       type(ffi).__name__))
     if not hasattr(ffi, '_assigned_source'):
diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py
--- a/_cffi1/test_recompiler.py
+++ b/_cffi1/test_recompiler.py
@@ -627,3 +627,24 @@
     lib = verify(ffi, 'test_math_sin_unicode', unicode('#include <math.h>'),
                  libraries=[unicode(lib_m)])
     assert lib.cos(1.43) == math.cos(1.43)
+
+def test_incomplete_struct_as_arg():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int x; ...; }; int f(struct foo_s);")
+    lib = verify(ffi, "test_incomplete_struct_as_arg",
+                 "struct foo_s { int a, x, z; };\n"
+                 "int f(struct foo_s s) { return s.x * 2; }")
+    s = ffi.new("struct foo_s *", [21])
+    assert s.x == 21
+    assert ffi.sizeof(s[0]) == 12
+    assert ffi.offsetof(ffi.typeof(s), 'x') == 4
+    assert lib.f(s[0]) == 42
+
+def test_incomplete_struct_as_result():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int x; ...; }; struct foo_s f(int);")
+    lib = verify(ffi, "test_incomplete_struct_as_result",
+            "struct foo_s { int a, x, z; };\n"
+            "struct foo_s f(int x) { struct foo_s r; r.x = x * 2; return r; }")
+    s = lib.f(21)
+    assert s.x == 42
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -4255,8 +4255,9 @@
             return NULL;
         if (ct->ct_flags & CT_CUSTOM_FIELD_POS) {
             PyErr_SetString(PyExc_TypeError,
-                "cannot pass as an argument a struct that was completed "
-                "with verify() (see _cffi_backend.c for details of why)");
+                "argument or return value is a struct (not pointer to struct) "
+                "which was declared with \"...;\" --- but the C calling "
+                "convention can depend on the missing fields");
             return NULL;
         }
 


More information about the pypy-commit mailing list