Author: Armin Rigo <ar...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit