summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2012-06-29 11:26:11 +0200
committerArmin Rigo <arigo@tunes.org>2012-06-29 11:26:11 +0200
commit3bef5312ac0c3f70bc39f43be28a11c7dd7deb33 (patch)
treef2815803b2e8e27fe22b828448e2a3db3958d6a6
parentd597b4c05a2eb0b5b46e75cbf7a79cfb783d833d (diff)
downloadcffi-3bef5312ac0c3f70bc39f43be28a11c7dd7deb33.tar.gz
More tests for MSVC's struct return type. Add a workaround similar
to the one present in ctypes.
-rw-r--r--c/_cffi_backend.c61
-rw-r--r--c/test_c.py40
-rw-r--r--setup.py5
-rw-r--r--setup_base.py3
4 files changed, 103 insertions, 6 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index 5a74d44..618225a 100644
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2747,7 +2747,8 @@ static void *fb_alloc(struct funcbuilder_s *fb, Py_ssize_t size)
}
}
-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 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct)
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 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct)
"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 @@ static int fb_build(struct funcbuilder_s *fb, PyObject *fargs,
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 @@ static int fb_build(struct funcbuilder_s *fb, PyObject *fargs,
/* 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 @@ static struct _testfunc13_s _testfunc13(int n)
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 @@ static PyObject *b__testfunc(PyObject *self, PyObject *args)
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
index 4b4b28b..7027fa5 100644
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1171,6 +1171,7 @@ def test_invalid_function_result_types():
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 @@ def test_struct_return_in_func():
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
index fd7f1b6..c65f67a 100644
--- a/setup.py
+++ b/setup.py
@@ -6,6 +6,7 @@ import errno
sources = ['c/_cffi_backend.c']
libraries = ['ffi']
include_dirs = []
+define_macros = []
if sys.platform == 'win32':
@@ -30,6 +31,7 @@ if COMPILE_LIBFFI:
_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 @@ if __name__ == '__main__':
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
index adae53a..1fe5687 100644
--- 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 @@ if __name__ == '__main__':
include_dirs=include_dirs,
sources=sources,
libraries=libraries,
+ define_macros=define_macros,
)])