[pypy-commit] cffi cffi-1.0: hg merge default

arigo noreply at buildbot.pypy.org
Fri Apr 24 11:06:38 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1789:111b2f47845a
Date: 2015-04-24 11:07 +0200
http://bitbucket.org/cffi/cffi/changeset/111b2f47845a/

Log:	hg merge default

diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -140,16 +140,6 @@
         replace_with = self._base_pattern % (', '.join(reprargs),)
         self.c_name_with_marker = (
             self.result.c_name_with_marker.replace('&', replace_with))
-        #
-        if isinstance(result, StructOrUnion) and result.partial:
-            from .ffiplatform import VerificationError
-            raise VerificationError(
-                '%s: the %s is a struct with "...;", which is not '
-                'supported as return type (how to call it with '
-                'libffi depends on possibly-omitted fields).  '
-                'Workaround: write a wrapper function which takes '
-                'a pointer-to-struct as extra argument and writes '
-                'the result there' % (self, result))
 
 
 class RawFunctionType(BaseFunctionType):
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -149,15 +149,21 @@
         context = 'argument of %s' % name
         arglist = [type.get_c_name(' %s' % arg, context)
                    for type, arg in zip(tp.args, argnames)]
+        tpresult = tp.result
+        if isinstance(tpresult, model.StructOrUnion):
+            arglist.insert(0, tpresult.get_c_name(' *r', context))
+            tpresult = model.void_type
         arglist = ', '.join(arglist) or 'void'
         wrappername = '_cffi_f_%s' % name
         self.export_symbols.append(wrappername)
         funcdecl = ' %s(%s)' % (wrappername, arglist)
         context = 'result of %s' % name
-        prnt(tp.result.get_c_name(funcdecl, context))
+        prnt(tpresult.get_c_name(funcdecl, context))
         prnt('{')
         #
-        if not isinstance(tp.result, model.VoidType):
+        if isinstance(tp.result, model.StructOrUnion):
+            result_code = '*r = '
+        elif not isinstance(tp.result, model.VoidType):
             result_code = 'return '
         else:
             result_code = ''
@@ -174,15 +180,22 @@
         else:
             indirections = []
             base_tp = tp
-            if any(isinstance(typ, model.StructOrUnion) for typ in tp.args):
+            if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)
+                    or isinstance(tp.result, model.StructOrUnion)):
                 indirect_args = []
                 for i, typ in enumerate(tp.args):
                     if isinstance(typ, model.StructOrUnion):
                         typ = model.PointerType(typ)
                         indirections.append((i, typ))
                     indirect_args.append(typ)
+                indirect_result = tp.result
+                if isinstance(indirect_result, model.StructOrUnion):
+                    indirect_result = model.PointerType(indirect_result)
+                    indirect_args.insert(0, indirect_result)
+                    indirections.insert(0, ("result", indirect_result))
+                    indirect_result = model.void_type
                 tp = model.FunctionPtrType(tuple(indirect_args),
-                                           tp.result, tp.ellipsis)
+                                           indirect_result, tp.ellipsis)
             BFunc = self.ffi._get_cached_btype(tp)
             wrappername = '_cffi_f_%s' % name
             newfunction = module.load_function(BFunc, wrappername)
@@ -195,9 +208,16 @@
     def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):
         backend = self.ffi._backend
         BType = self.ffi._get_cached_btype(tp)
-        def newfunc(*args):
-            args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
-            return oldfunc(*args)
+        if i == "result":
+            ffi = self.ffi
+            def newfunc(*args):
+                res = ffi.new(BType)
+                oldfunc(res, *args)
+                return res[0]
+        else:
+            def newfunc(*args):
+                args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
+                return oldfunc(*args)
         newfunc._cffi_base_type = base_tp
         return newfunc
 
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -1233,13 +1233,11 @@
         py.test.skip('Segfaults on mips64el')
     # XXX bad abuse of "struct { ...; }".  It only works a bit by chance
     # anyway.  XXX think about something better :-(
-    # ...in fact, it is no longer supported: likely crashes in vgen
     ffi = FFI()
-    py.test.raises(VerificationError, ffi.cdef, """
+    ffi.cdef("""
         typedef struct { ...; } myhandle_t;
         myhandle_t foo(void);
     """)
-    py.test.skip("XXX reimplement maybe?")
     lib = ffi.verify("""
         typedef short myhandle_t;
         myhandle_t foo(void) { return 42; }
@@ -1248,7 +1246,6 @@
     assert ffi.sizeof(h) == ffi.sizeof("short")
 
 def test_return_partial_struct():
-    py.test.skip("not implemented")
     ffi = FFI()
     ffi.cdef("""
         typedef struct { int x; ...; } foo_t;
@@ -1262,6 +1259,26 @@
     assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
     assert h.x == 81
 
+def test_take_and_return_partial_structs():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef struct { int x; ...; } foo_t;
+        foo_t foo(foo_t, foo_t);
+    """)
+    lib = ffi.verify("""
+        typedef struct { int y, x; } foo_t;
+        foo_t foo(foo_t a, foo_t b) {
+            foo_t r = { 100, a.x * 5 + b.x * 7 };
+            return r;
+        }
+    """)
+    args = ffi.new("foo_t[3]")
+    args[0].x = 1000
+    args[2].x = -498
+    h = lib.foo(args[0], args[2])
+    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
+    assert h.x == 1000 * 5 - 498 * 7
+
 def test_cannot_name_struct_type():
     ffi = FFI()
     ffi.cdef("typedef struct { int x; } *sp; void foo(sp);")


More information about the pypy-commit mailing list