[pypy-commit] cffi default: Delay reporting NotImplmentedErrors when building function types with

arigo noreply at buildbot.pypy.org
Fri Jan 2 19:16:29 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r1619:275285b314a7
Date: 2015-01-02 19:16 +0100
http://bitbucket.org/cffi/cffi/changeset/275285b314a7/

Log:	Delay reporting NotImplmentedErrors when building function types
	with unsupported arguments. They are now reported only when we
	actually try to do a call. Issue #127.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -4095,24 +4095,26 @@
         cf = (CFieldObject *)ct->ct_extra;
         for (i=0; i<n; i++) {
             Py_ssize_t flat;
-            CTypeDescrObject *ct;
+            CTypeDescrObject *ct1;
             assert(cf != NULL);
             if (cf->cf_bitshift >= 0) {
-                PyErr_SetString(PyExc_NotImplementedError,
-                                "cannot pass as argument or return value "
-                                "a struct with bit fields");
+                PyErr_Format(PyExc_NotImplementedError,
+                     "ctype '%s' not supported as argument or return value"
+                     " (it is a struct with bit fields)",
+                     ct->ct_name);
                 return NULL;
             }
             flat = 1;
-            ct = cf->cf_type;
-            while (ct->ct_flags & CT_ARRAY) {
-                flat *= ct->ct_length;
-                ct = ct->ct_itemdescr;
+            ct1 = cf->cf_type;
+            while (ct1->ct_flags & CT_ARRAY) {
+                flat *= ct1->ct_length;
+                ct1 = ct1->ct_itemdescr;
             }
             if (flat <= 0) {
-                PyErr_SetString(PyExc_NotImplementedError,
-                                "cannot pass as argument or return value "
-                                "a struct with a zero-length array");
+                PyErr_Format(PyExc_NotImplementedError,
+                     "ctype '%s' not supported as argument or return value"
+                     " (it is a struct with a zero-length array)",
+                     ct->ct_name);
                 return NULL;
             }
             nflat += flat;
@@ -4382,11 +4384,6 @@
                           &fabi))
         return NULL;
 
-    if (fresult->ct_flags & CT_UNION) {
-        PyErr_SetString(PyExc_NotImplementedError,
-                        "function returning a union");
-        return NULL;
-    }
     if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) ||
         (fresult->ct_flags & CT_ARRAY)) {
         char *msg;
@@ -4410,8 +4407,14 @@
         cif_description_t *cif_descr;
 
         cif_descr = fb_prepare_cif(fargs, fresult, fabi);
-        if (cif_descr == NULL)
-            goto error;
+        if (cif_descr == NULL) {
+            if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
+                PyErr_Clear();   /* will get the exception if we see an
+                                    actual call */
+            }
+            else
+                goto error;
+        }
 
         fct->ct_extra = (char *)cif_descr;
     }
@@ -4646,8 +4649,9 @@
 
     cif_descr = (cif_description_t *)ct->ct_extra;
     if (cif_descr == NULL) {
-        PyErr_SetString(PyExc_NotImplementedError,
-                        "callbacks with '...'");
+        PyErr_Format(PyExc_NotImplementedError,
+                     "%s: callback with unsupported argument or "
+                     "return type or with '...'", ct->ct_name);
         goto error;
     }
     if (ffi_prep_closure(closure, &cif_descr->cif,
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1041,11 +1041,12 @@
     BInt = new_primitive_type("int")
     BArray0 = new_array_type(new_pointer_type(BInt), 0)
     BStruct = new_struct_type("struct foo")
+    BStructP = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a', BArray0)])
-    py.test.raises(NotImplementedError, new_function_type,
-                   (BStruct,), BInt, False)
-    py.test.raises(NotImplementedError, new_function_type,
-                   (BInt,), BStruct, False)
+    BFunc = new_function_type((BStruct,), BInt, False)
+    py.test.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123))
+    BFunc2 = new_function_type((BInt,), BStruct, False)
+    py.test.raises(NotImplementedError, cast(BFunc2, 123), 123)
 
 def test_call_function_9():
     BInt = new_primitive_type("int")
@@ -1816,7 +1817,8 @@
     new_function_type((), new_pointer_type(BFunc))
     BUnion = new_union_type("union foo_u")
     complete_struct_or_union(BUnion, [])
-    py.test.raises(NotImplementedError, new_function_type, (), BUnion)
+    BFunc = new_function_type((), BUnion)
+    py.test.raises(NotImplementedError, cast(BFunc, 123))
     py.test.raises(TypeError, new_function_type, (), BArray)
 
 def test_struct_return_in_func():
diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py
--- a/testing/test_ffi_backend.py
+++ b/testing/test_ffi_backend.py
@@ -19,8 +19,8 @@
         ffi.cdef("struct foo_s { int a,b,c,d,e; int x:1; };")
         e = py.test.raises(NotImplementedError, ffi.callback,
                            "struct foo_s foo(void)", lambda: 42)
-        assert str(e.value) == ("<struct foo_s(*)(void)>: "
-            "cannot pass as argument or return value a struct with bit fields")
+        assert str(e.value) == ("struct foo_s(*)(): "
+            "callback with unsupported argument or return type or with '...'")
 
     def test_inspecttype(self):
         ffi = FFI(backend=self.Backend())
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -2069,3 +2069,20 @@
     ffi2.cdef("int foo;")
     lib2 = ffi2.verify("int foo;", flags=ffi2.RTLD_GLOBAL | ffi2.RTLD_LAZY)
     return lib2
+
+def test_consider_not_implemented_function_type():
+    ffi = FFI()
+    ffi.cdef("typedef union { int a; float b; } Data;"
+             "typedef struct { int a:2; } MyStr;"
+             "typedef void (*foofunc_t)(Data);"
+             "typedef MyStr (*barfunc_t)(void);")
+    fooptr = ffi.cast("foofunc_t", 123)
+    barptr = ffi.cast("barfunc_t", 123)
+    # assert did not crash so far
+    e = py.test.raises(NotImplementedError, fooptr, ffi.new("Data *"))
+    assert str(e.value) == (
+        "ctype 'Data' not supported as argument or return value")
+    e = py.test.raises(NotImplementedError, barptr)
+    assert str(e.value) == (
+        "ctype 'MyStr' not supported as argument or return value "
+        "(it is a struct with bit fields)")


More information about the pypy-commit mailing list