[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