[pypy-commit] cffi release-1.3: merge default for release 1.3.1

arigo noreply at buildbot.pypy.org
Wed Nov 18 10:55:32 EST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: release-1.3
Changeset: r2418:9a35705472a8
Date: 2015-11-18 15:46 +0100
http://bitbucket.org/cffi/cffi/changeset/9a35705472a8/

Log:	merge default for release 1.3.1

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5861,6 +5861,9 @@
                            (PyObject *)&CTypeDescr_Type);
 }
 
+/* forward, in commontypes.c */
+static PyObject *b__get_common_types(PyObject *self, PyObject *arg);
+
 static PyObject *b_gcp(PyObject *self, PyObject *args, PyObject *kwds)
 {
     CDataObject *cd;
@@ -6187,6 +6190,7 @@
     {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS},
 #endif
     {"_get_types", b__get_types, METH_NOARGS},
+    {"_get_common_types", b__get_common_types, METH_O},
     {"_testfunc", b__testfunc, METH_VARARGS},
     {"_testbuff", b__testbuff, METH_VARARGS},
     {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, METH_O},
@@ -6447,7 +6451,7 @@
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
         INITERROR;
 
-    v = PyText_FromString("1.3.0");
+    v = PyText_FromString("1.3.1");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
diff --git a/c/cffi1_module.c b/c/cffi1_module.c
--- a/c/cffi1_module.c
+++ b/c/cffi1_module.c
@@ -15,6 +15,7 @@
 #include "cglob.c"
 #include "lib_obj.c"
 #include "cdlopen.c"
+#include "commontypes.c"
 
 
 static int init_ffi_lib(PyObject *m)
diff --git a/c/commontypes.c b/c/commontypes.c
new file mode 100644
--- /dev/null
+++ b/c/commontypes.c
@@ -0,0 +1,215 @@
+/* This file must be kept in alphabetical order.  See test_commontypes.py */
+
+#define EQ(key, value)    key "\0" value   /* string concatenation */
+#ifdef _WIN64
+#  define W32_64(X,Y)  Y
+# else
+#  define W32_64(X,Y)  X
+# endif
+
+
+static const char *common_simple_types[] = {
+
+#ifdef MS_WIN32   /* Windows types */
+    EQ("ATOM", "WORD"),
+    EQ("BOOL", "int"),
+    EQ("BOOLEAN", "BYTE"),
+    EQ("BYTE", "unsigned char"),
+    EQ("CCHAR", "char"),
+    EQ("CHAR", "char"),
+    EQ("COLORREF", "DWORD"),
+    EQ("DWORD", "unsigned long"),
+    EQ("DWORD32", "unsigned int"),
+    EQ("DWORD64", "unsigned long long"),
+    EQ("DWORDLONG", "ULONGLONG"),
+    EQ("DWORD_PTR", "ULONG_PTR"),
+#endif
+
+    EQ("FILE", "struct _IO_FILE"),
+
+#ifdef MS_WIN32   /* more Windows types */
+    EQ("FLOAT", "float"),
+    EQ("HACCEL", "HANDLE"),
+    EQ("HALF_PTR", W32_64("short","int")),
+    EQ("HANDLE", "PVOID"),
+    EQ("HBITMAP", "HANDLE"),
+    EQ("HBRUSH", "HANDLE"),
+    EQ("HCOLORSPACE", "HANDLE"),
+    EQ("HCONV", "HANDLE"),
+    EQ("HCONVLIST", "HANDLE"),
+    EQ("HCURSOR", "HICON"),
+    EQ("HDC", "HANDLE"),
+    EQ("HDDEDATA", "HANDLE"),
+    EQ("HDESK", "HANDLE"),
+    EQ("HDROP", "HANDLE"),
+    EQ("HDWP", "HANDLE"),
+    EQ("HENHMETAFILE", "HANDLE"),
+    EQ("HFILE", "int"),
+    EQ("HFONT", "HANDLE"),
+    EQ("HGDIOBJ", "HANDLE"),
+    EQ("HGLOBAL", "HANDLE"),
+    EQ("HHOOK", "HANDLE"),
+    EQ("HICON", "HANDLE"),
+    EQ("HINSTANCE", "HANDLE"),
+    EQ("HKEY", "HANDLE"),
+    EQ("HKL", "HANDLE"),
+    EQ("HLOCAL", "HANDLE"),
+    EQ("HMENU", "HANDLE"),
+    EQ("HMETAFILE", "HANDLE"),
+    EQ("HMODULE", "HINSTANCE"),
+    EQ("HMONITOR", "HANDLE"),
+    EQ("HPALETTE", "HANDLE"),
+    EQ("HPEN", "HANDLE"),
+    EQ("HRESULT", "LONG"),
+    EQ("HRGN", "HANDLE"),
+    EQ("HRSRC", "HANDLE"),
+    EQ("HSZ", "HANDLE"),
+    EQ("HWND", "HANDLE"),
+    EQ("INT", "int"),
+    EQ("INT16", "short"),
+    EQ("INT32", "int"),
+    EQ("INT64", "long long"),
+    EQ("INT8", "signed char"),
+    EQ("INT_PTR", W32_64("int","long long")),
+    EQ("LANGID", "WORD"),
+    EQ("LCID", "DWORD"),
+    EQ("LCTYPE", "DWORD"),
+    EQ("LGRPID", "DWORD"),
+    EQ("LONG", "long"),
+    EQ("LONG32", "int"),
+    EQ("LONG64", "long long"),
+    EQ("LONGLONG", "long long"),
+    EQ("LONG_PTR", W32_64("long","long long")),
+    EQ("LPARAM", "LONG_PTR"),
+    EQ("LPBOOL", "BOOL *"),
+    EQ("LPBYTE", "BYTE *"),
+    EQ("LPCOLORREF", "DWORD *"),
+    EQ("LPCSTR", "const char *"),
+    EQ("LPCVOID", "const void *"),
+    EQ("LPCWSTR", "const WCHAR *"),
+    EQ("LPDWORD", "DWORD *"),
+    EQ("LPHANDLE", "HANDLE *"),
+    EQ("LPINT", "int *"),
+    EQ("LPLONG", "long *"),
+    EQ("LPSTR", "CHAR *"),
+    EQ("LPVOID", "void *"),
+    EQ("LPWORD", "WORD *"),
+    EQ("LPWSTR", "WCHAR *"),
+    EQ("LRESULT", "LONG_PTR"),
+    EQ("PBOOL", "BOOL *"),
+    EQ("PBOOLEAN", "BOOLEAN *"),
+    EQ("PBYTE", "BYTE *"),
+    EQ("PCHAR", "CHAR *"),
+    EQ("PCSTR", "const CHAR *"),
+    EQ("PCWSTR", "const WCHAR *"),
+    EQ("PDWORD", "DWORD *"),
+    EQ("PDWORD32", "DWORD32 *"),
+    EQ("PDWORD64", "DWORD64 *"),
+    EQ("PDWORDLONG", "DWORDLONG *"),
+    EQ("PDWORD_PTR", "DWORD_PTR *"),
+    EQ("PFLOAT", "FLOAT *"),
+    EQ("PHALF_PTR", "HALF_PTR *"),
+    EQ("PHANDLE", "HANDLE *"),
+    EQ("PHKEY", "HKEY *"),
+    EQ("PINT", "int *"),
+    EQ("PINT16", "INT16 *"),
+    EQ("PINT32", "INT32 *"),
+    EQ("PINT64", "INT64 *"),
+    EQ("PINT8", "INT8 *"),
+    EQ("PINT_PTR", "INT_PTR *"),
+    EQ("PLCID", "PDWORD"),
+    EQ("PLONG", "LONG *"),
+    EQ("PLONG32", "LONG32 *"),
+    EQ("PLONG64", "LONG64 *"),
+    EQ("PLONGLONG", "LONGLONG *"),
+    EQ("PLONG_PTR", "LONG_PTR *"),
+    EQ("PSHORT", "SHORT *"),
+    EQ("PSIZE_T", "SIZE_T *"),
+    EQ("PSSIZE_T", "SSIZE_T *"),
+    EQ("PSTR", "CHAR *"),
+    EQ("PUCHAR", "UCHAR *"),
+    EQ("PUHALF_PTR", "UHALF_PTR *"),
+    EQ("PUINT", "UINT *"),
+    EQ("PUINT16", "UINT16 *"),
+    EQ("PUINT32", "UINT32 *"),
+    EQ("PUINT64", "UINT64 *"),
+    EQ("PUINT8", "UINT8 *"),
+    EQ("PUINT_PTR", "UINT_PTR *"),
+    EQ("PULONG", "ULONG *"),
+    EQ("PULONG32", "ULONG32 *"),
+    EQ("PULONG64", "ULONG64 *"),
+    EQ("PULONGLONG", "ULONGLONG *"),
+    EQ("PULONG_PTR", "ULONG_PTR *"),
+    EQ("PUSHORT", "USHORT *"),
+    EQ("PVOID", "void *"),
+    EQ("PWCHAR", "WCHAR *"),
+    EQ("PWORD", "WORD *"),
+    EQ("PWSTR", "WCHAR *"),
+    EQ("QWORD", "unsigned long long"),
+    EQ("SC_HANDLE", "HANDLE"),
+    EQ("SC_LOCK", "LPVOID"),
+    EQ("SERVICE_STATUS_HANDLE", "HANDLE"),
+    EQ("SHORT", "short"),
+    EQ("SIZE_T", "ULONG_PTR"),
+    EQ("SSIZE_T", "LONG_PTR"),
+    EQ("UCHAR", "unsigned char"),
+    EQ("UHALF_PTR", W32_64("unsigned short","unsigned int")),
+    EQ("UINT", "unsigned int"),
+    EQ("UINT16", "unsigned short"),
+    EQ("UINT32", "unsigned int"),
+    EQ("UINT64", "unsigned long long"),
+    EQ("UINT8", "unsigned char"),
+    EQ("UINT_PTR", W32_64("unsigned int","unsigned long long")),
+    EQ("ULONG", "unsigned long"),
+    EQ("ULONG32", "unsigned int"),
+    EQ("ULONG64", "unsigned long long"),
+    EQ("ULONGLONG", "unsigned long long"),
+    EQ("ULONG_PTR", W32_64("unsigned long","unsigned long long")),
+    EQ("USHORT", "unsigned short"),
+    EQ("USN", "LONGLONG"),
+    EQ("VOID", "void"),
+    EQ("WCHAR", "wchar_t"),
+    EQ("WINSTA", "HANDLE"),
+    EQ("WORD", "unsigned short"),
+    EQ("WPARAM", "UINT_PTR"),
+#endif
+
+    EQ("bool", "_Bool"),
+};
+
+
+#undef EQ
+#undef W32_64
+
+#define num_common_simple_types    \
+    (sizeof(common_simple_types) / sizeof(common_simple_types[0]))
+
+
+static const char *get_common_type(const char *search, size_t search_len)
+{
+    const char *entry;
+    int index = search_sorted(common_simple_types, sizeof(const char *),
+                              num_common_simple_types, search, search_len);
+    if (index < 0)
+        return NULL;
+
+    entry = common_simple_types[index];
+    return entry + strlen(entry) + 1;
+}
+
+static PyObject *b__get_common_types(PyObject *self, PyObject *arg)
+{
+    int i, err;
+    for (i = 0; i < num_common_simple_types; i++) {
+        const char *s = common_simple_types[i];
+        PyObject *o = PyText_FromString(s + strlen(s) + 1);
+        if (o == NULL)
+            return NULL;
+        err = PyDict_SetItemString(arg, s, o);
+        Py_DECREF(o);
+        if (err < 0)
+            return NULL;
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
--- a/c/ffi_obj.c
+++ b/c/ffi_obj.c
@@ -361,7 +361,19 @@
                     &PyTuple_GET_ITEM(allocator, 1));
 }
 
-PyDoc_STRVAR(ffi_new_allocator_doc, "XXX");
+PyDoc_STRVAR(ffi_new_allocator_doc,
+"Return a new allocator, i.e. a function that behaves like ffi.new()\n"
+"but uses the provided low-level 'alloc' and 'free' functions.\n"
+"\n"
+"'alloc' is called with the size as argument.  If it returns NULL, a\n"
+"MemoryError is raised.  'free' is called with the result of 'alloc'\n"
+"as argument.  Both can be either Python functions or directly C\n"
+"functions.  If 'free' is None, then no free function is called.\n"
+"If both 'alloc' and 'free' are None, the default is used.\n"
+"\n"
+"If 'should_clear_after_alloc' is set to False, then the memory\n"
+"returned by 'alloc' is assumed to be already cleared (or you are\n"
+"fine with garbage); otherwise CFFI will clear it.");
 
 static PyObject *ffi_new_allocator(FFIObject *self, PyObject *args,
                                    PyObject *kwds)
diff --git a/c/parse_c_type.c b/c/parse_c_type.c
--- a/c/parse_c_type.c
+++ b/c/parse_c_type.c
@@ -220,6 +220,8 @@
 #define MAX_SSIZE_T  (((size_t)-1) >> 1)
 
 static int parse_complete(token_t *tok);
+static const char *get_common_type(const char *search, size_t search_len);
+static int parse_common_type_replacement(token_t *tok, const char *replacement);
 
 static int parse_sequel(token_t *tok, int outer)
 {
@@ -442,26 +444,34 @@
     return _CFFI_GETARG(result);
 }
 
+static int search_sorted(const char *const *base,
+                         size_t item_size, int array_len,
+                         const char *search, size_t search_len)
+{
+    int left = 0, right = array_len;
+    const char *baseptr = (const char *)base;
 
-#define MAKE_SEARCH_FUNC(FIELD)                                 \
-  static                                                        \
-  int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \
-                        const char *search, size_t search_len)  \
-  {                                                             \
-      int left = 0, right = ctx->num_##FIELD;                   \
-                                                                \
-      while (left < right) {                                    \
-          int middle = (left + right) / 2;                      \
-          const char *src = ctx->FIELD[middle].name;            \
-          int diff = strncmp(src, search, search_len);          \
-          if (diff == 0 && src[search_len] == '\0')             \
-              return middle;                                    \
-          else if (diff >= 0)                                   \
-              right = middle;                                   \
-          else                                                  \
-              left = middle + 1;                                \
-      }                                                         \
-      return -1;                                                \
+    while (left < right) {
+        int middle = (left + right) / 2;
+        const char *src = *(const char *const *)(baseptr + middle * item_size);
+        int diff = strncmp(src, search, search_len);
+        if (diff == 0 && src[search_len] == '\0')
+            return middle;
+        else if (diff >= 0)
+            right = middle;
+        else
+            left = middle + 1;
+    }
+    return -1;
+}
+
+#define MAKE_SEARCH_FUNC(FIELD)                                         \
+  static                                                                \
+  int search_in_##FIELD(const struct _cffi_type_context_s *ctx,         \
+                        const char *search, size_t search_len)          \
+  {                                                                     \
+      return search_sorted(&ctx->FIELD->name, sizeof(*ctx->FIELD),      \
+                           ctx->num_##FIELD, search, search_len);       \
   }
 
 MAKE_SEARCH_FUNC(globals)
@@ -715,6 +725,7 @@
             break;
         case TOK_IDENTIFIER:
         {
+            const char *replacement;
             int n = search_in_typenames(tok->info->ctx, tok->p, tok->size);
             if (n >= 0) {
                 t1 = _CFFI_OP(_CFFI_OP_TYPENAME, n);
@@ -725,6 +736,14 @@
                 t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, n);
                 break;
             }
+            replacement = get_common_type(tok->p, tok->size);
+            if (replacement != NULL) {
+                n = parse_common_type_replacement(tok, replacement);
+                if (n < 0)
+                    return parse_error(tok, "internal error, please report!");
+                t1 = _CFFI_OP(_CFFI_OP_NOOP, n);
+                break;
+            }
             return parse_error(tok, "undefined type name");
         }
         case TOK_STRUCT:
@@ -736,10 +755,15 @@
                 return parse_error(tok, "struct or union name expected");
 
             n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size);
-            if (n < 0)
-                return parse_error(tok, "undefined struct/union name");
-            if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) != 0)
-                ^ (kind == TOK_UNION))
+            if (n < 0) {
+                if (kind == TOK_STRUCT && tok->size == 8 &&
+                        !memcmp(tok->p, "_IO_FILE", 8))
+                    n = _CFFI__IO_FILE_STRUCT;
+                else
+                    return parse_error(tok, "undefined struct/union name");
+            }
+            else if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION)
+                      != 0) ^ (kind == TOK_UNION))
                 return parse_error(tok, "wrong kind of tag: struct vs union");
 
             t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n);
@@ -770,7 +794,8 @@
 
 
 static
-int parse_c_type(struct _cffi_parse_info_s *info, const char *input)
+int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index,
+                      const char *input)
 {
     int result;
     token_t token;
@@ -781,12 +806,26 @@
     token.p = input;
     token.size = 0;
     token.output = info->output;
-    token.output_index = 0;
+    token.output_index = *output_index;
 
     next_token(&token);
     result = parse_complete(&token);
 
+    *output_index = token.output_index;
     if (token.kind != TOK_END)
         return parse_error(&token, "unexpected symbol");
     return result;
 }
+
+static
+int parse_c_type(struct _cffi_parse_info_s *info, const char *input)
+{
+    size_t output_index = 0;
+    return parse_c_type_from(info, &output_index, input);
+}
+
+static
+int parse_common_type_replacement(token_t *tok, const char *replacement)
+{
+    return parse_c_type_from(tok->info, &tok->output_index, replacement);
+}
diff --git a/c/realize_c_type.c b/c/realize_c_type.c
--- a/c/realize_c_type.c
+++ b/c/realize_c_type.c
@@ -314,6 +314,16 @@
     _cffi_opcode_t op2;
     const struct _cffi_struct_union_s *s;
 
+    if (sindex == _CFFI__IO_FILE_STRUCT) {
+        /* returns a single global cached opaque type */
+        static PyObject *file_struct = NULL;
+        if (file_struct == NULL)
+            file_struct = new_struct_or_union_type("FILE",
+                                                   CT_STRUCT | CT_IS_FILE);
+        Py_XINCREF(file_struct);
+        return file_struct;
+    }
+
     s = &builder->ctx.struct_unions[sindex];
     op2 = builder->ctx.types[s->type_index];
     if ((((uintptr_t)op2) & 1) == 0) {
@@ -330,9 +340,9 @@
                           (s->flags & _CFFI_F_UNION) ? "union " : "struct ",
                           s->name);
             if (strcmp(name, "struct _IO_FILE") == 0)
-                flags |= CT_IS_FILE;
-
-            x = new_struct_or_union_type(name, flags);
+                x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT);
+            else
+                x = new_struct_or_union_type(name, flags);
             if (x == NULL)
                 return NULL;
 
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -7,12 +7,12 @@
     sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
 _setup_path()
 from _cffi_backend import *
-from _cffi_backend import _testfunc, _get_types, __version__
+from _cffi_backend import _testfunc, _get_types, _get_common_types, __version__
 
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.3.0", ("This test_c.py file is for testing a version"
+assert __version__ == "1.3.1", ("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,):
@@ -3520,3 +3520,8 @@
         assert repr(BFunc) == "<ctype 'int(__stdcall *)(int, int)'>"
     else:
         assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"
+
+def test_get_common_types():
+    d = {}
+    _get_common_types(d)
+    assert d['bool'] == '_Bool'
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.3.0"
-__version_info__ = (1, 3, 0)
+__version__ = "1.3.1"
+__version_info__ = (1, 3, 1)
 
 # 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 --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -110,6 +110,8 @@
 _UNKNOWN_FLOAT_PRIM    = -2
 _UNKNOWN_LONG_DOUBLE   = -3
 
+_IO_FILE_STRUCT        = -1
+
 PRIMITIVE_TO_INDEX = {
     'char':               PRIM_CHAR,
     'short':              PRIM_SHORT,
diff --git a/cffi/commontypes.py b/cffi/commontypes.py
--- a/cffi/commontypes.py
+++ b/cffi/commontypes.py
@@ -2,10 +2,17 @@
 from . import api, model
 
 
-COMMON_TYPES = {
-    'FILE': model.unknown_type('FILE', '_IO_FILE'),
-    'bool': '_Bool',
-    }
+COMMON_TYPES = {}
+
+try:
+    # fetch "bool" and all simple Windows types
+    from _cffi_backend import _get_common_types
+    _get_common_types(COMMON_TYPES)
+except ImportError:
+    pass
+
+COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE')
+COMMON_TYPES['bool'] = '_Bool'    # in case we got ImportError above
 
 for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
     if _type.endswith('_t'):
@@ -14,212 +21,35 @@
 
 _CACHE = {}
 
-def resolve_common_type(commontype):
+def resolve_common_type(parser, commontype):
     try:
         return _CACHE[commontype]
     except KeyError:
-        result = COMMON_TYPES.get(commontype, commontype)
-        if not isinstance(result, str):
-            pass    # result is already a BaseType
-        elif result.endswith(' *'):
-            if result.startswith('const '):
-                result = model.ConstPointerType(
-                    resolve_common_type(result[6:-2]))
-            else:
-                result = model.PointerType(resolve_common_type(result[:-2]))
-        elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
-            result = model.PrimitiveType(result)
-        elif result == 'set-unicode-needed':
+        cdecl = COMMON_TYPES.get(commontype, commontype)
+        if not isinstance(cdecl, str):
+            result, quals = cdecl, 0    # cdecl is already a BaseType
+        elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
+            result, quals = model.PrimitiveType(cdecl), 0
+        elif cdecl == 'set-unicode-needed':
             raise api.FFIError("The Windows type %r is only available after "
                                "you call ffi.set_unicode()" % (commontype,))
         else:
-            if commontype == result:
+            if commontype == cdecl:
                 raise api.FFIError("Unsupported type: %r.  Please file a bug "
                                    "if you think it should be." % (commontype,))
-            result = resolve_common_type(result)   # recursively
+            result, quals = parser.parse_type_and_quals(cdecl)   # recursive
+
         assert isinstance(result, model.BaseTypeByIdentity)
-        _CACHE[commontype] = result
-        return result
+        _CACHE[commontype] = result, quals
+        return result, quals
 
 
 # ____________________________________________________________
-# Windows common types
+# extra types for Windows (most of them are in commontypes.c)
 
 
-def win_common_types(maxsize):
-    result = {}
-    if maxsize < (1<<32):
-        result.update({      # Windows 32-bits
-            'HALF_PTR': 'short',
-            'INT_PTR': 'int',
-            'LONG_PTR': 'long',
-            'UHALF_PTR': 'unsigned short',
-            'UINT_PTR': 'unsigned int',
-            'ULONG_PTR': 'unsigned long',
-            })
-    else:
-        result.update({      # Windows 64-bits
-            'HALF_PTR': 'int',
-            'INT_PTR': 'long long',
-            'LONG_PTR': 'long long',
-            'UHALF_PTR': 'unsigned int',
-            'UINT_PTR': 'unsigned long long',
-            'ULONG_PTR': 'unsigned long long',
-            })
-    result.update({
-        "BYTE": "unsigned char",
-        "BOOL": "int",
-        "CCHAR": "char",
-        "CHAR": "char",
-        "DWORD": "unsigned long",
-        "DWORD32": "unsigned int",
-        "DWORD64": "unsigned long long",
-        "FLOAT": "float",
-        "INT": "int",
-        "INT8": "signed char",
-        "INT16": "short",
-        "INT32": "int",
-        "INT64": "long long",
-        "LONG": "long",
-        "LONGLONG": "long long",
-        "LONG32": "int",
-        "LONG64": "long long",
-        "WORD": "unsigned short",
-        "PVOID": model.voidp_type,
-        "ULONGLONG": "unsigned long long",
-        "WCHAR": "wchar_t",
-        "SHORT": "short",
-        "UCHAR": "unsigned char",
-        "UINT": "unsigned int",
-        "UINT8": "unsigned char",
-        "UINT16": "unsigned short",
-        "UINT32": "unsigned int",
-        "UINT64": "unsigned long long",
-        "ULONG": "unsigned long",
-        "ULONG32": "unsigned int",
-        "ULONG64": "unsigned long long",
-        "USHORT": "unsigned short",
-
-        "SIZE_T": "ULONG_PTR",
-        "SSIZE_T": "LONG_PTR",
-        "ATOM": "WORD",
-        "BOOLEAN": "BYTE",
-        "COLORREF": "DWORD",
-
-        "HANDLE": "PVOID",
-        "DWORDLONG": "ULONGLONG",
-        "DWORD_PTR": "ULONG_PTR",
-        "HACCEL": "HANDLE",
-
-        "HBITMAP": "HANDLE",
-        "HBRUSH": "HANDLE",
-        "HCOLORSPACE": "HANDLE",
-        "HCONV": "HANDLE",
-        "HCONVLIST": "HANDLE",
-        "HDC": "HANDLE",
-        "HDDEDATA": "HANDLE",
-        "HDESK": "HANDLE",
-        "HDROP": "HANDLE",
-        "HDWP": "HANDLE",
-        "HENHMETAFILE": "HANDLE",
-        "HFILE": "int",
-        "HFONT": "HANDLE",
-        "HGDIOBJ": "HANDLE",
-        "HGLOBAL": "HANDLE",
-        "HHOOK": "HANDLE",
-        "HICON": "HANDLE",
-        "HCURSOR": "HICON",
-        "HINSTANCE": "HANDLE",
-        "HKEY": "HANDLE",
-        "HKL": "HANDLE",
-        "HLOCAL": "HANDLE",
-        "HMENU": "HANDLE",
-        "HMETAFILE": "HANDLE",
-        "HMODULE": "HINSTANCE",
-        "HMONITOR": "HANDLE",
-        "HPALETTE": "HANDLE",
-        "HPEN": "HANDLE",
-        "HRESULT": "LONG",
-        "HRGN": "HANDLE",
-        "HRSRC": "HANDLE",
-        "HSZ": "HANDLE",
-        "WINSTA": "HANDLE",
-        "HWND": "HANDLE",
-
-        "LANGID": "WORD",
-        "LCID": "DWORD",
-        "LCTYPE": "DWORD",
-        "LGRPID": "DWORD",
-        "LPARAM": "LONG_PTR",
-        "LPBOOL": "BOOL *",
-        "LPBYTE": "BYTE *",
-        "LPCOLORREF": "DWORD *",
-        "LPCSTR": "const char *",
-
-        "LPCVOID": model.const_voidp_type,
-        "LPCWSTR": "const WCHAR *",
-        "LPDWORD": "DWORD *",
-        "LPHANDLE": "HANDLE *",
-        "LPINT": "int *",
-        "LPLONG": "long *",
-        "LPSTR": "CHAR *",
-        "LPWSTR": "WCHAR *",
-        "LPVOID": model.voidp_type,
-        "LPWORD": "WORD *",
-        "LRESULT": "LONG_PTR",
-        "PBOOL": "BOOL *",
-        "PBOOLEAN": "BOOLEAN *",
-        "PBYTE": "BYTE *",
-        "PCHAR": "CHAR *",
-        "PCSTR": "const CHAR *",
-        "PCWSTR": "const WCHAR *",
-        "PDWORD": "DWORD *",
-        "PDWORDLONG": "DWORDLONG *",
-        "PDWORD_PTR": "DWORD_PTR *",
-        "PDWORD32": "DWORD32 *",
-        "PDWORD64": "DWORD64 *",
-        "PFLOAT": "FLOAT *",
-        "PHALF_PTR": "HALF_PTR *",
-        "PHANDLE": "HANDLE *",
-        "PHKEY": "HKEY *",
-        "PINT": "int *",
-        "PINT_PTR": "INT_PTR *",
-        "PINT8": "INT8 *",
-        "PINT16": "INT16 *",
-        "PINT32": "INT32 *",
-        "PINT64": "INT64 *",
-        "PLCID": "PDWORD",
-        "PLONG": "LONG *",
-        "PLONGLONG": "LONGLONG *",
-        "PLONG_PTR": "LONG_PTR *",
-        "PLONG32": "LONG32 *",
-        "PLONG64": "LONG64 *",
-        "PSHORT": "SHORT *",
-        "PSIZE_T": "SIZE_T *",
-        "PSSIZE_T": "SSIZE_T *",
-        "PSTR": "CHAR *",
-        "PUCHAR": "UCHAR *",
-        "PUHALF_PTR": "UHALF_PTR *",
-        "PUINT": "UINT *",
-        "PUINT_PTR": "UINT_PTR *",
-        "PUINT8": "UINT8 *",
-        "PUINT16": "UINT16 *",
-        "PUINT32": "UINT32 *",
-        "PUINT64": "UINT64 *",
-        "PULONG": "ULONG *",
-        "PULONGLONG": "ULONGLONG *",
-        "PULONG_PTR": "ULONG_PTR *",
-        "PULONG32": "ULONG32 *",
-        "PULONG64": "ULONG64 *",
-        "PUSHORT": "USHORT *",
-        "PWCHAR": "WCHAR *",
-        "PWORD": "WORD *",
-        "PWSTR": "WCHAR *",
-        "QWORD": "unsigned long long",
-        "SC_HANDLE": "HANDLE",
-        "SC_LOCK": "LPVOID",
-        "SERVICE_STATUS_HANDLE": "HANDLE",
-
+def win_common_types():
+    return {
         "UNICODE_STRING": model.StructType(
             "_UNICODE_STRING",
             ["Length",
@@ -232,10 +62,6 @@
         "PUNICODE_STRING": "UNICODE_STRING *",
         "PCUNICODE_STRING": "const UNICODE_STRING *",
 
-        "USN": "LONGLONG",
-        "VOID": model.void_type,
-        "WPARAM": "UINT_PTR",
-
         "TBYTE": "set-unicode-needed",
         "TCHAR": "set-unicode-needed",
         "LPCTSTR": "set-unicode-needed",
@@ -244,9 +70,7 @@
         "PTSTR": "set-unicode-needed",
         "PTBYTE": "set-unicode-needed",
         "PTCHAR": "set-unicode-needed",
-        })
-    return result
-
+        }
 
 if sys.platform == 'win32':
-    COMMON_TYPES.update(win_common_types(sys.maxsize))
+    COMMON_TYPES.update(win_common_types())
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -29,6 +29,8 @@
 _r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b")
 _r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b")
 _r_cdecl = re.compile(r"\b__cdecl\b")
+_r_star_const_space = re.compile(       # matches "* const "
+    r"[*]\s*((const|volatile|restrict)\b\s*)+")
 
 def _get_parser():
     global _parser_cache
@@ -36,6 +38,48 @@
         _parser_cache = pycparser.CParser()
     return _parser_cache
 
+def _workaround_for_old_pycparser(csource):
+    # Workaround for a pycparser issue (fixed between pycparser 2.10 and
+    # 2.14): "char*const***" gives us a wrong syntax tree, the same as
+    # for "char***(*const)".  This means we can't tell the difference
+    # afterwards.  But "char(*const(***))" gives us the right syntax
+    # tree.  The issue only occurs if there are several stars in
+    # sequence with no parenthesis inbetween, just possibly qualifiers.
+    # Attempt to fix it by adding some parentheses in the source: each
+    # time we see "* const" or "* const *", we add an opening
+    # parenthesis before each star---the hard part is figuring out where
+    # to close them.
+    parts = []
+    while True:
+        match = _r_star_const_space.search(csource)
+        if not match:
+            break
+        #print repr(''.join(parts)+csource), '=>',
+        parts.append(csource[:match.start()])
+        parts.append('('); closing = ')'
+        parts.append(match.group())   # e.g. "* const "
+        endpos = match.end()
+        if csource.startswith('*', endpos):
+            parts.append('('); closing += ')'
+        level = 0
+        i = endpos
+        while i < len(csource):
+            c = csource[i]
+            if c == '(':
+                level += 1
+            elif c == ')':
+                if level == 0:
+                    break
+                level -= 1
+            elif c in ',;=':
+                if level == 0:
+                    break
+            i += 1
+        csource = csource[endpos:i] + closing + csource[i:]
+        #print repr(''.join(parts)+csource)
+    parts.append(csource)
+    return ''.join(parts)
+
 def _preprocess(csource):
     # Remove comments.  NOTE: this only work because the cdef() section
     # should not contain any string literal!
@@ -47,6 +91,10 @@
         macrovalue = macrovalue.replace('\\\n', '').strip()
         macros[macroname] = macrovalue
     csource = _r_define.sub('', csource)
+    #
+    if pycparser.__version__ < '2.14':
+        csource = _workaround_for_old_pycparser(csource)
+    #
     # BIG HACK: replace WINAPI or __stdcall with "volatile const".
     # It doesn't make sense for the return type of a function to be
     # "volatile volatile const", so we abuse it to detect __stdcall...
@@ -320,13 +368,15 @@
                     self._declare('variable ' + decl.name, tp, quals=quals)
 
     def parse_type(self, cdecl):
+        return self.parse_type_and_quals(cdecl)[0]
+
+    def parse_type_and_quals(self, cdecl):
         ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
         assert not macros
         exprnode = ast.ext[-1].type.args.params[0]
         if isinstance(exprnode, pycparser.c_ast.ID):
             raise api.CDefError("unknown identifier '%s'" % (exprnode.name,))
-        tp, quals = self._get_type_and_quals(exprnode.type)
-        return tp
+        return self._get_type_and_quals(exprnode.type)
 
     def _declare(self, name, obj, included=False, quals=0):
         if name in self._declarations:
@@ -348,6 +398,8 @@
                              pycparser.c_ast.PtrDecl)):
             if 'const' in type.quals:
                 quals |= model.Q_CONST
+            if 'volatile' in type.quals:
+                quals |= model.Q_VOLATILE
             if 'restrict' in type.quals:
                 quals |= model.Q_RESTRICT
         return quals
@@ -422,7 +474,8 @@
                 if ident == '__dotdotdot__':
                     raise api.FFIError(':%d: bad usage of "..."' %
                             typenode.coord.line)
-                return resolve_common_type(ident), quals
+                tp0, quals0 = resolve_common_type(self, ident)
+                return tp0, (quals | quals0)
             #
             if isinstance(type, pycparser.c_ast.Struct):
                 # 'struct foobar'
@@ -456,6 +509,13 @@
 
     def _parse_function_type(self, typenode, funcname=None):
         params = list(getattr(typenode.args, 'params', []))
+        for i, arg in enumerate(params):
+            if not hasattr(arg, 'type'):
+                raise api.CDefError("%s arg %d: unknown type '%s'"
+                    " (if you meant to use the old C syntax of giving"
+                    " untyped arguments, it is not supported)"
+                    % (funcname or 'in expression', i + 1,
+                       getattr(arg, 'name', '?')))
         ellipsis = (
             len(params) > 0 and
             isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -7,10 +7,13 @@
 # type qualifiers
 Q_CONST    = 0x01
 Q_RESTRICT = 0x02
+Q_VOLATILE = 0x04
 
 def qualify(quals, replace_with):
     if quals & Q_CONST:
         replace_with = ' const ' + replace_with.lstrip()
+    if quals & Q_VOLATILE:
+        replace_with = ' volatile ' + replace_with.lstrip()
     if quals & Q_RESTRICT:
         # It seems that __restrict is supported by gcc and msvc.
         # If you hit some different compiler, add a #define in
@@ -511,12 +514,17 @@
         if self.baseinttype is not None:
             return self.baseinttype.get_cached_btype(ffi, finishlist)
         #
+        from . import api
         if self.enumvalues:
             smallest_value = min(self.enumvalues)
             largest_value = max(self.enumvalues)
         else:
-            smallest_value = 0
-            largest_value = 0
+            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
         if smallest_value < 0:   # needs a signed type
             sign = 1
             candidate1 = PrimitiveType("int")
diff --git a/cffi/parse_c_type.h b/cffi/parse_c_type.h
--- a/cffi/parse_c_type.h
+++ b/cffi/parse_c_type.h
@@ -83,6 +83,8 @@
 #define _CFFI__UNKNOWN_FLOAT_PRIM     (-2)
 #define _CFFI__UNKNOWN_LONG_DOUBLE    (-3)
 
+#define _CFFI__IO_FILE_STRUCT         (-1)
+
 
 struct _cffi_global_s {
     const char *name;
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -253,7 +253,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 not byte strings.  (Before cffi version 0.9,
+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.)
 
diff --git a/doc/source/conf.py b/doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -47,7 +47,7 @@
 # The short X.Y version.
 version = '1.3'
 # The full version, including alpha/beta/rc tags.
-release = '1.3.0'
+release = '1.3.1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -51,11 +51,11 @@
 
 Download and Installation:
 
-* http://pypi.python.org/packages/source/c/cffi/cffi-1.3.0.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-1.3.1.tar.gz
 
-   - MD5: a40ed8c8ac653c8fc7d5603711b06eaf
+   - MD5: ...
 
-   - SHA: 54a0b2dbbc2f5d99131aa337e217b636652641a9
+   - SHA: ...
 
 * Or grab the most current version from the `Bitbucket page`_:
   ``hg clone https://bitbucket.org/cffi/cffi``
diff --git a/doc/source/using.rst b/doc/source/using.rst
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -514,6 +514,16 @@
 discouraged: using this a style, we are more likely to forget the
 callback object too early, when it is still in use.
 
+.. warning::
+    
+    **SELinux** requires that the setting ``deny_execmem`` is left to
+    its default setting of ``off`` to use callbacks.  A fix in cffi was
+    attempted (see the ``ffi_closure_alloc`` branch), but this branch is
+    not merged because it creates potential memory corruption with
+    ``fork()``.  For more information, `see here.`__
+
+.. __: https://bugzilla.redhat.com/show_bug.cgi?id=1249685
+
 *New in version 1.2:* If you want to be sure to catch all exceptions, use
 ``ffi.callback(..., onerror=func)``.  If an exception occurs and
 ``onerror`` is specified, then ``onerror(exception, exc_value,
@@ -692,13 +702,16 @@
 **ffi.from_buffer(python_buffer)**: return a ``<cdata 'char[]'>`` that
 points to the data of the given Python object, which must support the
 buffer interface.  This is the opposite of ``ffi.buffer()``.  It gives
-a (read-write) reference to the existing data, not a copy; for this
+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 bytearray (or buffers/memoryviews on them).
 It is meant to be used on objects
 containing large quantities of raw data, like ``array.array`` or numpy
 arrays.  It supports both the old buffer API (in Python 2.x) and the
-new memoryview API.  The original object is kept alive (and, in case
+new memoryview API.  Note that if you pass a read-only buffer object,
+you still get a regular ``<cdata 'char[]'>``; it is your responsibility
+not to write there if the original buffer doesn't expect you to.
+The original object is kept alive (and, in case
 of memoryview, locked) as long as the cdata object returned by
 ``ffi.from_buffer()`` is alive.  *New in version 0.9.*
 
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -3,6 +3,22 @@
 ======================
 
 
+v1.3.1
+======
+
+* The optional typedefs (``bool``, ``FILE`` and all Windows types) were
+  not always available from out-of-line FFI objects.
+
+* Opaque enums are phased out from the cdefs: they now give a warning,
+  instead of (possibly wrongly) being assumed equal to ``unsigned int``.
+  Please report if you get a reasonable use case for them.
+
+* Some parsing details, notably ``volatile`` is passed along like
+  ``const`` and ``restrict``.  Also, older versions of pycparser
+  mis-parse some pointer-to-pointer types like ``char * const *``: the
+  "const" ends up at the wrong place.  Added a workaround.
+
+
 v1.3.0
 ======
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -144,7 +144,7 @@
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
 """,
-        version='1.3.0',
+        version='1.3.1',
         packages=['cffi'] if cpython else [],
         package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h']}
                      if cpython else {},
diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py
--- a/testing/cffi0/backend_tests.py
+++ b/testing/cffi0/backend_tests.py
@@ -756,10 +756,11 @@
         p = ffi.cast("long long", ffi.cast("wchar_t", -1))
         if SIZE_OF_WCHAR == 2:      # 2 bytes, unsigned
             assert int(p) == 0xffff
-        elif platform.machine().startswith(('arm', 'aarch64')):
-            assert int(p) == 0xffffffff      # 4 bytes, unsigned
-        else:                       # 4 bytes, signed
+        elif (sys.platform.startswith('linux') and
+              platform.machine().startswith('x86')):   # known to be signed
             assert int(p) == -1
+        else:                     # in general, it can be either signed or not
+            assert int(p) in [-1, 0xffffffff]  # e.g. on arm, both cases occur
         p = ffi.cast("int", u+'\u1234')
         assert int(p) == 0x1234
 
@@ -1334,7 +1335,8 @@
         # these depend on user-defined data, so should not be shared
         assert ffi1.typeof("struct foo") is not ffi2.typeof("struct foo")
         assert ffi1.typeof("union foo *") is not ffi2.typeof("union foo*")
-        assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo")
+        # the following test is an opaque enum, which we no longer support
+        #assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo")
         # sanity check: twice 'ffi1'
         assert ffi1.typeof("struct foo*") is ffi1.typeof("struct foo *")
 
@@ -1346,6 +1348,17 @@
         assert ffi.getctype("pe") == 'e *'
         assert ffi.getctype("e1*") == 'e1 *'
 
+    def test_opaque_enum(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("enum foo;")
+        from cffi import __version_info__
+        if __version_info__ < (1, 4):
+            py.test.skip("re-enable me in version 1.4")
+        e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
+        assert str(e.value) == (
+            "'enum foo' has no values explicitly defined: refusing to guess "
+            "which integer type it is meant to be (unsigned/signed, int/long)")
+
     def test_new_ctype(self):
         ffi = FFI(backend=self.Backend())
         p = ffi.new("int *")
diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py
--- a/testing/cffi0/test_function.py
+++ b/testing/cffi0/test_function.py
@@ -486,7 +486,7 @@
         ffi = FFI(backend=self.Backend())
         ffi.cdef("double __stdcall sin(double x);")     # stdcall ignored
         m = ffi.dlopen(lib_m)
-        if (sys.platform == 'win32' and sys.maxint < 2**32 and 
+        if (sys.platform == 'win32' and sys.maxsize < 2**32 and 
                 self.Backend is not CTypesBackend):
             assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin))
         else:
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
--- a/testing/cffi0/test_parsing.py
+++ b/testing/cffi0/test_parsing.py
@@ -261,7 +261,8 @@
     ffi = FFI()
     ffi.cdef("typedef int bool, *FILE;")
     assert repr(ffi.cast("bool", 123)) == "<cdata 'int' 123>"
-    assert repr(ffi.cast("FILE", 123)) == "<cdata 'int *' 0x7b>"
+    assert re.match(r"<cdata 'int [*]' 0[xX]?0*7[bB]>",
+                    repr(ffi.cast("FILE", 123)))
     ffi = FFI()
     ffi.cdef("typedef bool (*fn_t)(bool, bool);")   # "bool," but within "( )"
 
@@ -272,6 +273,13 @@
     ffi = FFI()
     ffi.cdef("typedef _Bool bool; void f(bool);")
 
+def test_unknown_argument_type():
+    ffi = FFI()
+    e = py.test.raises(CDefError, ffi.cdef, "void f(foobarbazzz);")
+    assert str(e.value) == ("f arg 1: unknown type 'foobarbazzz' (if you meant"
+                            " to use the old C syntax of giving untyped"
+                            " arguments, it is not supported)")
+
 def test_void_renamed_as_only_arg():
     ffi = FFI()
     ffi.cdef("typedef void void_t1;"
@@ -279,38 +287,16 @@
              "typedef int (*func_t)(void_t);")
     assert ffi.typeof("func_t").args == ()
 
-def test_win_common_types():
-    from cffi.commontypes import COMMON_TYPES, _CACHE
-    from cffi.commontypes import win_common_types, resolve_common_type
-    #
-    def clear_all(extra={}, old_dict=COMMON_TYPES.copy()):
-        COMMON_TYPES.clear()
-        COMMON_TYPES.update(old_dict)
-        COMMON_TYPES.update(extra)
-        _CACHE.clear()
-    #
-    for maxsize in [2**32-1, 2**64-1]:
-        ct = win_common_types(maxsize)
-        clear_all(ct)
-        for key in sorted(ct):
-            if ct[key] != 'set-unicode-needed':
-                resolve_common_type(key)
-    # assert did not crash
-    # now try to use e.g. WPARAM (-> UINT_PTR -> unsigned 32/64-bit)
-    for maxsize in [2**32-1, 2**64-1]:
-        ct = win_common_types(maxsize)
-        clear_all(ct)
-        ffi = FFI()
-        value = int(ffi.cast("WPARAM", -1))
-        assert value == maxsize
-    #
-    clear_all()
-
 def test_WPARAM_on_windows():
     if sys.platform != 'win32':
         py.test.skip("Only for Windows")
     ffi = FFI()
     ffi.cdef("void f(WPARAM);")
+    #
+    # WPARAM -> UINT_PTR -> unsigned 32/64-bit integer
+    ffi = FFI()
+    value = int(ffi.cast("WPARAM", -42))
+    assert value == sys.maxsize * 2 - 40
 
 def test__is_constant_globalvar():
     for input, expected_output in [
@@ -360,6 +346,41 @@
     assert lst[0] == lst[2]
     assert lst[1] == lst[3]
 
+def test_const_pointer_to_pointer():
+    from cffi import model
+    ffi = FFI(backend=FakeBackend())
+    #
+    tp, qual = ffi._parser.parse_type_and_quals("char * * (* const)")
+    assert (str(tp), qual) == ("<char * * *>", model.Q_CONST)
+    tp, qual = ffi._parser.parse_type_and_quals("char * (* const (*))")
+    assert (str(tp), qual) == ("<char * * const *>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals("char (* const (* (*)))")
+    assert (str(tp), qual) == ("<char * const * *>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals("char const * * *")
+    assert (str(tp), qual) == ("<char const * * *>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals("const char * * *")
+    assert (str(tp), qual) == ("<char const * * *>", 0)
+    #
+    tp, qual = ffi._parser.parse_type_and_quals("char * * * const const")
+    assert (str(tp), qual) == ("<char * * *>", model.Q_CONST)
+    tp, qual = ffi._parser.parse_type_and_quals("char * * volatile *")
+    assert (str(tp), qual) == ("<char * * volatile *>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals("char * volatile restrict * *")
+    assert (str(tp), qual) == ("<char * __restrict volatile * *>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals("char const volatile * * *")
+    assert (str(tp), qual) == ("<char volatile const * * *>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals("const char * * *")
+    assert (str(tp), qual) == ("<char const * * *>", 0)
+    #
+    tp, qual = ffi._parser.parse_type_and_quals(
+        "int(char*const*, short****const*)")
+    assert (str(tp), qual) == (
+        "<int()(char * const *, short * * * * const *)>", 0)
+    tp, qual = ffi._parser.parse_type_and_quals(
+        "char*const*(short*const****)")
+    assert (str(tp), qual) == (
+        "<char * const *()(short * const * * * *)>", 0)
+
 def test_enum():
     ffi = FFI()
     ffi.cdef("""
diff --git a/testing/cffi1/test_commontypes.py b/testing/cffi1/test_commontypes.py
new file mode 100644
--- /dev/null
+++ b/testing/cffi1/test_commontypes.py
@@ -0,0 +1,34 @@
+import py, os, cffi, re
+import _cffi_backend
+
+
+def getlines():
+    try:
+        f = open(os.path.join(os.path.dirname(cffi.__file__),
+                              '..', 'c', 'commontypes.c'))
+    except IOError:
+        py.test.skip("cannot find ../c/commontypes.c")
+    lines = [line for line in f.readlines() if line.strip().startswith('EQ(')]
+    f.close()
+    return lines
+
+def test_alphabetical_order():
+    lines = getlines()
+    assert lines == sorted(lines)
+
+def test_dependencies():
+    r = re.compile(r'EQ[(]"([^"]+)",(?:\s*"([A-Z0-9_]+)\s*[*]*"[)])?')
+    lines = getlines()
+    d = {}
+    for line in lines:
+        match = r.search(line)
+        if match is not None:
+            d[match.group(1)] = match.group(2)
+    for value in d.values():
+        if value:
+            assert value in d
+
+def test_get_common_types():
+    d = {}
+    _cffi_backend._get_common_types(d)
+    assert d["bool"] == "_Bool"
diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py
--- a/testing/cffi1/test_ffi_obj.py
+++ b/testing/cffi1/test_ffi_obj.py
@@ -395,3 +395,23 @@
         return ffi.NULL
     alloc5 = ffi.new_allocator(myalloc5)
     py.test.raises(MemoryError, alloc5, "int[5]")
+
+def test_bool_issue228():
+    ffi = _cffi1_backend.FFI()
+    fntype = ffi.typeof("int(*callback)(bool is_valid)")
+    assert repr(fntype.args[0]) == "<ctype '_Bool'>"
+
+def test_FILE_issue228():
+    fntype1 = _cffi1_backend.FFI().typeof("FILE *")
+    fntype2 = _cffi1_backend.FFI().typeof("FILE *")
+    assert repr(fntype1) == "<ctype 'FILE *'>"
+    assert fntype1 is fntype2
+
+def test_cast_from_int_type_to_bool():
+    ffi = _cffi1_backend.FFI()
+    for basetype in ['char', 'short', 'int', 'long', 'long long']:
+        for sign in ['signed', 'unsigned']:
+            type = '%s %s' % (sign, basetype)
+            assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1
+            assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1
+            assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0
diff --git a/testing/cffi1/test_new_ffi_1.py b/testing/cffi1/test_new_ffi_1.py
--- a/testing/cffi1/test_new_ffi_1.py
+++ b/testing/cffi1/test_new_ffi_1.py
@@ -781,10 +781,11 @@
         p = ffi.cast("long long", ffi.cast("wchar_t", -1))
         if SIZE_OF_WCHAR == 2:      # 2 bytes, unsigned
             assert int(p) == 0xffff
-        elif platform.machine().startswith(('arm', 'aarch64')):
-            assert int(p) == 0xffffffff      # 4 bytes, unsigned
-        else:                       # 4 bytes, signed
+        elif (sys.platform.startswith('linux') and
+              platform.machine().startswith('x86')):   # known to be signed
             assert int(p) == -1
+        else:                     # in general, it can be either signed or not
+            assert int(p) in [-1, 0xffffffff]  # e.g. on arm, both cases occur
         p = ffi.cast("int", u+'\u1234')
         assert int(p) == 0x1234
 
diff --git a/testing/cffi1/test_parse_c_type.py b/testing/cffi1/test_parse_c_type.py
--- a/testing/cffi1/test_parse_c_type.py
+++ b/testing/cffi1/test_parse_c_type.py
@@ -19,8 +19,11 @@
 ffi.cdef(header)
 
 lib = ffi.verify(
-        open(os.path.join(cffi_dir, '..', 'c', 'parse_c_type.c')).read(),
-        include_dirs=[cffi_dir])
+        open(os.path.join(cffi_dir, '..', 'c', 'parse_c_type.c')).read() + """
+static const char *get_common_type(const char *search, size_t search_len) {
+    return NULL;
+}
+""",    include_dirs=[cffi_dir])
 
 class ParseError(Exception):
     pass
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
@@ -1204,12 +1204,19 @@
     assert foo_s.fields[1][1].type is ffi.typeof("void *")
 
 def test_restrict_fields():
-    if sys.platform == 'win32':
-        py.test.skip("'__restrict__' probably not recognized")
     ffi = FFI()
     ffi.cdef("""struct foo_s { void * restrict b; };""")
     lib = verify(ffi, 'test_restrict_fields', """
-        struct foo_s { void * __restrict__ b; };""")
+        struct foo_s { void * __restrict b; };""")
+    foo_s = ffi.typeof("struct foo_s")
+    assert foo_s.fields[0][0] == 'b'
+    assert foo_s.fields[0][1].type is ffi.typeof("void *")
+
+def test_volatile_fields():
+    ffi = FFI()
+    ffi.cdef("""struct foo_s { void * volatile b; };""")
+    lib = verify(ffi, 'test_volatile_fields', """
+        struct foo_s { void * volatile b; };""")
     foo_s = ffi.typeof("struct foo_s")
     assert foo_s.fields[0][0] == 'b'
     assert foo_s.fields[0][1].type is ffi.typeof("void *")
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -1494,15 +1494,6 @@
             assert lib.foo(0) == 1
             py.test.raises(TypeError, lib.foo, 0.0)
 
-def test_cast_from_int_type_to_bool():
-    ffi = FFI()
-    for basetype in ['char', 'short', 'int', 'long', 'long long']:
-        for sign in ['signed', 'unsigned']:
-            type = '%s %s' % (sign, basetype)
-            assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1
-            assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1
-            assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0
-
 def test_addressof():
     ffi = FFI()
     ffi.cdef("""
@@ -2250,3 +2241,31 @@
     assert p == lib.myarray + 4
     p[1] = 82
     assert lib.my_value == 82            # [5]
+
+def test_const_pointer_to_pointer():
+    ffi = FFI()
+    ffi.cdef("struct s { char *const *a; };")
+    ffi.verify("struct s { char *const *a; };")
+
+def test_share_FILE():
+    ffi1 = FFI()
+    ffi1.cdef("void do_stuff(FILE *);")
+    lib1 = ffi1.verify("void do_stuff(FILE *f) { (void)f; }")
+    ffi2 = FFI()
+    ffi2.cdef("FILE *barize(void);")
+    lib2 = ffi2.verify("FILE *barize(void) { return NULL; }")
+    lib1.do_stuff(lib2.barize())
+
+def test_win_common_types():
+    if sys.platform != 'win32':
+        py.test.skip("Windows only")
+    ffi = FFI()
+    ffi.set_unicode(True)
+    ffi.verify("")
+    assert ffi.typeof("PBYTE") is ffi.typeof("unsigned char *")
+    if sys.maxsize > 2**32:
+        expected = "unsigned long long"
+    else:
+        expected = "unsigned int"
+    assert ffi.typeof("UINT_PTR") is ffi.typeof(expected)
+    assert ffi.typeof("PTSTR") is ffi.typeof("wchar_t *")


More information about the pypy-commit mailing list