Hello community,

here is the log from the commit of package python3-cffi for openSUSE:Factory 
checked in at 2016-09-20 13:24:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-cffi (Old)
 and      /work/SRC/openSUSE:Factory/.python3-cffi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-cffi"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-cffi/python3-cffi-doc.changes    
2016-06-25 01:56:13.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-cffi.new/python3-cffi-doc.changes       
2016-09-20 13:24:53.000000000 +0200
@@ -1,0 +2,41 @@
+Sun Sep 18 15:53:20 UTC 2016 - a...@gmx.de
+
+- update to version 1.8.3:
+  * When passing a void * argument to a function with a different
+    pointer type, or vice-versa, the cast occurs automatically, like
+    in C. The same occurs for initialization with ffi.new() and a few
+    other places. However, I thought that char * had the same
+    property—but I was mistaken. In C you get the usual warning if you
+    try to give a char * to a char ** argument, for example. Sorry
+    about the confusion. This has been fixed in CFFI by giving for now
+    a warning, too. It will turn into an error in a future version.
+
+-------------------------------------------------------------------
+Fri Sep 16 15:10:25 UTC 2016 - toddrme2...@gmail.com
+
+- Update to 1.8.2
+  * Issue #283: fixed ``ffi.new()`` on structures/unions with nested
+    anonymous structures/unions, when there is at least one union in
+    the mix.  When initialized with a list or a dict, it should now
+    behave more closely like the ``{ }`` syntax does in GCC.
+- Update to 1.8.1
+  * CPython 3.x: experimental: the generated C extension modules now use
+    the "limited API", which means that, as a compiled .so/.dll, it should
+    work directly on any version of CPython >= 3.2.  The name produced by
+    distutils is still version-specific.  To get the version-independent
+    name, you can rename it manually to ``NAME.abi3.so``, or use the very
+    recent setuptools 26.
+  * Added ``ffi.compile(debug=...)``, similar to ``python setup.py build
+    --debug`` but defaulting to True if we are running a debugging
+    version of Python itself.
+- Update to 1.8
+  * Removed the restriction that ``ffi.from_buffer()`` cannot be used on
+    byte strings.  Now you can get a ``char *`` out of a byte string,
+    which is valid as long as the string object is kept alive.  (But
+    don't use it to *modify* the string object!  If you need this, use
+    ``bytearray`` or other official techniques.)
+  * PyPy 5.4 can now pass a byte string directly to a ``char *``
+    argument (in older versions, a copy would be made).  This used to be
+    a CPython-only optimization.
+
+-------------------------------------------------------------------
python3-cffi.changes: same change

Old:
----
  cffi-1.7.0.tar.gz

New:
----
  cffi-1.8.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-cffi-doc.spec ++++++
--- /var/tmp/diff_new_pack.CijluO/_old  2016-09-20 13:24:54.000000000 +0200
+++ /var/tmp/diff_new_pack.CijluO/_new  2016-09-20 13:24:54.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python3-cffi-doc
-Version:        1.7.0
+Version:        1.8.3
 Release:        0
 Summary:        Documentation for python3-cffi
 License:        MIT

python3-cffi.spec: same change
++++++ cffi-1.7.0.tar.gz -> cffi-1.8.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/PKG-INFO new/cffi-1.8.3/PKG-INFO
--- old/cffi-1.7.0/PKG-INFO     2016-06-20 16:33:45.000000000 +0200
+++ new/cffi-1.8.3/PKG-INFO     2016-09-17 12:21:52.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.7.0
+Version: 1.8.3
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
@@ -27,5 +27,6 @@
 Classifier: Programming Language :: Python :: 3.2
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/c/_cffi_backend.c 
new/cffi-1.8.3/c/_cffi_backend.c
--- old/cffi-1.7.0/c/_cffi_backend.c    2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/c/_cffi_backend.c    2016-09-17 12:21:34.000000000 +0200
@@ -2,7 +2,7 @@
 #include <Python.h>
 #include "structmember.h"
 
-#define CFFI_VERSION  "1.7.0"
+#define CFFI_VERSION  "1.8.3"
 
 #ifdef MS_WIN32
 #include <windows.h>
@@ -128,7 +128,7 @@
 #define CT_VOID             512    /* void */
 
 /* other flags that may also be set in addition to the base flag: */
-#define CT_CAST_ANYTHING         1024    /* 'char *' and 'void *' only */
+#define CT_IS_VOIDCHAR_PTR       1024
 #define CT_PRIMITIVE_FITS_LONG   2048
 #define CT_IS_OPAQUE             4096
 #define CT_IS_ENUM               8192
@@ -187,10 +187,12 @@
     Py_ssize_t cf_offset;
     short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */
     short cf_bitsize;
+    unsigned char cf_flags;   /* BF_... */
     struct cfieldobject_s *cf_next;
 } CFieldObject;
 #define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
 #define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
+#define BF_IGNORE_IN_CTOR  0x01  /* union field not in the first place */
 
 static PyTypeObject CTypeDescr_Type;
 static PyTypeObject CField_Type;
@@ -657,6 +659,7 @@
     {"offset", T_PYSSIZET, OFF(cf_offset), READONLY},
     {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY},
     {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY},
+    {"flags", T_UBYTE, OFF(cf_flags), READONLY},
     {NULL}      /* Sentinel */
 };
 #undef OFF
@@ -1274,24 +1277,14 @@
         return -1;
     }
 
-    if (ct->ct_flags & CT_UNION) {
-        Py_ssize_t n = PyObject_Size(init);
-        if (n < 0)
-            return -1;
-        if (n > 1) {
-            PyErr_Format(PyExc_ValueError,
-                         "initializer for '%s': %zd items given, but "
-                         "only one supported (use a dict if needed)",
-                         ct->ct_name, n);
-            return -1;
-        }
-    }
     if (PyList_Check(init) || PyTuple_Check(init)) {
         PyObject **items = PySequence_Fast_ITEMS(init);
         Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init);
         CFieldObject *cf = (CFieldObject *)ct->ct_extra;
 
         for (i=0; i<n; i++) {
+            while (cf != NULL && (cf->cf_flags & BF_IGNORE_IN_CTOR))
+                cf = cf->cf_next;
             if (cf == NULL) {
                 PyErr_Format(PyExc_ValueError,
                              "too many initializers for '%s' (got %zd)",
@@ -1365,9 +1358,26 @@
             }
         }
         if (ctinit != ct) {
-            if ((ct->ct_flags & CT_CAST_ANYTHING) ||
-                (ctinit->ct_flags & CT_CAST_ANYTHING))
-                ;   /* accept void* or char* as either source or target */
+            int combined_flags = ct->ct_flags | ctinit->ct_flags;
+            if (combined_flags & CT_IS_VOID_PTR)
+                ;   /* accept "void *" as either source or target */
+            else if (combined_flags & CT_IS_VOIDCHAR_PTR) {
+                /* for backward compatibility, accept "char *" as either
+                   source of target.  This is not what C does, though,
+                   so emit a warning that will eventually turn into an
+                   error. */
+                char *msg = (ct->ct_flags & CT_IS_VOIDCHAR_PTR ?
+                    "implicit cast to 'char *' from a different pointer type: "
+                    "will be forbidden in the future (check that the types "
+                    "are as you expect; use an explicit ffi.cast() if they "
+                    "are correct)" :
+                    "implicit cast from 'char *' to a different pointer type: "
+                    "will be forbidden in the future (check that the types "
+                    "are as you expect; use an explicit ffi.cast() if they "
+                    "are correct)");
+                if (PyErr_WarnEx(PyExc_UserWarning, msg, 1))
+                    return -1;
+            }
             else {
                 expected = "pointer to same type";
                 goto cannot_convert;
@@ -2355,8 +2365,16 @@
             return NULL;
         }
         itemsize = ct->ct_itemdescr->ct_size;
-        if (itemsize <= 0) itemsize = 1;
-        diff = (cdv->c_data - cdw->c_data) / itemsize;
+        diff = cdv->c_data - cdw->c_data;
+        if (itemsize > 1) {
+            if (diff % itemsize) {
+                PyErr_SetString(PyExc_ValueError,
+                     "pointer subtraction: the distance between the two "
+                     "pointers is not a multiple of the item size");
+                return NULL;
+            }
+            diff = diff / itemsize;
+        }
 #if PY_MAJOR_VERSION < 3
         return PyInt_FromSsize_t(diff);
 #else
@@ -2475,7 +2493,7 @@
     if (PyBytes_Check(init)) {
         /* from a string: just returning the string here is fine.
            We assume that the C code won't modify the 'char *' data. */
-        if ((ctptr->ct_flags & CT_CAST_ANYTHING) ||
+        if ((ctptr->ct_flags & CT_IS_VOIDCHAR_PTR) ||
             ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))
              && (ctitem->ct_size == sizeof(char)))) {
 #if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK)
@@ -3034,13 +3052,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);
@@ -3778,7 +3797,7 @@
        EPTYPE(um, uintmax_t, CT_PRIMITIVE_UNSIGNED)             \
        EPTYPE(pd, ptrdiff_t, CT_PRIMITIVE_SIGNED)               \
        EPTYPE(sz, size_t, CT_PRIMITIVE_UNSIGNED)                \
-       EPTYPE(ssz, ssize_t, CT_PRIMITIVE_SIGNED)
+       EPTYPE2(ssz, "ssize_t", Py_ssize_t, CT_PRIMITIVE_SIGNED)
 
 #ifdef HAVE_WCHAR_H
 # define ENUM_PRIMITIVE_TYPES_WCHAR                             \
@@ -3787,21 +3806,24 @@
 # define ENUM_PRIMITIVE_TYPES_WCHAR   /* nothing */
 #endif
 
-#define EPTYPE(code, typename, flags)                   \
+#define EPTYPE(code, typename, flags)  EPTYPE2(code, #typename, typename, 
flags)
+
+#define EPTYPE2(code, export_name, typename, flags)     \
     struct aligncheck_##code { char x; typename y; };
     ENUM_PRIMITIVE_TYPES
-#undef EPTYPE
+#undef EPTYPE2
 
     CTypeDescrObject *td;
     static const struct descr_s { const char *name; int size, align, flags; }
     types[] = {
-#define EPTYPE(code, typename, flags)                   \
-        { #typename,                                    \
+#define EPTYPE2(code, export_name, typename, flags)     \
+        { export_name,                                  \
           sizeof(typename),                             \
           offsetof(struct aligncheck_##code, y),        \
           flags                                         \
         },
     ENUM_PRIMITIVE_TYPES
+#undef EPTYPE2
 #undef EPTYPE
 #undef ENUM_PRIMITIVE_TYPES_WCHAR
 #undef ENUM_PRIMITIVE_TYPES
@@ -3924,7 +3946,7 @@
     if ((ctitem->ct_flags & CT_VOID) ||
         ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
          ctitem->ct_size == sizeof(char)))
-        td->ct_flags |= CT_CAST_ANYTHING;   /* 'void *' or 'char *' only */
+        td->ct_flags |= CT_IS_VOIDCHAR_PTR;   /* 'void *' or 'char *' only */
     unique_key[0] = ctitem;
     return get_unique_type(td, unique_key, 1);
 }
@@ -4073,7 +4095,7 @@
 
 static CFieldObject *
 _add_field(PyObject *interned_fields, PyObject *fname, CTypeDescrObject *ftype,
-           Py_ssize_t offset, int bitshift, int fbitsize)
+           Py_ssize_t offset, int bitshift, int fbitsize, int flags)
 {
     int err;
     Py_ssize_t prev_size;
@@ -4086,6 +4108,7 @@
     cf->cf_offset = offset;
     cf->cf_bitshift = bitshift;
     cf->cf_bitsize = fbitsize;
+    cf->cf_flags = flags;
 
     Py_INCREF(fname);
     PyText_InternInPlace(&fname);
@@ -4172,7 +4195,7 @@
     int totalalignment = -1;
     CFieldObject **previous;
     int prev_bitfield_size, prev_bitfield_free;
-    int sflags = 0;
+    int sflags = 0, fflags;
 
     if (!PyArg_ParseTuple(args, "O!O!|Onii:complete_struct_or_union",
                           &CTypeDescr_Type, &ct,
@@ -4258,6 +4281,8 @@
         if (alignment < falign && do_align)
             alignment = falign;
 
+        fflags = (is_union && i > 0) ? BF_IGNORE_IN_CTOR : 0;
+
         if (fbitsize < 0) {
             /* not a bitfield: common case */
             int bs_flag;
@@ -4293,7 +4318,8 @@
                                            cfsrc->cf_type,
                                            boffset / 8 + cfsrc->cf_offset,
                                            cfsrc->cf_bitshift,
-                                           cfsrc->cf_bitsize);
+                                           cfsrc->cf_bitsize,
+                                           cfsrc->cf_flags | fflags);
                     if (*previous == NULL)
                         goto error;
                     previous = &(*previous)->cf_next;
@@ -4303,7 +4329,7 @@
             }
             else {
                 *previous = _add_field(interned_fields, fname, ftype,
-                                        boffset / 8, bs_flag, -1);
+                                        boffset / 8, bs_flag, -1, fflags);
                 if (*previous == NULL)
                     goto error;
                 previous = &(*previous)->cf_next;
@@ -4433,7 +4459,8 @@
                     bitshift = 8 * ftype->ct_size - fbitsize - bitshift;
 
                 *previous = _add_field(interned_fields, fname, ftype,
-                                       field_offset_bytes, bitshift, fbitsize);
+                                       field_offset_bytes, bitshift, fbitsize,
+                                       fflags);
                 if (*previous == NULL)
                     goto error;
                 previous = &(*previous)->cf_next;
@@ -4612,6 +4639,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;
@@ -5472,7 +5501,7 @@
         *offset = cf->cf_offset;
     }
     else {
-        ssize_t index = PyInt_AsSsize_t(fieldname);
+        Py_ssize_t index = PyInt_AsSsize_t(fieldname);
         if (index < 0 && PyErr_Occurred()) {
             PyErr_SetString(PyExc_TypeError,
                             "field name or array index expected");
@@ -5891,7 +5920,7 @@
         return NULL;
     }
     ct = ((CDataObject *)arg)->c_type;
-    if (!(ct->ct_flags & CT_CAST_ANYTHING)) {
+    if (!(ct->ct_flags & CT_IS_VOIDCHAR_PTR)) {
         PyErr_Format(PyExc_TypeError,
                      "expected a 'cdata' object with a 'void *' out of "
                      "new_handle(), got '%s'", ct->ct_name);
@@ -5971,6 +6000,11 @@
 
 static int invalid_input_buffer_type(PyObject *x)
 {
+    /* From PyPy 5.4, from_buffer() accepts strings (but still not buffers
+       or memoryviews on strings). */
+    if (PyBytes_Check(x))
+        return 0;
+
 #if PY_MAJOR_VERSION < 3
     if (PyBuffer_Check(x)) {
         /* XXX fish fish fish in an inofficial way */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/c/test_c.py new/cffi-1.8.3/c/test_c.py
--- old/cffi-1.7.0/c/test_c.py  2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/c/test_c.py  2016-09-17 12:21:34.000000000 +0200
@@ -12,7 +12,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.7.0", ("This test_c.py file is for testing a version"
+assert __version__ == "1.8.3", ("This test_c.py file is for testing a version"
                                 " of cffi that differs from the one that we"
                                 " get from 'import _cffi_backend'")
 if sys.version_info < (3,):
@@ -587,6 +587,19 @@
     e = py.test.raises(TypeError, "q - a")
     assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'"
 
+def test_ptr_sub_unaligned():
+    BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
+    a = cast(BIntPtr, 1240)
+    for bi in range(1430, 1438):
+        b = cast(BIntPtr, bi)
+        if ((bi - 1240) % size_of_int()) == 0:
+            assert b - a == (bi - 1240) // size_of_int()
+            assert a - b == (1240 - bi) // size_of_int()
+        else:
+            py.test.raises(ValueError, "b - a")
+            py.test.raises(ValueError, "a - b")
+
 def test_cast_primitive_from_cdata():
     p = new_primitive_type("int")
     n = cast(p, cast(p, -42))
@@ -2523,6 +2536,25 @@
     assert d[2][1].bitshift == -1
     assert d[2][1].bitsize == -1
 
+def test_nested_anonymous_struct_2():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("struct foo")
+    BInnerUnion = new_union_type("union bar")
+    complete_struct_or_union(BInnerUnion, [('a1', BInt, -1),
+                                           ('a2', BInt, -1)])
+    complete_struct_or_union(BStruct, [('b1', BInt, -1),
+                                       ('', BInnerUnion, -1),
+                                       ('b2', BInt, -1)])
+    assert sizeof(BInnerUnion) == sizeof(BInt)
+    assert sizeof(BStruct) == sizeof(BInt) * 3
+    fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields]
+    assert fields == [
+        ('b1', 0 * sizeof(BInt), 0),
+        ('a1', 1 * sizeof(BInt), 0),
+        ('a2', 1 * sizeof(BInt), 1),
+        ('b2', 2 * sizeof(BInt), 0),
+    ]
+
 def test_sizeof_union():
     # a union has the largest alignment of its members, and a total size
     # that is the largest of its items *possibly further aligned* if
@@ -3341,13 +3373,18 @@
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
     BCharA = new_array_type(BCharP, None)
-    py.test.raises(TypeError, from_buffer, BCharA, b"foo")
+    p1 = from_buffer(BCharA, b"foo")
+    assert p1 == from_buffer(BCharA, b"foo")
+    import gc; gc.collect()
+    assert p1 == from_buffer(BCharA, b"foo")
     py.test.raises(TypeError, from_buffer, BCharA, u+"foo")
     try:
         from __builtin__ import buffer
     except ImportError:
         pass
     else:
+        # from_buffer(buffer(b"foo")) does not work, because it's not
+        # implemented on pypy; only from_buffer(b"foo") works.
         py.test.raises(TypeError, from_buffer, BCharA, buffer(b"foo"))
         py.test.raises(TypeError, from_buffer, BCharA, buffer(u+"foo"))
     try:
@@ -3639,3 +3676,27 @@
     check_dir(pp, [])
     check_dir(pp[0], ['a1', 'a2'])
     check_dir(pp[0][0], ['a1', 'a2'])
+
+def test_char_pointer_conversion():
+    import warnings
+    assert __version__.startswith(("1.8", "1.9")), (
+        "consider turning the warning into an error")
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    BVoidP = new_pointer_type(new_void_type())
+    z1 = cast(BCharP, 0)
+    z2 = cast(BIntP, 0)
+    z3 = cast(BVoidP, 0)
+    with warnings.catch_warnings(record=True) as w:
+        newp(new_pointer_type(BIntP), z1)    # warn
+        assert len(w) == 1
+        newp(new_pointer_type(BVoidP), z1)   # fine
+        assert len(w) == 1
+        newp(new_pointer_type(BCharP), z2)   # warn
+        assert len(w) == 2
+        newp(new_pointer_type(BVoidP), z2)   # fine
+        assert len(w) == 2
+        newp(new_pointer_type(BCharP), z3)   # fine
+        assert len(w) == 2
+        newp(new_pointer_type(BIntP), z3)    # fine
+        assert len(w) == 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/__init__.py 
new/cffi-1.8.3/cffi/__init__.py
--- old/cffi-1.7.0/cffi/__init__.py     2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/__init__.py     2016-09-17 12:21:34.000000000 +0200
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.7.0"
-__version_info__ = (1, 7, 0)
+__version__ = "1.8.3"
+__version_info__ = (1, 8, 3)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/_cffi_include.h 
new/cffi-1.8.3/cffi/_cffi_include.h
--- old/cffi-1.7.0/cffi/_cffi_include.h 2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/_cffi_include.h 2016-09-17 12:21:34.000000000 +0200
@@ -1,4 +1,20 @@
 #define _CFFI_
+
+/* We try to define Py_LIMITED_API before including Python.h.
+
+   Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and
+   Py_REF_DEBUG are not defined.  This is a best-effort approximation:
+   we can learn about Py_DEBUG from pyconfig.h, but it is unclear if
+   the same works for the other two macros.  Py_DEBUG implies them,
+   but not the other way around.
+*/
+#ifndef _CFFI_USE_EMBEDDING
+#  include <pyconfig.h>
+#  if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
+#    define Py_LIMITED_API
+#  endif
+#endif
+
 #include <Python.h>
 #ifdef __cplusplus
 extern "C" {
@@ -42,7 +58,9 @@
 #  include <stdint.h>
 # endif
 # if _MSC_VER < 1800   /* MSVC < 2013 */
-   typedef unsigned char _Bool;
+#  ifndef __cplusplus
+    typedef unsigned char _Bool;
+#  endif
 # endif
 #else
 # include <stdint.h>
@@ -59,7 +77,7 @@
 
 #ifdef __cplusplus
 # ifndef _Bool
-#  define _Bool bool   /* semi-hackish: C++ has no _Bool; bool is builtin */
+   typedef bool _Bool;   /* semi-hackish: C++ has no _Bool; bool is builtin */
 # endif
 #endif
 
@@ -196,20 +214,6 @@
     return NULL;
 }
 
-_CFFI_UNUSED_FN
-static PyObject **_cffi_unpack_args(PyObject *args_tuple, Py_ssize_t expected,
-                                    const char *fnname)
-{
-    if (PyTuple_GET_SIZE(args_tuple) != expected) {
-        PyErr_Format(PyExc_TypeError,
-                     "%.150s() takes exactly %zd arguments (%zd given)",
-                     fnname, expected, PyTuple_GET_SIZE(args_tuple));
-        return NULL;
-    }
-    return &PyTuple_GET_ITEM(args_tuple, 0);   /* pointer to the first item,
-                                                  the others follow */
-}
-
 /**********  end CPython-specific section  **********/
 #else
 _CFFI_UNUSED_FN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/_embedding.h 
new/cffi-1.8.3/cffi/_embedding.h
--- old/cffi-1.7.0/cffi/_embedding.h    2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/_embedding.h    2016-09-17 12:21:34.000000000 +0200
@@ -233,7 +233,7 @@
         f = PySys_GetObject((char *)"stderr");
         if (f != NULL && f != Py_None) {
             PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
-                               "\ncompiled with cffi version: 1.7.0"
+                               "\ncompiled with cffi version: 1.8.3"
                                "\n_cffi_backend module: ", f);
             modules = PyImport_GetModuleDict();
             mod = PyDict_GetItemString(modules, "_cffi_backend");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/api.py new/cffi-1.8.3/cffi/api.py
--- old/cffi-1.7.0/cffi/api.py  2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/api.py  2016-09-17 12:21:34.000000000 +0200
@@ -652,7 +652,7 @@
         recompile(self, module_name, source,
                   c_file=filename, call_c_compiler=False, **kwds)
 
-    def compile(self, tmpdir='.', verbose=0, target=None):
+    def compile(self, tmpdir='.', verbose=0, target=None, debug=None):
         """The 'target' argument gives the final file name of the
         compiled DLL.  Use '*' to force distutils' choice, suitable for
         regular CPython C API modules.  Use a file name ending in '.*'
@@ -669,7 +669,7 @@
         module_name, source, source_extension, kwds = self._assigned_source
         return recompile(self, module_name, source, tmpdir=tmpdir,
                          target=target, source_extension=source_extension,
-                         compiler_verbose=verbose, **kwds)
+                         compiler_verbose=verbose, debug=debug, **kwds)
 
     def init_once(self, func, tag):
         # Read _init_once_cache[tag], which is either (False, lock) if
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/backend_ctypes.py 
new/cffi-1.8.3/cffi/backend_ctypes.py
--- old/cffi-1.7.0/cffi/backend_ctypes.py       2016-06-20 16:30:45.000000000 
+0200
+++ new/cffi-1.8.3/cffi/backend_ctypes.py       2016-09-17 12:21:34.000000000 
+0200
@@ -997,29 +997,43 @@
         assert onerror is None   # XXX not implemented
         return BType(source, error)
 
+    _weakref_cache_ref = None
+
     def gcp(self, cdata, destructor):
-        BType = self.typeof(cdata)
+        if self._weakref_cache_ref is None:
+            import weakref
+            class MyRef(weakref.ref):
+                def __eq__(self, other):
+                    myref = self()
+                    return self is other or (
+                        myref is not None and myref is other())
+                def __ne__(self, other):
+                    return not (self == other)
+                def __hash__(self):
+                    try:
+                        return self._hash
+                    except AttributeError:
+                        self._hash = hash(self())
+                        return self._hash
+            self._weakref_cache_ref = {}, MyRef
+        weak_cache, MyRef = self._weakref_cache_ref
 
         if destructor is None:
-            if not (hasattr(BType, '_gcp_type') and
-                    BType._gcp_type is BType):
+            try:
+                del weak_cache[MyRef(cdata)]
+            except KeyError:
                 raise TypeError("Can remove destructor only on a object "
                                 "previously returned by ffi.gc()")
-            cdata._destructor = None
             return None
 
-        try:
-            gcp_type = BType._gcp_type
-        except AttributeError:
-            class CTypesDataGcp(BType):
-                __slots__ = ['_orig', '_destructor']
-                def __del__(self):
-                    if self._destructor is not None:
-                        self._destructor(self._orig)
-            gcp_type = BType._gcp_type = CTypesDataGcp
-        new_cdata = self.cast(gcp_type, cdata)
-        new_cdata._orig = cdata
-        new_cdata._destructor = destructor
+        def remove(k):
+            cdata, destructor = weak_cache.pop(k, (None, None))
+            if destructor is not None:
+                destructor(cdata)
+
+        new_cdata = self.cast(self.typeof(cdata), cdata)
+        assert new_cdata is not cdata
+        weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor)
         return new_cdata
 
     typeof = type
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/ffiplatform.py 
new/cffi-1.8.3/cffi/ffiplatform.py
--- old/cffi-1.7.0/cffi/ffiplatform.py  2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/ffiplatform.py  2016-09-17 12:21:34.000000000 +0200
@@ -21,12 +21,12 @@
         allsources.append(os.path.normpath(src))
     return Extension(name=modname, sources=allsources, **kwds)
 
-def compile(tmpdir, ext, compiler_verbose=0):
+def compile(tmpdir, ext, compiler_verbose=0, debug=None):
     """Compile a C extension module using distutils."""
 
     saved_environ = os.environ.copy()
     try:
-        outputfilename = _build(tmpdir, ext, compiler_verbose)
+        outputfilename = _build(tmpdir, ext, compiler_verbose, debug)
         outputfilename = os.path.abspath(outputfilename)
     finally:
         # workaround for a distutils bugs where some env vars can
@@ -36,7 +36,7 @@
                 os.environ[key] = value
     return outputfilename
 
-def _build(tmpdir, ext, compiler_verbose=0):
+def _build(tmpdir, ext, compiler_verbose=0, debug=None):
     # XXX compact but horrible :-(
     from distutils.core import Distribution
     import distutils.errors, distutils.log
@@ -44,6 +44,9 @@
     dist = Distribution({'ext_modules': [ext]})
     dist.parse_config_files()
     options = dist.get_option_dict('build_ext')
+    if debug is None:
+        debug = sys.flags.debug
+    options['debug'] = ('ffiplatform', debug)
     options['force'] = ('ffiplatform', True)
     options['build_lib'] = ('ffiplatform', tmpdir)
     options['build_temp'] = ('ffiplatform', tmpdir)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/model.py new/cffi-1.8.3/cffi/model.py
--- old/cffi-1.7.0/cffi/model.py        2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/model.py        2016-09-17 12:21:34.000000000 +0200
@@ -519,12 +519,10 @@
             smallest_value = min(self.enumvalues)
             largest_value = max(self.enumvalues)
         else:
-            import warnings
-            warnings.warn("%r has no values explicitly defined; next version "
-                          "will refuse to guess which integer type it is "
-                          "meant to be (unsigned/signed, int/long)"
-                          % self._get_c_name())
-            smallest_value = largest_value = 0
+            raise api.CDefError("%r has no values explicitly defined: "
+                                "refusing to guess which integer type it is "
+                                "meant to be (unsigned/signed, int/long)"
+                % self._get_c_name())
         if smallest_value < 0:   # needs a signed type
             sign = 1
             candidate1 = PrimitiveType("int")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/recompiler.py 
new/cffi-1.8.3/cffi/recompiler.py
--- old/cffi-1.7.0/cffi/recompiler.py   2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/recompiler.py   2016-09-17 12:21:34.000000000 +0200
@@ -275,6 +275,8 @@
     def write_c_source_to_f(self, f, preamble):
         self._f = f
         prnt = self._prnt
+        if self.ffi._embedding is not None:
+            prnt('#define _CFFI_USE_EMBEDDING')
         #
         # first the '#include' (actually done by inlining the file's content)
         lines = self._rel_readlines('_cffi_include.h')
@@ -513,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))
@@ -570,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))
@@ -683,13 +685,11 @@
             rng = range(len(tp.args))
             for i in rng:
                 prnt('  PyObject *arg%d;' % i)
-            prnt('  PyObject **aa;')
             prnt()
-            prnt('  aa = _cffi_unpack_args(args, %d, "%s");' % (len(rng), 
name))
-            prnt('  if (aa == NULL)')
+            prnt('  if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % (
+                name, len(rng), len(rng),
+                ', '.join(['&arg%d' % i for i in rng])))
             prnt('    return NULL;')
-            for i in rng:
-                prnt('  arg%d = aa[%d];' % (i, i))
         prnt()
         #
         for i, type in enumerate(tp.args):
@@ -862,6 +862,8 @@
             enumfields = list(tp.enumfields())
             for fldname, fldtype, fbitsize, fqual in enumfields:
                 fldtype = self._field_type(tp, fldname, fldtype)
+                self._check_not_opaque(fldtype,
+                                       "field '%s.%s'" % (tp.name, fldname))
                 # cname is None for _add_missing_struct_unions() only
                 op = OP_NOOP
                 if fbitsize >= 0:
@@ -911,6 +913,13 @@
                             first_field_index, c_fields))
         self._seen_struct_unions.add(tp)
 
+    def _check_not_opaque(self, tp, location):
+        while isinstance(tp, model.ArrayType):
+            tp = tp.item
+        if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None:
+            raise TypeError(
+                "%s is of an opaque type (not declared in cdef())" % location)
+
     def _add_missing_struct_unions(self):
         # not very nice, but some struct declarations might be missing
         # because they don't have any known C name.  Check that they are
@@ -1422,7 +1431,7 @@
 
 def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
               c_file=None, source_extension='.c', extradir=None,
-              compiler_verbose=1, target=None, **kwds):
+              compiler_verbose=1, target=None, debug=None, **kwds):
     if not isinstance(module_name, str):
         module_name = module_name.encode('ascii')
     if ffi._windows_unicode:
@@ -1458,7 +1467,8 @@
                 if target != '*':
                     _patch_for_target(patchlist, target)
                 os.chdir(tmpdir)
-                outputfilename = ffiplatform.compile('.', ext, 
compiler_verbose)
+                outputfilename = ffiplatform.compile('.', ext,
+                                                     compiler_verbose, debug)
             finally:
                 os.chdir(cwd)
                 _unpatch_meths(patchlist)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/setuptools_ext.py 
new/cffi-1.8.3/cffi/setuptools_ext.py
--- old/cffi-1.7.0/cffi/setuptools_ext.py       2016-06-20 16:30:45.000000000 
+0200
+++ new/cffi-1.8.3/cffi/setuptools_ext.py       2016-09-17 12:21:34.000000000 
+0200
@@ -69,16 +69,36 @@
     else:
         _add_c_module(dist, ffi, module_name, source, source_extension, kwds)
 
+def _set_py_limited_api(Extension, kwds):
+    """
+    Add py_limited_api to kwds if setuptools >= 26 is in use.
+    Do not alter the setting if it already exists.
+    Setuptools takes care of ignoring the flag on Python 2 and PyPy.
+    """
+    if 'py_limited_api' not in kwds:
+        import setuptools
+        try:
+            setuptools_major_version = 
int(setuptools.__version__.partition('.')[0])
+            if setuptools_major_version >= 26:
+                kwds['py_limited_api'] = True
+        except ValueError:  # certain development versions of setuptools
+            # If we don't know the version number of setuptools, we
+            # try to set 'py_limited_api' anyway.  At worst, we get a
+            # warning.
+            kwds['py_limited_api'] = True
+    return kwds
 
 def _add_c_module(dist, ffi, module_name, source, source_extension, kwds):
     from distutils.core import Extension
-    from distutils.command.build_ext import build_ext
+    # We are a setuptools extension. Need this build_ext for py_limited_api.
+    from setuptools.command.build_ext import build_ext
     from distutils.dir_util import mkpath
     from distutils import log
     from cffi import recompiler
 
     allsources = ['$PLACEHOLDER']
     allsources.extend(kwds.pop('sources', []))
+    kwds = _set_py_limited_api(Extension, kwds)
     ext = Extension(name=module_name, sources=allsources, **kwds)
 
     def make_mod(tmpdir, pre_run=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi/vengine_cpy.py 
new/cffi-1.8.3/cffi/vengine_cpy.py
--- old/cffi-1.7.0/cffi/vengine_cpy.py  2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/cffi/vengine_cpy.py  2016-09-17 12:21:34.000000000 +0200
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/cffi.egg-info/PKG-INFO 
new/cffi-1.8.3/cffi.egg-info/PKG-INFO
--- old/cffi-1.7.0/cffi.egg-info/PKG-INFO       2016-06-20 16:33:45.000000000 
+0200
+++ new/cffi-1.8.3/cffi.egg-info/PKG-INFO       2016-09-17 12:21:52.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.7.0
+Version: 1.8.3
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
@@ -27,5 +27,6 @@
 Classifier: Programming Language :: Python :: 3.2
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/doc/source/cdef.rst 
new/cffi-1.8.3/doc/source/cdef.rst
--- old/cffi-1.7.0/doc/source/cdef.rst  2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/doc/source/cdef.rst  2016-09-17 12:21:34.000000000 +0200
@@ -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
@@ -506,7 +504,10 @@
 ``long *``) or in other locations (e.g. a global array ``int a[5];``
 must not be misdeclared ``long a[5];``).  CFFI considers `all types listed
 above`_ as primitive (so ``long long a[5];`` and ``int64_t a[5]`` are
-different declarations).
+different declarations).  The reason for that is detailed in `a comment
+about an issue.`__
+
+.. __: 
https://bitbucket.org/cffi/cffi/issues/265/cffi-doesnt-allow-creating-pointers-to#comment-28406958
 
 
 ffibuilder.compile() etc.: compiling out-of-line modules
@@ -521,7 +522,18 @@
 the mtime to be updated anyway, delete the file before calling the
 functions.
 
-**ffibuilder.compile(tmpdir='.', verbose=False):**
+*New in version 1.8:* the C code produced by ``emit_c_code()`` or
+``compile()`` contains ``#define Py_LIMITED_API``.  This means that on
+CPython >= 3.2, compiling this source produces a binary .so/.dll that
+should work for any version of CPython >= 3.2 (as opposed to only for
+the same version of CPython x.y).  However, the standard ``distutils``
+package will still produce a file called e.g.
+``NAME.cpython-35m-x86_64-linux-gnu.so``.  You can manually rename it to
+``NAME.abi3.so``, or use setuptools version 26 or later.  Also, note
+that compiling with a debug version of Python will not actually define
+``Py_LIMITED_API``, as doing so makes ``Python.h`` unhappy.
+
+**ffibuilder.compile(tmpdir='.', verbose=False, debug=None):**
 explicitly generate the .py or .c file,
 and (if .c) compile it.  The output file is (or are) put in the
 directory given by ``tmpdir``.  In the examples given here, we use
@@ -536,6 +548,13 @@
 compiler.  (This parameter might be changed to True by default in a
 future release.)
 
+*New in version 1.8.1:* ``debug`` argument.  If set to a bool, it
+controls whether the C code is compiled in debug mode or not.  The
+default None means to use the host Python's ``sys.flags.debug``.
+Starting with version 1.8.1, if you are running a debug-mode Python, the
+C code is thus compiled in debug mode by default (note that it is anyway
+necessary to do so on Windows).
+
 **ffibuilder.emit_python_code(filename):** generate the given .py file (same
 as ``ffibuilder.compile()`` for ABI mode, with an explicitly-named file to
 write).  If you choose, you can include this .py file pre-packaged in
@@ -823,8 +842,8 @@
 .. __: distutils-setuptools_
 
 The following example should work both with old (pre-1.0) and new
-versions of CFFI---supporting both is important to run on PyPy,
-because CFFI 1.0 does not work in PyPy < 2.6:
+versions of CFFI---supporting both is important to run on old
+versions of PyPy (CFFI 1.0 does not work in PyPy < 2.6):
 
 .. code-block:: python
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/doc/source/conf.py 
new/cffi-1.8.3/doc/source/conf.py
--- old/cffi-1.7.0/doc/source/conf.py   2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/doc/source/conf.py   2016-09-17 12:21:34.000000000 +0200
@@ -45,9 +45,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '1.7'
+version = '1.8'
 # The full version, including alpha/beta/rc tags.
-release = '1.7.0'
+release = '1.8.3'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/doc/source/installation.rst 
new/cffi-1.8.3/doc/source/installation.rst
--- old/cffi-1.7.0/doc/source/installation.rst  2016-06-20 16:30:45.000000000 
+0200
+++ new/cffi-1.8.3/doc/source/installation.rst  2016-09-17 12:21:34.000000000 
+0200
@@ -51,12 +51,14 @@
 
 Download and Installation:
 
-* http://pypi.python.org/packages/source/c/cffi/cffi-1.7.0.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-1.8.3.tar.gz
 
    - MD5: ...
 
    - SHA: ...
 
+   - SHA256: ...
+
 * Or grab the most current version from the `Bitbucket page`_:
   ``hg clone https://bitbucket.org/cffi/cffi``
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/doc/source/ref.rst 
new/cffi-1.8.3/doc/source/ref.rst
--- old/cffi-1.7.0/doc/source/ref.rst   2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/doc/source/ref.rst   2016-09-17 12:21:34.000000000 +0200
@@ -171,7 +171,7 @@
 buffer interface.  This is the opposite of ``ffi.buffer()``.  It gives
 a reference to the existing data, not a copy; for this
 reason, and for PyPy compatibility, it does not work with the built-in
-types str or unicode (or buffers/memoryviews on them).
+type unicode; nor buffers/memoryviews to byte or unicode strings.
 It is meant to be used on objects
 containing large quantities of raw data, like bytearrays
 or ``array.array`` or numpy
@@ -193,6 +193,9 @@
 method is called), then the ``<cdata>`` object will point to freed
 memory and must not be used any more.
 
+*New in version 1.8:* the python_buffer can be a byte string (but still
+not a buffer/memoryview on a string).
+
 
 ffi.memmove()
 +++++++++++++
@@ -289,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
@@ -572,12 +575,12 @@
 +---------------+------------------------+------------------+----------------+
 |  pointers     | another <cdata> with   | a <cdata>        |``[]`` `(****)`,|
 |               | a compatible type (i.e.|                  |``+``, ``-``,   |
-|               | same type or ``char*`` |                  |bool()          |
+|               | same type              |                  |bool()          |
 |               | or ``void*``, or as an |                  |                |
 |               | array instead) `(*)`   |                  |                |
 +---------------+------------------------+                  |                |
-|  ``void *``,  | another <cdata> with   |                  |                |
-|  ``char *``   | any pointer or array   |                  |                |
+|  ``void *``   | another <cdata> with   |                  |                |
+|               | any pointer or array   |                  |                |
 |               | type                   |                  |                |
 +---------------+------------------------+                  +----------------+
 |  pointers to  | same as pointers       |                  | ``[]``, ``+``, |
@@ -624,12 +627,12 @@
    *`` argument might be passed as ``[[x, y]]`` or ``[{'x': 5, 'y':
    10}]``.
 
-   As an optimization, the CPython version of CFFI assumes that a
+   As an optimization, CFFI assumes that a
    function with a ``char *`` argument to which you pass a Python
    string will not actually modify the array of characters passed in,
    and so passes directly a pointer inside the Python string object.
-   (PyPy might in the future do the same, but it is harder because
-   strings are not naturally zero-terminated in PyPy.)
+   (On PyPy, this optimization is only available since PyPy 5.4
+   with CFFI 1.8.)
 
 `(**)` C function calls are done with the GIL released.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/doc/source/using.rst 
new/cffi-1.8.3/doc/source/using.rst
--- old/cffi-1.7.0/doc/source/using.rst 2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/doc/source/using.rst 2016-09-17 12:21:34.000000000 +0200
@@ -81,6 +81,33 @@
         # away, then the weak dictionary entry will be removed.
         return s1
 
+Usually you don't need a weak dict: for example, to call a function with
+a ``char * *`` argument that contains a pointer to a ``char *`` pointer,
+it is enough to do this:
+
+.. code-block:: python
+
+    p = ffi.new("char[]", "hello, world")    # p is a 'char *'
+    q = ffi.new("char **", p)                # q is a 'char **'
+    lib.myfunction(q)
+    # p is alive at least until here, so that's fine
+
+However, this is always wrong (usage of freed memory):
+
+.. code-block:: python
+
+    p = ffi.new("char **", ffi.new("char[]", "hello, world"))
+    # WRONG!  as soon as p is built, the inner ffi.new() gets freed!
+
+This is wrong too, for the same reason:
+
+.. code-block:: python
+
+    p = ffi.new("struct my_stuff")
+    p.foo = ffi.new("char[]", "hello, world")
+    # WRONG!  as soon as p.foo is set, the ffi.new() gets freed!
+
+
 The cdata objects support mostly the same operations as in C: you can
 read or write from pointers, arrays and structures.  Dereferencing a
 pointer is done usually in C with the syntax ``*p``, which is not valid
@@ -339,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
 
@@ -350,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).
-
-Before version 1.1 (or with the deprecated ``ffi.verify()``), if you
-really need a cdata pointer to the function, use the following
-workaround:
-
-.. code-block:: python
-  
-    ffi.cdef(""" int (*foo)(int a, int b); """)
+use ``ffi.addressof(lib, "name")``.
 
-i.e. declare them as pointer-to-function in the cdef (even if they are
-regular functions in the C code).
+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:
+
+* a union (but a *pointer* to a union is fine);
+
+* 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/doc/source/whatsnew.rst 
new/cffi-1.8.3/doc/source/whatsnew.rst
--- old/cffi-1.7.0/doc/source/whatsnew.rst      2016-06-20 16:30:45.000000000 
+0200
+++ new/cffi-1.8.3/doc/source/whatsnew.rst      2016-09-17 12:21:34.000000000 
+0200
@@ -3,6 +3,57 @@
 ======================
 
 
+v1.8.3
+======
+
+* When passing a ``void *`` argument to a function with a different
+  pointer type, or vice-versa, the cast occurs automatically, like in C.
+  The same occurs for initialization with ``ffi.new()`` and a few other
+  places.  However, I thought that ``char *`` had the same
+  property---but I was mistaken.  In C you get the usual warning if you
+  try to give a ``char *`` to a ``char **`` argument, for example.
+  Sorry about the confusion.  This has been fixed in CFFI by giving for
+  now a warning, too.  It will turn into an error in a future version.
+
+
+v1.8.2
+======
+
+* Issue #283: fixed ``ffi.new()`` on structures/unions with nested
+  anonymous structures/unions, when there is at least one union in
+  the mix.  When initialized with a list or a dict, it should now
+  behave more closely like the ``{ }`` syntax does in GCC.
+
+
+v1.8.1
+======
+
+* CPython 3.x: experimental: the generated C extension modules now use
+  the "limited API", which means that, as a compiled .so/.dll, it should
+  work directly on any version of CPython >= 3.2.  The name produced by
+  distutils is still version-specific.  To get the version-independent
+  name, you can rename it manually to ``NAME.abi3.so``, or use the very
+  recent setuptools 26.
+
+* Added ``ffi.compile(debug=...)``, similar to ``python setup.py build
+  --debug`` but defaulting to True if we are running a debugging
+  version of Python itself.
+
+
+v1.8
+====
+
+* Removed the restriction that ``ffi.from_buffer()`` cannot be used on
+  byte strings.  Now you can get a ``char *`` out of a byte string,
+  which is valid as long as the string object is kept alive.  (But
+  don't use it to *modify* the string object!  If you need this, use
+  ``bytearray`` or other official techniques.)
+
+* PyPy 5.4 can now pass a byte string directly to a ``char *``
+  argument (in older versions, a copy would be made).  This used to be
+  a CPython-only optimization.
+
+
 v1.7
 ====
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/setup.py new/cffi-1.8.3/setup.py
--- old/cffi-1.7.0/setup.py     2016-06-20 16:30:45.000000000 +0200
+++ new/cffi-1.8.3/setup.py     2016-09-17 12:21:34.000000000 +0200
@@ -144,7 +144,7 @@
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
 """,
-        version='1.7.0',
+        version='1.8.3',
         packages=['cffi'] if cpython else [],
         package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', 
                                '_embedding.h']}
@@ -188,6 +188,7 @@
             'Programming Language :: Python :: 3.2',
             'Programming Language :: Python :: 3.3',
             'Programming Language :: Python :: 3.4',
+            'Programming Language :: Python :: 3.5',
             'Programming Language :: Python :: Implementation :: CPython',
             'Programming Language :: Python :: Implementation :: PyPy',
         ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/testing/cffi0/backend_tests.py 
new/cffi-1.8.3/testing/cffi0/backend_tests.py
--- old/cffi-1.7.0/testing/cffi0/backend_tests.py       2016-06-20 
16:30:45.000000000 +0200
+++ new/cffi-1.8.3/testing/cffi0/backend_tests.py       2016-09-17 
12:21:34.000000000 +0200
@@ -1414,6 +1414,7 @@
         assert p.b == 12
         assert p.c == 14
         assert p.d == 14
+        py.test.raises(ValueError, ffi.new, "struct foo_s *", [0, 0, 0, 0])
 
     def test_nested_field_offset_align(self):
         ffi = FFI(backend=self.Backend())
@@ -1453,14 +1454,42 @@
         assert p.b == 0
         assert p.c == 14
         assert p.d == 14
-        p = ffi.new("union foo_u *", {'b': 12})
-        assert p.a == 0
+        p = ffi.new("union foo_u *", {'a': -63, 'b': 12})
+        assert p.a == -63
         assert p.b == 12
-        assert p.c == 0
-        assert p.d == 0
-        # we cannot specify several items in the dict, even though
-        # in theory in this particular case it would make sense
-        # to give both 'a' and 'b'
+        assert p.c == -63
+        assert p.d == -63
+        p = ffi.new("union foo_u *", [123, 456])
+        assert p.a == 123
+        assert p.b == 456
+        assert p.c == 123
+        assert p.d == 123
+        py.test.raises(ValueError, ffi.new, "union foo_u *", [0, 0, 0])
+
+    def test_nested_anonymous_struct_2(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            struct foo_s {
+                int a;
+                union { int b; union { int c, d; }; };
+                int e;
+            };
+        """)
+        assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
+        p = ffi.new("struct foo_s *", [11, 22, 33])
+        assert p.a == 11
+        assert p.b == p.c == p.d == 22
+        assert p.e == 33
+        py.test.raises(ValueError, ffi.new, "struct foo_s *", [11, 22, 33, 44])
+        FOO = ffi.typeof("struct foo_s")
+        fields = [(name, fld.offset, fld.flags) for (name, fld) in FOO.fields]
+        assert fields == [
+            ('a', 0 * SIZE_OF_INT, 0),
+            ('b', 1 * SIZE_OF_INT, 0),
+            ('c', 1 * SIZE_OF_INT, 1),
+            ('d', 1 * SIZE_OF_INT, 1),
+            ('e', 2 * SIZE_OF_INT, 0),
+        ]
 
     def test_cast_to_array_type(self):
         ffi = FFI(backend=self.Backend())
@@ -1478,6 +1507,7 @@
             assert p1[0] == 123
             seen.append(1)
         q = ffi.gc(p, destructor)
+        assert ffi.typeof(q) is ffi.typeof(p)
         import gc; gc.collect()
         assert seen == []
         del q
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/testing/cffi0/test_ctypes.py 
new/cffi-1.8.3/testing/cffi0/test_ctypes.py
--- old/cffi-1.7.0/testing/cffi0/test_ctypes.py 2016-06-20 16:30:45.000000000 
+0200
+++ new/cffi-1.8.3/testing/cffi0/test_ctypes.py 2016-09-17 12:21:34.000000000 
+0200
@@ -34,6 +34,9 @@
     def test_nested_anonymous_union(self):
         py.test.skip("ctypes backend: not supported: nested anonymous union")
 
+    def test_nested_anonymous_struct_2(self):
+        py.test.skip("ctypes backend: not supported: nested anonymous union")
+
     def test_CData_CType_2(self):
         if sys.version_info >= (3,):
             py.test.skip("ctypes backend: not supported in Python 3: CType")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/testing/cffi0/test_ownlib.py 
new/cffi-1.8.3/testing/cffi0/test_ownlib.py
--- old/cffi-1.7.0/testing/cffi0/test_ownlib.py 2016-06-20 16:30:45.000000000 
+0200
+++ new/cffi-1.8.3/testing/cffi0/test_ownlib.py 2016-09-17 12:21:34.000000000 
+0200
@@ -129,7 +129,7 @@
                 cls.module = str(udir.join('testownlib.dll'))
         else:
             subprocess.check_call(
-                'gcc testownlib.c -shared -fPIC -o testownlib.so',
+                'cc testownlib.c -shared -fPIC -o testownlib.so',
                 cwd=str(udir), shell=True)
             cls.module = str(udir.join('testownlib.so'))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/testing/cffi0/test_zintegration.py 
new/cffi-1.8.3/testing/cffi0/test_zintegration.py
--- old/cffi-1.7.0/testing/cffi0/test_zintegration.py   2016-06-20 
16:30:45.000000000 +0200
+++ new/cffi-1.8.3/testing/cffi0/test_zintegration.py   2016-09-17 
12:21:34.000000000 +0200
@@ -148,3 +148,28 @@
         p = snip_setuptools_verify2.C.getpwuid(0)
         assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
         ''')
+
+    def test_set_py_limited_api(self):
+        from cffi.setuptools_ext import _set_py_limited_api
+        try:
+            import setuptools
+        except ImportError as e:
+            py.test.skip(str(e))
+        orig_version = setuptools.__version__
+        try:
+            setuptools.__version__ = '26.0.0'
+            from setuptools import Extension
+
+            kwds = _set_py_limited_api(Extension, {})
+            assert kwds['py_limited_api'] == True
+
+            setuptools.__version__ = '25.0'
+            kwds = _set_py_limited_api(Extension, {})
+            assert not kwds
+
+            setuptools.__version__ = 'development'
+            kwds = _set_py_limited_api(Extension, {})
+            assert kwds['py_limited_api'] == True
+
+        finally:
+            setuptools.__version__ = orig_version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.7.0/testing/cffi1/test_recompiler.py 
new/cffi-1.8.3/testing/cffi1/test_recompiler.py
--- old/cffi-1.7.0/testing/cffi1/test_recompiler.py     2016-06-20 
16:30:45.000000000 +0200
+++ new/cffi-1.8.3/testing/cffi1/test_recompiler.py     2016-09-17 
12:21:34.000000000 +0200
@@ -851,9 +851,12 @@
     assert str(e2.value) == "foo0() takes no arguments (2 given)"
     assert str(e3.value) == "foo1() takes exactly one argument (0 given)"
     assert str(e4.value) == "foo1() takes exactly one argument (2 given)"
-    assert str(e5.value) == "foo2() takes exactly 2 arguments (0 given)"
-    assert str(e6.value) == "foo2() takes exactly 2 arguments (1 given)"
-    assert str(e7.value) == "foo2() takes exactly 2 arguments (3 given)"
+    assert str(e5.value) in ["foo2 expected 2 arguments, got 0",
+                             "foo2() takes exactly 2 arguments (0 given)"]
+    assert str(e6.value) in ["foo2 expected 2 arguments, got 1",
+                             "foo2() takes exactly 2 arguments (1 given)"]
+    assert str(e7.value) in ["foo2 expected 2 arguments, got 3",
+                             "foo2() takes exactly 2 arguments (3 given)"]
 
 def test_address_of_function():
     ffi = FFI()
@@ -1915,3 +1918,65 @@
     ffi.cdef("bool f(void);")
     lib = verify(ffi, "test_bool_in_cpp", "char f(void) { return 2; }")
     assert lib.f() == 1
+
+def test_bool_in_cpp_2():
+    ffi = FFI()
+    ffi.cdef('int add(int a, int b);')
+    lib = verify(ffi, "test_bool_bug_cpp", '''
+        typedef bool _Bool;  /* there is a Windows header with this line */
+        int add(int a, int b)
+        {
+            return a + b;
+        }''', source_extension='.cpp')
+    c = lib.add(2, 3)
+    assert c == 5
+
+def test_struct_field_opaque():
+    ffi = FFI()
+    ffi.cdef("struct a { struct b b; };")
+    e = py.test.raises(TypeError, verify,
+                       ffi, "test_struct_field_opaque", "?")
+    assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
+                            " type (not declared in cdef())")
+    ffi = FFI()
+    ffi.cdef("struct a { struct b b[2]; };")
+    e = py.test.raises(TypeError, verify,
+                       ffi, "test_struct_field_opaque", "?")
+    assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
+                            " type (not declared in cdef())")
+    ffi = FFI()
+    ffi.cdef("struct a { struct b b[]; };")
+    e = py.test.raises(TypeError, verify,
+                       ffi, "test_struct_field_opaque", "?")
+    assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
+                            " type (not declared in cdef())")
+
+def test_function_arg_opaque():
+    py.test.skip("can currently declare a function with an opaque struct "
+                 "as argument, but AFAICT it's impossible to call it later")
+
+def test_function_returns_opaque():
+    ffi = FFI()
+    ffi.cdef("struct a foo(int);")
+    e = py.test.raises(TypeError, verify,
+                       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 aaa { int a; ...; }; struct aaa f1(int);")
+    lib = verify(ffi, "test_function_returns_partial_struct", """
+        struct aaa { int b, a, c; };
+        static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; }
+    """)
+    assert lib.f1(52).a == 52


Reply via email to