[pypy-commit] cffi default: More tests for MSVC's struct return type. Add a workaround similar
arigo
noreply at buildbot.pypy.org
Fri Jun 29 11:26:21 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r567:ee603675e7aa
Date: 2012-06-29 11:26 +0200
http://bitbucket.org/cffi/cffi/changeset/ee603675e7aa/
Log: More tests for MSVC's struct return type. Add a workaround similar
to the one present in ctypes.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2747,7 +2747,8 @@
}
}
-static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct)
+static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
+ int is_result_type)
{
if (ct->ct_flags & CT_PRIMITIVE_ANY) {
return (ffi_type *)ct->ct_extra;
@@ -2785,6 +2786,19 @@
return NULL;
}
+#ifdef USE_C_LIBFFI_MSVC
+ /* MSVC returns small structures in registers. Pretend int32 or
+ int64 return type. This is needed as a workaround for what
+ is really a bug of libffi_msvc seen as an independent library
+ (ctypes has a similar workaround). */
+ if (is_result_type) {
+ if (ct->ct_size <= 4)
+ return &ffi_type_sint32;
+ if (ct->ct_size <= 8)
+ return &ffi_type_sint64;
+ }
+#endif
+
n = PyDict_Size(ct->ct_stuff);
elements = fb_alloc(fb, (n + 1) * sizeof(ffi_type*));
cf = (CFieldObject *)ct->ct_extra;
@@ -2796,7 +2810,7 @@
"cannot pass as argument a struct with bit fields");
return NULL;
}
- ffifield = fb_fill_type(fb, cf->cf_type);
+ ffifield = fb_fill_type(fb, cf->cf_type, 0);
if (elements != NULL)
elements[i] = ffifield;
cf = cf->cf_next;
@@ -2839,7 +2853,7 @@
fb->nargs = nargs;
/* ffi buffer: next comes the result type */
- fb->rtype = fb_fill_type(fb, fresult);
+ fb->rtype = fb_fill_type(fb, fresult, 1);
if (PyErr_Occurred())
return -1;
if (cif_descr != NULL) {
@@ -2867,7 +2881,7 @@
/* ffi buffer: fill in the ffi for the i'th argument */
assert(farg != NULL);
- atype = fb_fill_type(fb, farg);
+ atype = fb_fill_type(fb, farg, 0);
if (PyErr_Occurred())
return -1;
@@ -3550,6 +3564,41 @@
return result;
}
+struct _testfunc14_s { float a1; };
+static struct _testfunc14_s _testfunc14(int n)
+{
+ struct _testfunc14_s result;
+ result.a1 = (float)n;
+ return result;
+}
+
+struct _testfunc15_s { float a1; int a2; };
+static struct _testfunc15_s _testfunc15(int n)
+{
+ struct _testfunc15_s result;
+ result.a1 = (float)n;
+ result.a2 = n * n;
+ return result;
+}
+
+struct _testfunc16_s { float a1, a2; };
+static struct _testfunc16_s _testfunc16(int n)
+{
+ struct _testfunc16_s result;
+ result.a1 = (float)n;
+ result.a2 = -(float)n;
+ return result;
+}
+
+struct _testfunc17_s { int a1; float a2; };
+static struct _testfunc17_s _testfunc17(int n)
+{
+ struct _testfunc17_s result;
+ result.a1 = n;
+ result.a2 = (float)n * (float)n;
+ return result;
+}
+
static PyObject *b__testfunc(PyObject *self, PyObject *args)
{
/* for testing only */
@@ -3572,6 +3621,10 @@
case 11: f = &_testfunc11; break;
case 12: f = &_testfunc12; break;
case 13: f = &_testfunc13; break;
+ case 14: f = &_testfunc14; break;
+ case 15: f = &_testfunc15; break;
+ case 16: f = &_testfunc16; break;
+ case 17: f = &_testfunc17; break;
default:
PyErr_SetNone(PyExc_ValueError);
return NULL;
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1171,6 +1171,7 @@
def test_struct_return_in_func():
BChar = new_primitive_type("char")
BShort = new_primitive_type("short")
+ BFloat = new_primitive_type("float")
BDouble = new_primitive_type("double")
BInt = new_primitive_type("int")
BStruct = new_struct_type("foo_s")
@@ -1213,6 +1214,45 @@
assert s.a1 == 40
assert s.a2 == 40 * 40
assert s.a3 == 40 * 40 * 40
+ #
+ BStruct14 = new_struct_type("test14")
+ complete_struct_or_union(BStruct14, [('a1', BFloat, -1),
+ ])
+ BFunc14 = new_function_type((BInt,), BStruct14)
+ f = cast(BFunc14, _testfunc(14))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test14' owning 4 bytes>"
+ assert s.a1 == 40.0
+ #
+ BStruct15 = new_struct_type("test15")
+ complete_struct_or_union(BStruct15, [('a1', BFloat, -1),
+ ('a2', BInt, -1)])
+ BFunc15 = new_function_type((BInt,), BStruct15)
+ f = cast(BFunc15, _testfunc(15))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test15' owning 8 bytes>"
+ assert s.a1 == 40.0
+ assert s.a2 == 40 * 40
+ #
+ BStruct16 = new_struct_type("test16")
+ complete_struct_or_union(BStruct16, [('a1', BFloat, -1),
+ ('a2', BFloat, -1)])
+ BFunc16 = new_function_type((BInt,), BStruct16)
+ f = cast(BFunc16, _testfunc(16))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test16' owning 8 bytes>"
+ assert s.a1 == 40.0
+ assert s.a2 == -40.0
+ #
+ BStruct17 = new_struct_type("test17")
+ complete_struct_or_union(BStruct17, [('a1', BInt, -1),
+ ('a2', BFloat, -1)])
+ BFunc17 = new_function_type((BInt,), BStruct17)
+ f = cast(BFunc17, _testfunc(17))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test17' owning 8 bytes>"
+ assert s.a1 == 40
+ assert s.a2 == 40.0 * 40.0
def test_cast_with_functionptr():
BFunc = new_function_type((), new_void_type())
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -6,6 +6,7 @@
sources = ['c/_cffi_backend.c']
libraries = ['ffi']
include_dirs = []
+define_macros = []
if sys.platform == 'win32':
@@ -30,6 +31,7 @@
_filenames.remove('win32.c')
sources.extend(os.path.join(COMPILE_LIBFFI, filename)
for filename in _filenames)
+ define_macros.append(('USE_C_LIBFFI_MSVC', '1'))
else:
try:
p = subprocess.Popen(['pkg-config', '--cflags-only-I', 'libffi'],
@@ -66,7 +68,8 @@
Extension(name='_cffi_backend',
include_dirs=include_dirs,
sources=sources,
- libraries=libraries),
+ libraries=libraries,
+ define_macros=define_macros),
],
),
},
diff --git a/setup_base.py b/setup_base.py
--- a/setup_base.py
+++ b/setup_base.py
@@ -1,7 +1,7 @@
import sys, os
-from setup import include_dirs, sources, libraries
+from setup import include_dirs, sources, libraries, define_macros
if __name__ == '__main__':
@@ -11,4 +11,5 @@
include_dirs=include_dirs,
sources=sources,
libraries=libraries,
+ define_macros=define_macros,
)])
More information about the pypy-commit
mailing list