[pypy-commit] pypy default: update to cffi 1.9.2
arigo
pypy.commits at gmail.com
Thu Dec 22 11:54:38 EST 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r89214:29df4aac463b
Date: 2016-12-22 17:51 +0100
http://bitbucket.org/pypy/pypy/changeset/29df4aac463b/
Log: update to cffi 1.9.2
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.9.1"
-__version_info__ = (1, 9, 1)
+__version__ = "1.9.2"
+__version_info__ = (1, 9, 2)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
--- a/lib_pypy/cffi/_embedding.h
+++ b/lib_pypy/cffi/_embedding.h
@@ -233,7 +233,7 @@
f = PySys_GetObject((char *)"stderr");
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.9.1"
+ "\ncompiled with cffi version: 1.9.2"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -3,7 +3,7 @@
from rpython.rlib import rdynload, clibffi
from rpython.rtyper.lltypesystem import rffi
-VERSION = "1.9.1"
+VERSION = "1.9.2"
FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
try:
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -17,7 +17,7 @@
from pypy.module._cffi_backend.ctypeobj import W_CType
from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase, W_CTypePointer
from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
-from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct
+from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct, W_CTypeUnion
from pypy.module._cffi_backend.ctypeprim import (W_CTypePrimitiveSigned,
W_CTypePrimitiveUnsigned, W_CTypePrimitiveCharOrUniChar,
W_CTypePrimitiveFloat, W_CTypePrimitiveLongDouble)
@@ -231,6 +231,11 @@
return cifbuilder.fb_struct_ffi_type(self, is_result_type)
return _missing_ffi_type(self, cifbuilder, is_result_type)
+def _union_ffi_type(self, cifbuilder, is_result_type):
+ if self.size >= 0: # only for a better error message
+ return cifbuilder.fb_union_ffi_type(self, is_result_type)
+ return _missing_ffi_type(self, cifbuilder, is_result_type)
+
def _primsigned_ffi_type(self, cifbuilder, is_result_type):
size = self.size
if size == 1: return clibffi.ffi_type_sint8
@@ -266,6 +271,7 @@
W_CType._get_ffi_type = _missing_ffi_type
W_CTypeStruct._get_ffi_type = _struct_ffi_type
+W_CTypeUnion._get_ffi_type = _union_ffi_type
W_CTypePrimitiveSigned._get_ffi_type = _primsigned_ffi_type
W_CTypePrimitiveCharOrUniChar._get_ffi_type = _primunsigned_ffi_type
W_CTypePrimitiveUnsigned._get_ffi_type = _primunsigned_ffi_type
@@ -276,6 +282,12 @@
# ----------
+_SUPPORTED_IN_API_MODE = (
+ " are only supported as %s if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder"
+ ".cdef()+ffibuilder.set_source() and not taking a final '...' "
+ "argument)")
+
class CifDescrBuilder(object):
rawmem = lltype.nullptr(rffi.CCHARP.TO)
@@ -297,6 +309,20 @@
def fb_fill_type(self, ctype, is_result_type):
return ctype._get_ffi_type(self, is_result_type)
+ def fb_unsupported(self, ctype, is_result_type, detail):
+ place = "return value" if is_result_type else "argument"
+ raise oefmt(self.space.w_NotImplementedError,
+ "ctype '%s' not supported as %s. %s. "
+ "Such structs" + _SUPPORTED_IN_API_MODE,
+ ctype.name, place, detail, place)
+
+ def fb_union_ffi_type(self, ctype, is_result_type=False):
+ place = "return value" if is_result_type else "argument"
+ raise oefmt(self.space.w_NotImplementedError,
+ "ctype '%s' not supported as %s by libffi. "
+ "Unions" + _SUPPORTED_IN_API_MODE,
+ ctype.name, place, place)
+
def fb_struct_ffi_type(self, ctype, is_result_type=False):
# We can't pass a struct that was completed by verify().
# Issue: assume verify() is given "struct { long b; ...; }".
@@ -309,37 +335,40 @@
# Another reason for 'custom_field_pos' would be anonymous
# nested structures: we lost the information about having it
# here, so better safe (and forbid it) than sorry (and maybe
- # crash).
+ # crash). Note: it seems we only get in this case with
+ # ffi.verify().
space = self.space
ctype.force_lazy_struct()
if ctype._custom_field_pos:
# these NotImplementedErrors may be caught and ignored until
# a real call is made to a function of this type
- place = "return value" if is_result_type else "argument"
- raise oefmt(space.w_NotImplementedError,
- "ctype '%s' not supported as %s (it is a struct declared "
- "with \"...;\", but the C calling convention may depend "
- "on the missing fields)", ctype.name, place)
+ raise self.fb_unsupported(ctype, is_result_type,
+ "It is a struct declared with \"...;\", but the C "
+ "calling convention may depend on the missing fields; "
+ "or, it contains anonymous struct/unions")
+ # Another reason: __attribute__((packed)) is not supported by libffi.
+ if ctype._with_packed_change:
+ raise self.fb_unsupported(ctype, is_result_type,
+ "It is a 'packed' structure, with a different layout than "
+ "expected by libffi")
# walk the fields, expanding arrays into repetitions; first,
# only count how many flattened fields there are
nflat = 0
for i, cf in enumerate(ctype._fields_list):
if cf.is_bitfield():
- place = "return value" if is_result_type else "argument"
- raise oefmt(space.w_NotImplementedError,
- "ctype '%s' not supported as %s"
- " (it is a struct with bit fields)", ctype.name, place)
+ raise self.fb_unsupported(ctype, is_result_type,
+ "It is a struct with bit fields, which libffi does not "
+ "support")
flat = 1
ct = cf.ctype
while isinstance(ct, ctypearray.W_CTypeArray):
flat *= ct.length
ct = ct.ctitem
if flat <= 0:
- place = "return value" if is_result_type else "argument"
- raise oefmt(space.w_NotImplementedError,
- "ctype '%s' not supported as %s (it is a struct"
- " with a zero-length array)", ctype.name, place)
+ raise self.fb_unsupported(ctype, is_result_type,
+ "It is a struct with a zero-length array, which libffi "
+ "does not support")
nflat += flat
if USE_C_LIBFFI_MSVC and is_result_type:
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -34,6 +34,7 @@
_fields_dict = None
_custom_field_pos = False
_with_var_array = False
+ _with_packed_changed = False
def __init__(self, space, name):
W_CType.__init__(self, space, -1, name, len(name))
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -303,6 +303,7 @@
fields_dict = {}
w_ctype._custom_field_pos = False
with_var_array = False
+ with_packed_change = False
for i in range(len(fields_w)):
w_field = fields_w[i]
@@ -333,7 +334,8 @@
#
# update the total alignment requirement, but skip it if the
# field is an anonymous bitfield or if SF_PACKED
- falign = 1 if sflags & SF_PACKED else ftype.alignof()
+ falignorg = ftype.alignof()
+ falign = 1 if sflags & SF_PACKED else falignorg
do_align = True
if (sflags & SF_GCC_ARM_BITFIELDS) == 0 and fbitsize >= 0:
if (sflags & SF_MSVC_BITFIELDS) == 0:
@@ -359,7 +361,10 @@
bs_flag = ctypestruct.W_CField.BS_REGULAR
# align this field to its own 'falign' by inserting padding
+ boffsetorg = (boffset + falignorg*8-1) & ~(falignorg*8-1)
boffset = (boffset + falign*8-1) & ~(falign*8-1)
+ if boffsetorg != boffset:
+ with_packed_change = True
if foffset >= 0:
# a forced field position: ignore the offset just computed,
@@ -372,6 +377,7 @@
if (fname == '' and
isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)):
# a nested anonymous struct or union
+ # note: it seems we only get here with ffi.verify()
srcfield2names = {}
ftype.force_lazy_struct()
for name, srcfld in ftype._fields_dict.items():
@@ -530,6 +536,7 @@
w_ctype._fields_dict = fields_dict
#w_ctype._custom_field_pos = ...set above already
w_ctype._with_var_array = with_var_array
+ w_ctype._with_packed_change = with_packed_change
# ____________________________________________________________
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1,7 +1,7 @@
# ____________________________________________________________
import sys
-assert __version__ == "1.9.1", ("This test_c.py file is for testing a version"
+assert __version__ == "1.9.2", ("This test_c.py file is for testing a version"
" of cffi that differs from the one that we"
" get from 'import _cffi_backend'")
if sys.version_info < (3,):
@@ -1084,9 +1084,13 @@
BFunc = new_function_type((BStruct,), BDouble) # internally not callable
dummy_func = cast(BFunc, 42)
e = py.test.raises(NotImplementedError, dummy_func, "?")
- msg = ("ctype \'struct foo\' not supported as argument (it is a struct "
- 'declared with "...;", but the C calling convention may depend on '
- 'the missing fields)')
+ msg = ("ctype 'struct foo' not supported as argument. It is a struct "
+ 'declared with "...;", but the C calling convention may depend '
+ "on the missing fields; or, it contains anonymous struct/unions. "
+ "Such structs are only supported as argument if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder."
+ "cdef()+ffibuilder.set_source() and not taking a final '...' "
+ "argument)")
assert str(e.value) == msg
def test_new_charp():
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -6,9 +6,9 @@
import pypy.module.cpyext.api # side-effect of pre-importing it
- at unwrap_spec(cdef=str, module_name=str, source=str)
+ at unwrap_spec(cdef=str, module_name=str, source=str, packed=int)
def prepare(space, cdef, module_name, source, w_includes=None,
- w_extra_source=None, w_min_version=None):
+ w_extra_source=None, w_min_version=None, packed=False):
try:
import cffi
from cffi import FFI # <== the system one, which
@@ -47,7 +47,7 @@
ffi = FFI()
for include_ffi_object in includes:
ffi.include(include_ffi_object._test_recompiler_source_ffi)
- ffi.cdef(cdef)
+ ffi.cdef(cdef, packed=packed)
ffi.set_source(module_name, source)
ffi.emit_c_code(c_file)
@@ -1838,3 +1838,149 @@
raises(ffi.error, ffi.sizeof, "vmat_t")
p = ffi.new("vmat_t", 4)
assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int")
+
+ def test_call_with_custom_field_pos(self):
+ ffi, lib = self.prepare("""
+ struct foo { int x; ...; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """, "test_call_with_custom_field_pos", """
+ struct foo { int y, x; };
+ struct foo f(void) {
+ struct foo s = { 40, 200 };
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().x == 200
+ e = raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ 'ctype \'struct foo\' not supported as return value. It is a '
+ 'struct declared with "...;", but the C calling convention may '
+ 'depend on the missing fields; or, it contains anonymous '
+ 'struct/unions. Such structs are only supported '
+ 'as return value if the function is \'API mode\' and non-variadic '
+ '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
+ 'and not taking a final \'...\' argument)')
+
+ def test_call_with_nested_anonymous_struct(self):
+ import sys
+ if sys.platform == 'win32':
+ py.test.skip("needs a GCC extension")
+ ffi, lib = self.prepare("""
+ struct foo { int a; union { int b, c; }; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """, "test_call_with_nested_anonymous_struct", """
+ struct foo { int a; union { int b, c; }; };
+ struct foo f(void) {
+ struct foo s = { 40 };
+ s.b = 200;
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().b == 200
+ e = raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ 'ctype \'struct foo\' not supported as return value. It is a '
+ 'struct declared with "...;", but the C calling convention may '
+ 'depend on the missing fields; or, it contains anonymous '
+ 'struct/unions. Such structs are only supported '
+ 'as return value if the function is \'API mode\' and non-variadic '
+ '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
+ 'and not taking a final \'...\' argument)')
+
+ def test_call_with_bitfield(self):
+ ffi, lib = self.prepare("""
+ struct foo { int x:5; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """, "test_call_with_bitfield", """
+ struct foo { int x:5; };
+ struct foo f(void) {
+ struct foo s = { 11 };
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().x == 11
+ e = raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'struct foo' not supported as return value. It is a struct "
+ "with bit fields, which libffi does not support. Such structs are "
+ "only supported as return value if the function is 'API mode' and "
+ "non-variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
+ "set_source() and not taking a final '...' argument)")
+
+ def test_call_with_zero_length_field(self):
+ ffi, lib = self.prepare("""
+ struct foo { int a; int x[0]; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """, "test_call_with_zero_length_field", """
+ struct foo { int a; int x[0]; };
+ struct foo f(void) {
+ struct foo s = { 42 };
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().a == 42
+ e = raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'struct foo' not supported as return value. It is a "
+ "struct with a zero-length array, which libffi does not support. "
+ "Such structs are only supported as return value if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
+ "+ffibuilder.set_source() and not taking a final '...' argument)")
+
+ def test_call_with_union(self):
+ ffi, lib = self.prepare("""
+ union foo { int a; char b; };
+ union foo f(void);
+ union foo g(int, ...);
+ """, "test_call_with_union", """
+ union foo { int a; char b; };
+ union foo f(void) {
+ union foo s = { 42 };
+ return s;
+ }
+ union foo g(int a, ...) { }
+ """)
+ assert lib.f().a == 42
+ e = raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'union foo' not supported as return value by libffi. "
+ "Unions are only supported as return value if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
+ "+ffibuilder.set_source() and not taking a final '...' argument)")
+
+ def test_call_with_packed_struct(self):
+ import sys
+ if sys.platform == 'win32':
+ py.test.skip("needs a GCC extension")
+ ffi, lib = self.prepare("""
+ struct foo { char y; int x; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """, "test_call_with_packed_struct", """
+ struct foo { char y; int x; } __attribute__((packed));
+ struct foo f(void) {
+ struct foo s = { 40, 200 };
+ return s;
+ }
+ struct foo g(int a, ...) {
+ struct foo s = { 41, 201 };
+ return s;
+ }
+ """, packed=True, min_version=(1, 8, 3))
+ assert lib.f().y == chr(40)
+ assert lib.f().x == 200
+ e = raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'struct foo' not supported as return value. It is a 'packed'"
+ " structure, with a different layout than expected by libffi. "
+ "Such structs are only supported as return value if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
+ "+ffibuilder.set_source() and not taking a final '...' argument)")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
@@ -1076,9 +1076,13 @@
int (*foo)(struct foo_s s) = &foo1;
""")
e = py.test.raises(NotImplementedError, lib.foo, "?")
- msg = ("ctype 'struct foo_s' not supported as argument (it is a struct "
- 'declared with "...;", but the C calling convention may depend '
- 'on the missing fields)')
+ msg = ("ctype 'struct foo_s' not supported as argument. It is a struct "
+ 'declared with "...;", but the C calling convention may depend on '
+ "the missing fields; or, it contains anonymous struct/unions. "
+ "Such structs are only supported as argument "
+ "if the function is 'API mode' and non-variadic (i.e. declared "
+ "inside ffibuilder.cdef()+ffibuilder.set_source() and not taking "
+ "a final '...' argument)")
assert str(e.value) == msg
def test_func_returns_struct():
@@ -2147,14 +2151,23 @@
# assert did not crash so far
e = py.test.raises(NotImplementedError, fooptr, ffi.new("Data *"))
assert str(e.value) == (
- "ctype 'Data' (size 4) not supported as argument")
+ "ctype 'Data' not supported as argument by libffi. Unions are only "
+ "supported as argument if the function is 'API mode' and "
+ "non-variadic (i.e. declared inside ffibuilder.cdef()+"
+ "ffibuilder.set_source() and not taking a final '...' argument)")
e = py.test.raises(NotImplementedError, bazptr)
assert str(e.value) == (
- "ctype 'Data' (size 4) not supported as return value")
+ "ctype 'Data' not supported as return value by libffi. Unions are "
+ "only supported as return value if the function is 'API mode' and "
+ "non-variadic (i.e. declared inside ffibuilder.cdef()+"
+ "ffibuilder.set_source() and not taking a final '...' argument)")
e = py.test.raises(NotImplementedError, barptr)
assert str(e.value) == (
- "ctype 'MyStr' not supported as return value "
- "(it is a struct with bit fields)")
+ "ctype 'MyStr' not supported as return value. It is a struct with "
+ "bit fields, which libffi does not support. Such structs are only "
+ "supported as return value if the function is 'API mode' and non-"
+ "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
+ "set_source() and not taking a final '...' argument)")
def test_verify_extra_arguments():
ffi = FFI()
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -2013,3 +2013,159 @@
py.test.raises(ffi.error, ffi.sizeof, "vmat_t")
p = ffi.new("vmat_t", 4)
assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int")
+
+def test_call_with_custom_field_pos():
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo { int x; ...; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """)
+ lib = verify(ffi, "test_call_with_custom_field_pos", """
+ struct foo { int y, x; };
+ struct foo f(void) {
+ struct foo s = { 40, 200 };
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().x == 200
+ e = py.test.raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ 'ctype \'struct foo\' not supported as return value. It is a '
+ 'struct declared with "...;", but the C calling convention may '
+ 'depend on the missing fields; or, it contains anonymous '
+ 'struct/unions. Such structs are only supported '
+ 'as return value if the function is \'API mode\' and non-variadic '
+ '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
+ 'and not taking a final \'...\' argument)')
+
+def test_call_with_nested_anonymous_struct():
+ if sys.platform == 'win32':
+ py.test.skip("needs a GCC extension")
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo { int a; union { int b, c; }; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """)
+ lib = verify(ffi, "test_call_with_nested_anonymous_struct", """
+ struct foo { int a; union { int b, c; }; };
+ struct foo f(void) {
+ struct foo s = { 40 };
+ s.b = 200;
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().b == 200
+ e = py.test.raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ 'ctype \'struct foo\' not supported as return value. It is a '
+ 'struct declared with "...;", but the C calling convention may '
+ 'depend on the missing fields; or, it contains anonymous '
+ 'struct/unions. Such structs are only supported '
+ 'as return value if the function is \'API mode\' and non-variadic '
+ '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
+ 'and not taking a final \'...\' argument)')
+
+def test_call_with_bitfield():
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo { int x:5; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """)
+ lib = verify(ffi, "test_call_with_bitfield", """
+ struct foo { int x:5; };
+ struct foo f(void) {
+ struct foo s = { 11 };
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().x == 11
+ e = py.test.raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'struct foo' not supported as return value. It is a struct "
+ "with bit fields, which libffi does not support. Such structs are "
+ "only supported as return value if the function is 'API mode' and "
+ "non-variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
+ "set_source() and not taking a final '...' argument)")
+
+def test_call_with_zero_length_field():
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo { int a; int x[0]; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """)
+ lib = verify(ffi, "test_call_with_zero_length_field", """
+ struct foo { int a; int x[0]; };
+ struct foo f(void) {
+ struct foo s = { 42 };
+ return s;
+ }
+ struct foo g(int a, ...) { }
+ """)
+ assert lib.f().a == 42
+ e = py.test.raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'struct foo' not supported as return value. It is a "
+ "struct with a zero-length array, which libffi does not support."
+ " Such structs are only supported as return value if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
+ "+ffibuilder.set_source() and not taking a final '...' argument)")
+
+def test_call_with_union():
+ ffi = FFI()
+ ffi.cdef("""
+ union foo { int a; char b; };
+ union foo f(void);
+ union foo g(int, ...);
+ """)
+ lib = verify(ffi, "test_call_with_union", """
+ union foo { int a; char b; };
+ union foo f(void) {
+ union foo s = { 42 };
+ return s;
+ }
+ union foo g(int a, ...) { }
+ """)
+ assert lib.f().a == 42
+ e = py.test.raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'union foo' not supported as return value by libffi. "
+ "Unions are only supported as return value if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
+ "+ffibuilder.set_source() and not taking a final '...' argument)")
+
+def test_call_with_packed_struct():
+ if sys.platform == 'win32':
+ py.test.skip("needs a GCC extension")
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo { char y; int x; };
+ struct foo f(void);
+ struct foo g(int, ...);
+ """, packed=True)
+ lib = verify(ffi, "test_call_with_packed_struct", """
+ struct foo { char y; int x; } __attribute__((packed));
+ struct foo f(void) {
+ struct foo s = { 40, 200 };
+ return s;
+ }
+ struct foo g(int a, ...) {
+ struct foo s = { 41, 201 };
+ return s;
+ }
+ """)
+ assert lib.f().y == chr(40)
+ assert lib.f().x == 200
+ e = py.test.raises(NotImplementedError, lib.g, 0)
+ assert str(e.value) == (
+ "ctype 'struct foo' not supported as return value. It is a "
+ "'packed' structure, with a different layout than expected by libffi."
+ " Such structs are only supported as return value if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
+ "+ffibuilder.set_source() and not taking a final '...' argument)")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
@@ -1043,9 +1043,13 @@
int (*foo)(struct foo_s s) = &foo1;
""")
e = py.test.raises(NotImplementedError, lib.foo, "?")
- msg = ("ctype 'struct foo_s' not supported as argument (it is a struct "
- 'declared with "...;", but the C calling convention may depend '
- 'on the missing fields)')
+ msg = ("ctype 'struct foo_s' not supported as argument. It is a struct "
+ 'declared with "...;", but the C calling convention may depend on '
+ "the missing fields; or, it contains anonymous struct/unions. "
+ "Such structs are only supported as argument "
+ "if the function is 'API mode' and non-variadic (i.e. declared "
+ "inside ffibuilder.cdef()+ffibuilder.set_source() and not taking "
+ "a final '...' argument)")
assert str(e.value) == msg
def test_func_returns_struct():
@@ -2115,14 +2119,23 @@
# assert did not crash so far
e = py.test.raises(NotImplementedError, fooptr, ffi.new("Data *"))
assert str(e.value) == (
- "ctype 'Data' (size 4) not supported as argument")
+ "ctype 'Data' not supported as argument by libffi. Unions are only "
+ "supported as argument if the function is 'API mode' and "
+ "non-variadic (i.e. declared inside ffibuilder.cdef()+"
+ "ffibuilder.set_source() and not taking a final '...' argument)")
e = py.test.raises(NotImplementedError, bazptr)
assert str(e.value) == (
- "ctype 'Data' (size 4) not supported as return value")
+ "ctype 'Data' not supported as return value by libffi. Unions are "
+ "only supported as return value if the function is 'API mode' and "
+ "non-variadic (i.e. declared inside ffibuilder.cdef()+"
+ "ffibuilder.set_source() and not taking a final '...' argument)")
e = py.test.raises(NotImplementedError, barptr)
assert str(e.value) == (
- "ctype 'MyStr' not supported as return value "
- "(it is a struct with bit fields)")
+ "ctype 'MyStr' not supported as return value. It is a struct with "
+ "bit fields, which libffi does not support. Such structs are only "
+ "supported as return value if the function is 'API mode' and non-"
+ "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
+ "set_source() and not taking a final '...' argument)")
def test_verify_extra_arguments():
ffi = FFI()
More information about the pypy-commit
mailing list