[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