[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