diff options
author | Armin Rigo <arigo@tunes.org> | 2012-06-29 11:26:11 +0200 |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2012-06-29 11:26:11 +0200 |
commit | 3bef5312ac0c3f70bc39f43be28a11c7dd7deb33 (patch) | |
tree | f2815803b2e8e27fe22b828448e2a3db3958d6a6 | |
parent | d597b4c05a2eb0b5b46e75cbf7a79cfb783d833d (diff) | |
download | cffi-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.c | 61 | ||||
-rw-r--r-- | c/test_c.py | 40 | ||||
-rw-r--r-- | setup.py | 5 | ||||
-rw-r--r-- | setup_base.py | 3 |
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()) @@ -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, )]) |