[pypy-commit] cffi default: Reimplement vengine_gen returning incomplete structs.
arigo
noreply at buildbot.pypy.org
Fri Apr 24 11:06:15 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1788:e4b22b167187
Date: 2015-04-24 11:06 +0200
http://bitbucket.org/cffi/cffi/changeset/e4b22b167187/
Log: Reimplement vengine_gen returning incomplete structs.
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