[pypy-commit] cffi default: merge heads

arigo pypy.commits at gmail.com
Mon Aug 22 11:40:51 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2746:3ce478433f9b
Date: 2016-08-22 17:40 +0200
http://bitbucket.org/cffi/cffi/changeset/3ce478433f9b/

Log:	merge heads

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3042,13 +3042,14 @@
 static PyObject *
 convert_struct_to_owning_object(char *data, CTypeDescrObject *ct)
 {
+    /* also accepts unions, for the API mode */
     CDataObject *cd;
     Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment);
     Py_ssize_t datasize = ct->ct_size;
 
-    if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) {
+    if (datasize < 0) {
         PyErr_SetString(PyExc_TypeError,
-                        "return type is not a struct or is opaque");
+                        "return type is an opaque structure or union");
         return NULL;
     }
     cd = allocate_owning_object(dataoffset + datasize, ct);
@@ -4623,6 +4624,8 @@
                 ct = ct->ct_itemdescr;
             }
             ffifield = fb_fill_type(fb, ct, 0);
+            if (PyErr_Occurred())
+                return NULL;
             if (elements != NULL) {
                 for (j=0; j<flat; j++)
                     elements[nflat++] = ffifield;
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -515,7 +515,7 @@
                                                     tovar, errcode)
             return
         #
-        elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
+        elif isinstance(tp, model.StructOrUnionOrEnum):
             # a struct (not a struct pointer) as a function argument
             self._prnt('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
                       % (tovar, self._gettypenum(tp), fromvar))
@@ -572,7 +572,7 @@
         elif isinstance(tp, model.ArrayType):
             return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
                 var, self._gettypenum(model.PointerType(tp.item)))
-        elif isinstance(tp, model.StructType):
+        elif isinstance(tp, model.StructOrUnion):
             if tp.fldnames is None:
                 raise TypeError("'%s' is used as %s, but is opaque" % (
                     tp._get_c_name(), context))
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -308,7 +308,7 @@
         elif isinstance(tp, model.ArrayType):
             return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
                 var, self._gettypenum(model.PointerType(tp.item)))
-        elif isinstance(tp, model.StructType):
+        elif isinstance(tp, model.StructOrUnion):
             if tp.fldnames is None:
                 raise TypeError("'%s' is used as %s, but is opaque" % (
                     tp._get_c_name(), context))
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -269,9 +269,7 @@
 
 Usually, the right thing to do is to call this method with True.  Be
 aware (particularly on Python 2) that, afterwards, you need to pass unicode
-strings as arguments instead of byte strings.  (Before cffi version 0.9,
-``TCHAR`` and friends where hard-coded as unicode, but ``UNICODE`` was,
-inconsistently, not defined by default.)
+strings as arguments instead of byte strings.
 
 
 .. _loading-libraries:
@@ -336,7 +334,7 @@
 
 **ffibuilder.set_source(module_name, c_header_source, [\*\*keywords...])**:
 prepare the ffi for producing out-of-line an external module called
-``module_name``.  *New in version 1.0.*
+``module_name``.
 
 ``ffibuilder.set_source()`` by itself does not write any file, but merely
 records its arguments for later.  It can therefore be called before or
@@ -425,7 +423,7 @@
    declaration which doesn't use "``...``" is assumed to be exact, but this is
    checked: you get an error if it is not correct.
 
-*  *New in version 1.1:* integer types: the syntax "``typedef
+*  integer types: the syntax "``typedef
    int... foo_t;``" declares the type ``foo_t`` as an integer type
    whose exact size and signedness is not specified.  The compiler will
    figure it out.  (Note that this requires ``set_source()``; it does
@@ -462,8 +460,8 @@
    length is completed by the C compiler.
    This is slightly different from "``int n[];``", because the latter
    means that the length is not known even to the C compiler, and thus
-   no attempt is made to complete it.  *New in version 1.1:* support
-   for multidimensional arrays: "``int n[...][...];``".
+   no attempt is made to complete it.  This supports
+   multidimensional arrays: "``int n[...][...];``".
 
    *New in version 1.2:* "``int m[][...];``", i.e. ``...`` can be used
    in the innermost dimensions without being also used in the outermost
diff --git a/doc/source/ref.rst b/doc/source/ref.rst
--- a/doc/source/ref.rst
+++ b/doc/source/ref.rst
@@ -292,7 +292,7 @@
 
 3. ``ffi.addressof(<library>, "name")`` returns the address of the
 named function or global variable from the given library object.
-*New in version 1.1:* for functions, it returns a regular cdata
+For functions, it returns a regular cdata
 object containing a pointer to the function.
 
 Note that the case 1. cannot be used to take the address of a
diff --git a/doc/source/using.rst b/doc/source/using.rst
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -366,8 +366,8 @@
 
 __ ref.html#conversions
 
-CFFI supports passing and returning structs to functions and callbacks.
-Example:
+CFFI supports passing and returning structs and unions to functions and
+callbacks.  Example:
 
 .. code-block:: python
 
@@ -377,36 +377,33 @@
     myfoo = lib.function_returning_a_struct()
     # `myfoo`: <cdata 'struct foo_s' owning 8 bytes>
 
-There are a few (obscure) limitations to the argument types and return
-type.  You cannot pass directly as argument a union (but a *pointer*
-to a union is fine), nor a struct which uses bitfields (but a
-*pointer* to such a struct is fine).  If you pass a struct (not a
-*pointer* to a struct), the struct type cannot have been declared with
-"``...;``" in the ``cdef()``; you need to declare it completely in
-``cdef()``.  You can work around these limitations by writing a C
-function with a simpler signature in the C header code passed to
-``ffibuilder.set_source()``, and have this C function call the real one.
-
-Aside from these limitations, functions and callbacks can receive and
-return structs.
-
-For performance, API-level functions are not returned as ``<cdata>``
-objects, but as a different type (on CPython, ``<built-in
-function>``).  This means you cannot e.g. pass them to some other C
+For performance, non-variadic API-level functions that you get by
+writing ``lib.some_function`` are not ``<cdata>``
+objects, but an object of a different type (on CPython, ``<built-in
+function>``).  This means you cannot pass them directly to some other C
 function expecting a function pointer argument.  Only ``ffi.typeof()``
 works on them.  To get a cdata containing a regular function pointer,
-use ``ffi.addressof(lib, "name")`` (new in version 1.1).
+use ``ffi.addressof(lib, "name")``.
 
-Before version 1.1 (or with the deprecated ``ffi.verify()``), if you
-really need a cdata pointer to the function, use the following
-workaround:
+There are a few (obscure) limitations to the supported argument and
+return types.  These limitations come from libffi and apply only to
+calling ``<cdata>`` function pointers; in other words, they don't
+apply to non-variadic ``cdef()``-declared functions if you are using
+the API mode.  The limitations are that you cannot pass directly as
+argument or return type:
 
-.. code-block:: python
-  
-    ffi.cdef(""" int (*foo)(int a, int b); """)
+* a union (but a *pointer* to a union is fine);
 
-i.e. declare them as pointer-to-function in the cdef (even if they are
-regular functions in the C code).
+* a struct which uses bitfields (but a *pointer* to such a struct is
+  fine);
+
+* a struct that was declared with "``...``" in the ``cdef()``.
+
+In API mode, you can work around these limitations: for example, if you
+need to call such a function pointer from Python, you can instead write
+a custom C function that accepts the function pointer and the real
+arguments and that does the call from C.  Then declare that custom C
+function in the ``cdef()`` and use it from Python.
 
 
 Variadic function calls
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
@@ -1962,3 +1962,21 @@
                        ffi, "test_function_returns_opaque", "?")
     assert str(e.value) == ("function foo: 'struct a' is used as result type,"
                             " but is opaque")
+
+def test_function_returns_union():
+    ffi = FFI()
+    ffi.cdef("union u1 { int a, b; }; union u1 f1(int);")
+    lib = verify(ffi, "test_function_returns_union", """
+        union u1 { int a, b; };
+        static union u1 f1(int x) { union u1 u; u.b = x; return u; }
+    """)
+    assert lib.f1(51).a == 51
+
+def test_function_returns_partial_struct():
+    ffi = FFI()
+    ffi.cdef("struct a { int a; ...; }; struct a f1(int);")
+    lib = verify(ffi, "test_function_returns_partial_struct", """
+        struct a { int b, a, c; };
+        static struct a f1(int x) { struct a s = {0}; s.a = x; return s; }
+    """)
+    assert lib.f1(52).a == 52


More information about the pypy-commit mailing list