[pypy-commit] pypy default: Update to cffi/86cdfb3ff7fa

arigo noreply at buildbot.pypy.org
Tue Nov 3 16:37:18 EST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r80526:4a523256b0e4
Date: 2015-11-03 21:28 +0100
http://bitbucket.org/pypy/pypy/changeset/4a523256b0e4/

Log:	Update to cffi/86cdfb3ff7fa

diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py
--- a/lib_pypy/cffi/cffi_opcode.py
+++ b/lib_pypy/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/lib_pypy/cffi/commontypes.py b/lib_pypy/cffi/commontypes.py
--- a/lib_pypy/cffi/commontypes.py
+++ b/lib_pypy/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/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/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,46 @@
         _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
+        for i in xrange(endpos, len(csource)):
+            c = csource[i]
+            if c == '(':
+                level += 1
+            elif c == ')':
+                if level == 0:
+                    break
+                level -= 1
+            elif c in ',;=':
+                if level == 0:
+                    break
+        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 +89,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 +366,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 +396,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 +472,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 +507,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/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/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
diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h
--- a/lib_pypy/cffi/parse_c_type.h
+++ b/lib_pypy/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/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -43,6 +43,7 @@
         'newp_handle': 'handle.newp_handle',
         'from_handle': 'handle.from_handle',
         '_get_types': 'func._get_types',
+        '_get_common_types': 'func._get_common_types',
         'from_buffer': 'func.from_buffer',
 
         'string': 'func.string',
diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py
--- a/pypy/module/_cffi_backend/cffi_opcode.py
+++ b/pypy/module/_cffi_backend/cffi_opcode.py
@@ -110,6 +110,9 @@
 _UNKNOWN_FLOAT_PRIM    = -2
 _UNKNOWN_LONG_DOUBLE   = -3
 
+_IO_FILE_STRUCT        = -1
+
+
 PRIMITIVE_TO_INDEX = {
     'char':               PRIM_CHAR,
     'short':              PRIM_SHORT,
diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -84,6 +84,20 @@
 
 # ____________________________________________________________
 
+def _get_common_types(space, w_dict):
+    from pypy.module._cffi_backend.parse_c_type import ll_enum_common_types
+    index = 0
+    while True:
+        p = ll_enum_common_types(rffi.cast(rffi.INT, index))
+        if not p:
+            break
+        key = rffi.charp2str(p)
+        value = rffi.charp2str(rffi.ptradd(p, len(key) + 1))
+        space.setitem_str(w_dict, key, space.wrap(value))
+        index += 1
+
+# ____________________________________________________________
+
 def _fetch_as_read_buffer(space, w_x):
     # xxx do we really need to implement the same mess as in CPython 2.7
     # w.r.t. buffers and memoryviews??
diff --git a/pypy/module/_cffi_backend/parse_c_type.py b/pypy/module/_cffi_backend/parse_c_type.py
--- a/pypy/module/_cffi_backend/parse_c_type.py
+++ b/pypy/module/_cffi_backend/parse_c_type.py
@@ -87,6 +87,8 @@
 ll_set_cdl_realize_global_int = llexternal('pypy_set_cdl_realize_global_int',
                                            [lltype.Ptr(GLOBAL_S)],
                                            lltype.Void)
+ll_enum_common_types = llexternal('pypy_enum_common_types',
+                                  [rffi.INT], rffi.CCHARP)
 
 def parse_c_type(info, input):
     p_input = rffi.str2charp(input)
diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py
--- a/pypy/module/_cffi_backend/realize_c_type.py
+++ b/pypy/module/_cffi_backend/realize_c_type.py
@@ -74,7 +74,15 @@
     assert len(NAMES) == cffi_opcode._NUM_PRIM
 
     def __init__(self, space):
+        self.space = space
         self.all_primitives = [None] * cffi_opcode._NUM_PRIM
+        self.file_struct = None
+
+    def get_file_struct(self):
+        if self.file_struct is None:
+            self.file_struct = ctypestruct.W_CTypeStruct(self.space, "FILE")
+        return self.file_struct
+
 
 def get_primitive_type(ffi, num):
     space = ffi.space
@@ -266,6 +274,10 @@
 
 
 def _realize_c_struct_or_union(ffi, sindex):
+    if sindex == cffi_opcode._IO_FILE_STRUCT:
+        # returns a single global cached opaque type
+        return ffi.space.fromcache(RealizeCache).get_file_struct()
+
     s = ffi.ctxobj.ctx.c_struct_unions[sindex]
     type_index = rffi.getintfield(s, 'c_type_index')
     if ffi.cached_types[type_index] is not None:
@@ -281,7 +293,10 @@
             x = ctypestruct.W_CTypeUnion(space, name)
         else:
             name = _realize_name("struct ", s.c_name)
-            x = ctypestruct.W_CTypeStruct(space, name)
+            if name == "struct _IO_FILE":
+                x = space.fromcache(RealizeCache).get_file_struct()
+            else:
+                x = ctypestruct.W_CTypeStruct(space, name)
         if (c_flags & cffi_opcode.F_OPAQUE) == 0:
             assert c_first_field_index >= 0
             w_ctype = x
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c b/pypy/module/_cffi_backend/src/parse_c_type.c
--- a/pypy/module/_cffi_backend/src/parse_c_type.c
+++ b/pypy/module/_cffi_backend/src/parse_c_type.c
@@ -231,6 +231,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)
 {
@@ -387,11 +389,18 @@
 
             case TOK_INTEGER:
                 errno = 0;
-#ifndef _MSC_VER
-                if (sizeof(length) > sizeof(unsigned long))
+                if (sizeof(length) > sizeof(unsigned long)) {
+#ifdef MS_WIN32
+# ifdef _WIN64
+                    length = _strtoui64(tok->p, &endptr, 0);
+# else
+                    abort();  /* unreachable */
+# endif
+#else
                     length = strtoull(tok->p, &endptr, 0);
+#endif
+                }
                 else
-#endif
                     length = strtoul(tok->p, &endptr, 0);
                 if (endptr != tok->p + tok->size)
                     return parse_error(tok, "invalid number");
@@ -446,26 +455,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)                                 \
-  RPY_EXTERN int                                                \
-  pypy_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)                                         \
+  RPY_EXTERN int                                                        \
+  pypy_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)
@@ -719,6 +736,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);
@@ -729,6 +747,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:
@@ -740,10 +766,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);
@@ -773,8 +804,9 @@
 }
 
 
-RPY_EXTERN
-int pypy_parse_c_type(struct _cffi_parse_info_s *info, const char *input)
+static
+int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index,
+                      const char *input)
 {
     int result;
     token_t token;
@@ -785,16 +817,33 @@
     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;
 }
 
+RPY_EXTERN
+int pypy_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);
+}
+
+
+#include "commontypes.c"      /* laziness hack: include this file here */
+
 
 /************************************************************/
 /* extra from cdlopen.c                                     */
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.h b/pypy/module/_cffi_backend/src/parse_c_type.h
--- a/pypy/module/_cffi_backend/src/parse_c_type.h
+++ b/pypy/module/_cffi_backend/src/parse_c_type.h
@@ -5,7 +5,7 @@
 
 #define _CFFI_OP(opcode, arg)   (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8))
 #define _CFFI_GETOP(cffi_opcode)    ((unsigned char)(uintptr_t)cffi_opcode)
-#define _CFFI_GETARG(cffi_opcode)   (((uintptr_t)cffi_opcode) >> 8)
+#define _CFFI_GETARG(cffi_opcode)   (((intptr_t)cffi_opcode) >> 8)
 
 #define _CFFI_OP_PRIMITIVE       1
 #define _CFFI_OP_POINTER         3
@@ -25,6 +25,8 @@
 #define _CFFI_OP_CONSTANT_INT   31
 #define _CFFI_OP_GLOBAL_VAR     33
 #define _CFFI_OP_DLOPEN_FUNC    35
+#define _CFFI_OP_DLOPEN_CONST   37
+#define _CFFI_OP_GLOBAL_VAR_F   39
 
 #define _CFFI_PRIM_VOID          0
 #define _CFFI_PRIM_BOOL          1
@@ -77,6 +79,11 @@
 #define _CFFI_PRIM_UINTMAX      47
 
 #define _CFFI__NUM_PRIM         48
+#define _CFFI__UNKNOWN_PRIM           (-1)
+#define _CFFI__UNKNOWN_FLOAT_PRIM     (-2)
+#define _CFFI__UNKNOWN_LONG_DOUBLE    (-3)
+
+#define _CFFI__IO_FILE_STRUCT         (-1)
 
 
 struct _cffi_global_s {
@@ -164,4 +171,6 @@
                              const char *search, size_t search_len);
 RPY_EXTERN
 void pypy_set_cdl_realize_global_int(struct _cffi_global_s *target);
+RPY_EXTERN
+char *pypy_enum_common_types(int index);
 #endif
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -3509,3 +3509,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/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -424,3 +424,26 @@
             return ffi.NULL
         alloc5 = ffi.new_allocator(myalloc5)
         raises(MemoryError, alloc5, "int[5]")
+
+    def test_bool_issue228(self):
+        import _cffi_backend as _cffi1_backend
+        ffi = _cffi1_backend.FFI()
+        fntype = ffi.typeof("int(*callback)(bool is_valid)")
+        assert repr(fntype.args[0]) == "<ctype '_Bool'>"
+
+    def test_FILE_issue228(self):
+        import _cffi_backend as _cffi1_backend
+        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(self):
+        import _cffi_backend as _cffi1_backend
+        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/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -28,6 +28,7 @@
     module_name = '_CFFI_' + module_name
     rdir = udir.ensure('recompiler', dir=1)
     rdir.join('Python.h').write(
+        '#include <stdio.h>\n'
         '#define PYPY_VERSION XX\n'
         '#define PyMODINIT_FUNC /*exported*/ void\n'
         )
@@ -1076,3 +1077,302 @@
         raises(ffi.error, getattr, lib, 'my_value')
         e = raises(ffi.error, setattr, lib, 'my_value', 50)
         assert str(e.value) == "global variable 'my_value' is at address NULL"
+
+    def test_const_fields(self):
+        ffi, lib = self.prepare(
+            """struct foo_s { const int a; void *const b; };""",
+            'test_const_fields',
+            """struct foo_s { const int a; void *const b; };""")
+        foo_s = ffi.typeof("struct foo_s")
+        assert foo_s.fields[0][0] == 'a'
+        assert foo_s.fields[0][1].type is ffi.typeof("int")
+        assert foo_s.fields[1][0] == 'b'
+        assert foo_s.fields[1][1].type is ffi.typeof("void *")
+
+    def test_restrict_fields(self):
+        ffi, lib = self.prepare(
+            """struct foo_s { void * restrict b; };""",
+            'test_restrict_fields',
+            """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(self):
+        ffi, lib = self.prepare(
+            """struct foo_s { void * volatile b; };""",
+            '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 *")
+
+    def test_const_array_fields(self):
+        ffi, lib = self.prepare(
+            """struct foo_s { const int a[4]; };""",
+            'test_const_array_fields',
+            """struct foo_s { const int a[4]; };""")
+        foo_s = ffi.typeof("struct foo_s")
+        assert foo_s.fields[0][0] == 'a'
+        assert foo_s.fields[0][1].type is ffi.typeof("int[4]")
+
+    def test_const_array_fields_varlength(self):
+        ffi, lib = self.prepare(
+            """struct foo_s { const int a[]; ...; };""",
+            'test_const_array_fields_varlength',
+            """struct foo_s { const int a[4]; };""")
+        foo_s = ffi.typeof("struct foo_s")
+        assert foo_s.fields[0][0] == 'a'
+        assert foo_s.fields[0][1].type is ffi.typeof("int[]")
+
+    def test_const_array_fields_unknownlength(self):
+        ffi, lb = self.prepare(
+            """struct foo_s { const int a[...]; ...; };""",
+            'test_const_array_fields_unknownlength',
+            """struct foo_s { const int a[4]; };""")
+        foo_s = ffi.typeof("struct foo_s")
+        assert foo_s.fields[0][0] == 'a'
+        assert foo_s.fields[0][1].type is ffi.typeof("int[4]")
+
+    def test_const_function_args(self):
+        ffi, lib = self.prepare(
+            """int foobar(const int a, const int *b, const int c[]);""",
+            'test_const_function_args', """
+            int foobar(const int a, const int *b, const int c[]) {
+                return a + *b + *c;
+            }
+        """)
+        assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142
+
+    def test_const_function_type_args(self):
+        ffi, lib = self.prepare(
+            """int (*foobar)(const int a, const int *b, const int c[]);""",
+            'test_const_function_type_args', """
+            int (*foobar)(const int a, const int *b, const int c[]);
+        """)
+        t = ffi.typeof(lib.foobar)
+        assert t.args[0] is ffi.typeof("int")
+        assert t.args[1] is ffi.typeof("int *")
+        assert t.args[2] is ffi.typeof("int *")
+
+    def test_const_constant(self):
+        ffi, lib = self.prepare(
+            """struct foo_s { int x,y; }; const struct foo_s myfoo;""",
+            'test_const_constant', """
+            struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 };
+        """)
+        assert lib.myfoo.x == 40
+        assert lib.myfoo.y == 2
+
+    def test_const_via_typedef(self):
+        ffi, lib = self.prepare(
+            """typedef const int const_t; const_t aaa;""",
+            'test_const_via_typedef', """
+            typedef const int const_t;
+            #define aaa 42
+        """)
+        assert lib.aaa == 42
+        raises(AttributeError, "lib.aaa = 43")
+
+    def test_win32_calling_convention_0(self):
+        import sys
+        ffi, lib = self.prepare(
+            """
+            int call1(int(__cdecl   *cb)(int));
+            int (*const call2)(int(__stdcall *cb)(int));
+            """,
+            'test_win32_calling_convention_0', r"""
+            #ifndef _MSC_VER
+            #  define __stdcall  /* nothing */
+            #endif
+            int call1(int(*cb)(int)) {
+                int i, result = 0;
+                //printf("call1: cb = %p\n", cb);
+                for (i = 0; i < 1000; i++)
+                    result += cb(i);
+                //printf("result = %d\n", result);
+                return result;
+            }
+            int call2(int(__stdcall *cb)(int)) {
+                int i, result = 0;
+                //printf("call2: cb = %p\n", cb);
+                for (i = 0; i < 1000; i++)
+                    result += cb(-i);
+                //printf("result = %d\n", result);
+                return result;
+            }
+        """)
+        @ffi.callback("int(int)")
+        def cb1(x):
+            return x * 2
+        @ffi.callback("int __stdcall(int)")
+        def cb2(x):
+            return x * 3
+        res = lib.call1(cb1)
+        assert res == 500*999*2
+        assert res == ffi.addressof(lib, 'call1')(cb1)
+        res = lib.call2(cb2)
+        assert res == -500*999*3
+        assert res == ffi.addressof(lib, 'call2')(cb2)
+        if sys.platform == 'win32' and not sys.maxsize > 2**32:
+            assert '__stdcall' in str(ffi.typeof(cb2))
+            assert '__stdcall' not in str(ffi.typeof(cb1))
+            raises(TypeError, lib.call1, cb2)
+            raises(TypeError, lib.call2, cb1)
+        else:
+            assert '__stdcall' not in str(ffi.typeof(cb2))
+            assert ffi.typeof(cb2) is ffi.typeof(cb1)
+
+    def test_win32_calling_convention_1(self):
+        ffi, lib = self.prepare("""
+            int __cdecl   call1(int(__cdecl   *cb)(int));
+            int __stdcall call2(int(__stdcall *cb)(int));
+            int (__cdecl   *const cb1)(int);
+            int (__stdcall *const cb2)(int);
+        """, 'test_win32_calling_convention_1', r"""
+            #ifndef _MSC_VER
+            #  define __cdecl
+            #  define __stdcall
+            #endif
+            int __cdecl   cb1(int x) { return x * 2; }
+            int __stdcall cb2(int x) { return x * 3; }
+
+            int __cdecl call1(int(__cdecl *cb)(int)) {
+                int i, result = 0;
+                //printf("here1\n");
+                //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
+                for (i = 0; i < 1000; i++)
+                    result += cb(i);
+                //printf("result = %d\n", result);
+                return result;
+            }
+            int __stdcall call2(int(__stdcall *cb)(int)) {
+                int i, result = 0;
+                //printf("here1\n");
+                //printf("cb = %p, cb2 = %p\n", cb, (void *)cb2);
+                for (i = 0; i < 1000; i++)
+                    result += cb(-i);
+                //printf("result = %d\n", result);
+                return result;
+            }
+        """)
+        #print '<<< cb1 =', ffi.addressof(lib, 'cb1')
+        ptr_call1 = ffi.addressof(lib, 'call1')
+        assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2
+        assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2
+        #print '<<< cb2 =', ffi.addressof(lib, 'cb2')
+        ptr_call2 = ffi.addressof(lib, 'call2')
+        assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3
+        assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3
+        #print '<<< done'
+
+    def test_win32_calling_convention_2(self):
+        import sys
+        # any mistake in the declaration of plain function (including the
+        # precise argument types and, here, the calling convention) are
+        # automatically corrected.  But this does not apply to the 'cb'
+        # function pointer argument.
+        ffi, lib = self.prepare("""
+            int __stdcall call1(int(__cdecl   *cb)(int));
+            int __cdecl   call2(int(__stdcall *cb)(int));
+            int (__cdecl   *const cb1)(int);
+            int (__stdcall *const cb2)(int);
+        """, 'test_win32_calling_convention_2', """
+            #ifndef _MSC_VER
+            #  define __cdecl
+            #  define __stdcall
+            #endif
+            int __cdecl call1(int(__cdecl *cb)(int)) {
+                int i, result = 0;
+                for (i = 0; i < 1000; i++)
+                    result += cb(i);
+                return result;
+            }
+            int __stdcall call2(int(__stdcall *cb)(int)) {
+                int i, result = 0;
+                for (i = 0; i < 1000; i++)
+                    result += cb(-i);
+                return result;
+            }
+            int __cdecl   cb1(int x) { return x * 2; }
+            int __stdcall cb2(int x) { return x * 3; }
+        """)
+        ptr_call1 = ffi.addressof(lib, 'call1')
+        ptr_call2 = ffi.addressof(lib, 'call2')
+        if sys.platform == 'win32' and not sys.maxsize > 2**32:
+            raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2'))
+            raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2'))
+            raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1'))
+            raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1'))
+        assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2
+        assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2
+        assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3
+        assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3
+
+    def test_win32_calling_convention_3(self):
+        import sys
+        ffi, lib = self.prepare("""
+            struct point { int x, y; };
+
+            int (*const cb1)(struct point);
+            int (__stdcall *const cb2)(struct point);
+
+            struct point __stdcall call1(int(*cb)(struct point));
+            struct point call2(int(__stdcall *cb)(struct point));
+        """, 'test_win32_calling_convention_3', r"""
+            #ifndef _MSC_VER
+            #  define __cdecl
+            #  define __stdcall
+            #endif
+            struct point { int x, y; };
+            int           cb1(struct point pt) { return pt.x + 10 * pt.y; }
+            int __stdcall cb2(struct point pt) { return pt.x + 100 * pt.y; }
+            struct point __stdcall call1(int(__cdecl *cb)(struct point)) {
+                int i;
+                struct point result = { 0, 0 };
+                //printf("here1\n");
+                //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
+                for (i = 0; i < 1000; i++) {
+                    struct point p = { i, -i };
+                    int r = cb(p);
+                    result.x += r;
+                    result.y -= r;
+                }
+                return result;
+            }
+            struct point __cdecl call2(int(__stdcall *cb)(struct point)) {
+                int i;
+                struct point result = { 0, 0 };
+                for (i = 0; i < 1000; i++) {
+                    struct point p = { -i, i };
+                    int r = cb(p);
+                    result.x += r;
+                    result.y -= r;
+                }
+                return result;
+            }
+        """)
+        ptr_call1 = ffi.addressof(lib, 'call1')
+        ptr_call2 = ffi.addressof(lib, 'call2')
+        if sys.platform == 'win32' and not sys.maxsize > 2**32:
+            raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2'))
+            raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2'))
+            raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1'))
+            raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1'))
+        pt = lib.call1(ffi.addressof(lib, 'cb1'))
+        assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
+        pt = ptr_call1(ffi.addressof(lib, 'cb1'))
+        assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
+        pt = lib.call2(ffi.addressof(lib, 'cb2'))
+        assert (pt.x, pt.y) == (99*500*999, -99*500*999)
+        pt = ptr_call2(ffi.addressof(lib, 'cb2'))
+        assert (pt.x, pt.y) == (99*500*999, -99*500*999)
+
+    def test_share_FILE(self):
+        ffi1, lib1 = self.prepare("void do_stuff(FILE *);",
+                                  'test_share_FILE_a',
+                                  "void do_stuff(FILE *f) { (void)f; }")
+        ffi2, lib2 = self.prepare("FILE *barize(void);",
+                                  'test_share_FILE_b',
+                                  "FILE *barize(void) { return NULL; }")
+        lib1.do_stuff(lib2.barize())
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -757,10 +757,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/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py
@@ -262,7 +262,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 "( )"
 
@@ -273,6 +274,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;"
@@ -280,38 +288,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 [
@@ -361,6 +347,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/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
@@ -396,3 +396,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/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py
@@ -782,10 +782,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/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py
@@ -20,8 +20,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/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -1205,12 +1205,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/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
@@ -1495,15 +1495,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("""
@@ -2251,3 +2242,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