[pypy-commit] cffi default: Fix/test/expand the error messages we get by using structs/unions as

arigo pypy.commits at gmail.com
Thu Dec 22 06:06:16 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2836:6e21f10eead4
Date: 2016-12-22 12:05 +0100
http://bitbucket.org/cffi/cffi/changeset/6e21f10eead4/

Log:	Fix/test/expand the error messages we get by using structs/unions as
	arguments/return values of functions

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -4629,6 +4629,22 @@
     }
 }
 
+#define 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)"
+
+static ffi_type *fb_unsupported(CTypeDescrObject *ct, const char *place,
+                                const char *detail)
+{
+    PyErr_Format(PyExc_NotImplementedError,
+        "ctype '%s' not supported as %s.  %s.  "
+        "Such structs" SUPPORTED_IN_API_MODE,
+        ct->ct_name, place, detail, place);
+    return NULL;
+}
+
 static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
                               int is_result_type)
 {
@@ -4675,11 +4691,10 @@
         if (ct->ct_flags & CT_CUSTOM_FIELD_POS) {
             /* these NotImplementedErrors may be caught and ignored until
                a real call is made to a function of this type */
-            PyErr_Format(PyExc_NotImplementedError,
-                "ctype '%s' not supported as %s (it is a struct declared "
-                "with \"...;\", but the C calling convention may depend "
-                "on the missing fields)", ct->ct_name, place);
-            return NULL;
+            return fb_unsupported(ct, place,
+                "It can be a struct declared with \"...;\": then the C "
+                "calling convention may depend on the missing fields.  "
+                "Or, it can be a struct with nested anonymous structs/unions");
         }
 
         n = PyDict_Size(ct->ct_stuff);
@@ -4693,11 +4708,8 @@
             CTypeDescrObject *ct1;
             assert(cf != NULL);
             if (cf->cf_bitshift >= 0) {
-                PyErr_Format(PyExc_NotImplementedError,
-                     "ctype '%s' not supported as %s"
-                     " (it is a struct with bit fields)",
-                     ct->ct_name, place);
-                return NULL;
+                return fb_unsupported(ct, place,
+                                      "It is a struct with bit fields");
             }
             flat = 1;
             ct1 = cf->cf_type;
@@ -4706,11 +4718,8 @@
                 ct1 = ct1->ct_itemdescr;
             }
             if (flat <= 0) {
-                PyErr_Format(PyExc_NotImplementedError,
-                     "ctype '%s' not supported as %s"
-                     " (it is a struct with a zero-length array)",
-                     ct->ct_name, place);
-                return NULL;
+                return fb_unsupported(ct, place,
+                    "It is a struct with a zero-length array");
             }
             nflat += flat;
             cf = cf->cf_next;
@@ -4751,8 +4760,9 @@
     }
     else {
         PyErr_Format(PyExc_NotImplementedError,
-                     "ctype '%s' (size %zd) not supported as %s",
-                     ct->ct_name, ct->ct_size, place);
+                     "ctype '%s' (size %zd) not supported as %s.  "
+                     "Unions" SUPPORTED_IN_API_MODE,
+                     ct->ct_name, ct->ct_size, place, place);
         return NULL;
     }
 }
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -2012,3 +2012,79 @@
     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)
+    print str(e.value)
+
+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)
+    print str(e.value)
+
+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)
+    print str(e.value)
+
+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)
+    print str(e.value)


More information about the pypy-commit mailing list