Author: Armin Rigo <ar...@tunes.org> Branch: cffi-complex Changeset: r91484:fc36c63955e1 Date: 2017-06-02 09:25 +0200 http://bitbucket.org/pypy/pypy/changeset/fc36c63955e1/
Log: hg merge default diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.10.0 +Version: 1.11.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI from .error import CDefError, FFIError, VerificationError, VerificationMissing -__version__ = "1.10.0" -__version_info__ = (1, 10, 0) +__version__ = "1.11.0" +__version_info__ = (1, 11, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -8,7 +8,7 @@ the same works for the other two macros. Py_DEBUG implies them, but not the other way around. */ -#ifndef _CFFI_USE_EMBEDDING +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) # include <pyconfig.h> # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) # define Py_LIMITED_API diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.10.0" + "\ncompiled with cffi version: 1.11.0" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); 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 @@ -105,8 +105,11 @@ PRIM_UINT_FAST64 = 45 PRIM_INTMAX = 46 PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 -_NUM_PRIM = 48 + +_NUM_PRIM = 50 _UNKNOWN_PRIM = -1 _UNKNOWN_FLOAT_PRIM = -2 _UNKNOWN_LONG_DOUBLE = -3 @@ -128,6 +131,8 @@ 'float': PRIM_FLOAT, 'double': PRIM_DOUBLE, 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, '_Bool': PRIM_BOOL, 'wchar_t': PRIM_WCHAR, 'int8_t': PRIM_INT8, 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 @@ -16,6 +16,7 @@ except ImportError: lock = None +CDEF_SOURCE_STRING = "<cdef source string>" _r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", re.DOTALL | re.MULTILINE) _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" @@ -258,15 +259,21 @@ ctn.discard(name) typenames += sorted(ctn) # - csourcelines = ['typedef int %s;' % typename for typename in typenames] + csourcelines = [] + csourcelines.append('# 1 "<cdef automatic initialization code>"') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called <cdef source string> from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) csourcelines.append(csource) - csource = '\n'.join(csourcelines) + fullcsource = '\n'.join(csourcelines) if lock is not None: lock.acquire() # pycparser is not thread-safe... try: - ast = _get_parser().parse(csource) + ast = _get_parser().parse(fullcsource) except pycparser.c_parser.ParseError as e: self.convert_pycparser_error(e, csource) finally: @@ -276,17 +283,17 @@ return ast, macros, csource def _convert_pycparser_error(self, e, csource): - # xxx look for ":NUM:" at the start of str(e) and try to interpret - # it as a line number + # xxx look for "<cdef source string>:NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. line = None msg = str(e) - if msg.startswith(':') and ':' in msg[1:]: - linenum = msg[1:msg.find(':',1)] - if linenum.isdigit(): - linenum = int(linenum, 10) - csourcelines = csource.splitlines() - if 1 <= linenum <= len(csourcelines): - line = csourcelines[linenum-1] + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] return line def convert_pycparser_error(self, e, csource): @@ -321,10 +328,12 @@ break else: assert 0 + current_decl = None # try: self._inside_extern_python = '__cffi_extern_python_stop' for decl in iterator: + current_decl = decl if isinstance(decl, pycparser.c_ast.Decl): self._parse_decl(decl) elif isinstance(decl, pycparser.c_ast.Typedef): @@ -348,7 +357,13 @@ elif decl.__class__.__name__ == 'Pragma': pass # skip pragma, only in pycparser 2.15 else: - raise CDefError("unrecognized construct", decl) + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise except FFIError as e: msg = self._convert_pycparser_error(e, csource) if msg: diff --git a/lib_pypy/cffi/error.py b/lib_pypy/cffi/error.py --- a/lib_pypy/cffi/error.py +++ b/lib_pypy/cffi/error.py @@ -5,10 +5,13 @@ class CDefError(Exception): def __str__(self): try: - line = 'line %d: ' % (self.args[1].coord.line,) + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) except (AttributeError, TypeError, IndexError): - line = '' - return '%s%s' % (line, self.args[0]) + prefix = '' + return '%s%s' % (prefix, self.args[0]) class VerificationError(Exception): """ An error raised when verification fails diff --git a/lib_pypy/cffi/ffiplatform.py b/lib_pypy/cffi/ffiplatform.py --- a/lib_pypy/cffi/ffiplatform.py +++ b/lib_pypy/cffi/ffiplatform.py @@ -6,6 +6,7 @@ 'extra_objects', 'depends'] def get_extension(srcfilename, modname, sources=(), **kwds): + _hack_at_distutils() from distutils.core import Extension allsources = [srcfilename] for src in sources: @@ -15,6 +16,7 @@ def compile(tmpdir, ext, compiler_verbose=0, debug=None): """Compile a C extension module using distutils.""" + _hack_at_distutils() saved_environ = os.environ.copy() try: outputfilename = _build(tmpdir, ext, compiler_verbose, debug) @@ -113,3 +115,13 @@ f = cStringIO.StringIO() _flatten(x, f) return f.getvalue() + +def _hack_at_distutils(): + # Windows-only workaround for some configurations: see + # https://bugs.python.org/issue23246 (Python 2.7 with + # a specific MS compiler suite download) + if sys.platform == "win32": + try: + import setuptools # for side-effects, patches distutils + except ImportError: + pass 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 @@ -95,7 +95,8 @@ class BasePrimitiveType(BaseType): - pass + def is_complex_type(self): + return False class PrimitiveType(BasePrimitiveType): @@ -116,6 +117,8 @@ 'float': 'f', 'double': 'f', 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', '_Bool': 'i', # the following types are not primitive in the C sense 'wchar_t': 'c', @@ -163,6 +166,8 @@ return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' def is_float_type(self): return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' def build_backend_type(self, ffi, finishlist): return global_cache(self, ffi, 'new_primitive_type', self.name) 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 @@ -79,8 +79,10 @@ #define _CFFI_PRIM_UINT_FAST64 45 #define _CFFI_PRIM_INTMAX 46 #define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 -#define _CFFI__NUM_PRIM 48 +#define _CFFI__NUM_PRIM 50 #define _CFFI__UNKNOWN_PRIM (-1) #define _CFFI__UNKNOWN_FLOAT_PRIM (-2) #define _CFFI__UNKNOWN_LONG_DOUBLE (-3) diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -506,7 +506,7 @@ def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): extraarg = '' - if isinstance(tp, model.BasePrimitiveType): + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name @@ -524,8 +524,10 @@ tovar, errcode) return # - elif isinstance(tp, model.StructOrUnionOrEnum): - # a struct (not a struct pointer) as a function argument + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' % (tovar, self._gettypenum(tp), fromvar)) self._prnt(' %s;' % errcode) @@ -570,7 +572,7 @@ return '_cffi_from_c_int(%s, %s)' % (var, tp.name) elif isinstance(tp, model.UnknownFloatType): return '_cffi_from_c_double(%s)' % (var,) - elif tp.name != 'long double': + elif tp.name != 'long double' and not tp.is_complex_type(): return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( @@ -734,21 +736,26 @@ # # the PyPy version: need to replace struct/union arguments with # pointers, and if the result is a struct/union, insert a first - # arg that is a pointer to the result. + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) difference = False arguments = [] call_arguments = [] context = 'argument of %s' % name for i, type in enumerate(tp.args): indirection = '' - if isinstance(type, model.StructOrUnion): + if need_indirection(type): indirection = '*' difference = True arg = type.get_c_name(' %sx%d' % (indirection, i), context) arguments.append(arg) call_arguments.append('%sx%d' % (indirection, i)) tp_result = tp.result - if isinstance(tp_result, model.StructOrUnion): + if need_indirection(tp_result): context = 'result of %s' % name arg = tp_result.get_c_name(' *result', context) arguments.insert(0, arg) @@ -1180,7 +1187,7 @@ size_of_result = '(int)sizeof(%s)' % ( tp.result.get_c_name('', context),) prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) - prnt(' { "%s", %s };' % (name, size_of_result)) + prnt(' { "%s.%s", %s };' % (self.module_name, name, size_of_result)) prnt() # arguments = [] @@ -1479,6 +1486,12 @@ _patch_for_embedding(patchlist) if target != '*': _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) os.chdir(tmpdir) outputfilename = ffiplatform.compile('.', ext, compiler_verbose, debug) diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -26,16 +26,6 @@ s = s.encode('ascii') super(NativeIO, self).write(s) -def _hack_at_distutils(): - # Windows-only workaround for some configurations: see - # https://bugs.python.org/issue23246 (Python 2.7 with - # a specific MS compiler suite download) - if sys.platform == "win32": - try: - import setuptools # for side-effects, patches distutils - except ImportError: - pass - class Verifier(object): @@ -126,7 +116,7 @@ return basename def get_extension(self): - _hack_at_distutils() # backward compatibility hack + ffiplatform._hack_at_distutils() # backward compatibility hack if not self._has_source: with self.ffi._lock: if not self._has_source: diff --git a/pypy/doc/release-v5.8.0.rst b/pypy/doc/release-v5.8.0.rst --- a/pypy/doc/release-v5.8.0.rst +++ b/pypy/doc/release-v5.8.0.rst @@ -8,8 +8,7 @@ the dual release. Note that PyPy3.5 supports Linux 64bit only for now. This new PyPy2.7 release includes the upstream stdlib version 2.7.13, and -PyPy3.5 (our first in the 3.5 series) includes the upstream stdlib version -3.5.3. +PyPy3.5 includes the upstream stdlib version 3.5.3. We continue to make incremental improvements to our C-API compatibility layer (cpyext). PyPy2 can now import and run many C-extension @@ -19,13 +18,13 @@ faster but need real-world examples (not micro-benchmarks) of problematic code. Work proceeds at a good pace on the PyPy3.5 -version due to a grant_ from the Mozilla Foundation, hence our first 3.5.3 beta +version due to a grant_ from the Mozilla Foundation, hence our 3.5.3 beta release. Thanks Mozilla !!! While we do not pass all tests yet, asyncio works and as `these benchmarks show`_ it already gives a nice speed bump. We also backported the ``f""`` formatting from 3.6 (as an exception; otherwise "PyPy3.5" supports the Python 3.5 language). -CFFI_ has been updated to 1.10, improving an already great package for +CFFI_ has been updated to 1.11, improving an already great package for interfacing with C. As always, this release fixed many issues and bugs raised by the @@ -81,28 +80,52 @@ See also issues that were resolved_ +Note that these are also merged into PyPy 3.5 + * New features and cleanups - * Implement PyModule_New, + * Implement PyModule_New, Py_GetRecursionLimit, Py_SetRecursionLimit, + Py_EnterRecursiveCall, Py_LeaveRecursiveCall, populate tp_descr_get and + tp_descr_set slots, + add conversions of ``__len__``, ``__setitem__``, ``__delitem__`` to + appropriate C-API slots * Fix for multiple inheritance in app-level for C-API defined classes * Revert a change that removed tp_getattr (Part of the 5.7.1 bugfix release) * Document more differences with CPython here_ * Add native PyPy support to profile frames in vmprof * Fix an issue with Exception order on failed import * Fix for a corner case of __future__ imports + * Update packaged Windows zlib, sqlite, expat and OpenSSL to versions used + by CPython + * Allow windows builds to use ``jom.exe`` for compiling in parallel + * Rewrite ``itertools.groupby()``, following CPython + * Backport changes from PyPy 3.5 to minimize the code differences + * Improve support for BSD using patches contributed by downstream + * Support profile-guided optimization, enabled with --profopt, , and + specify training data ``profoptpath`` -* Bug Fixes +* Bug Fixes * Correctly handle dict.pop where the popping key is not the same type as the dict's and pop is called with a default (Part of the 5.7.1 bugfix release) * Improve our file's universal newline .readline implementation for ``\n``, ``\r`` confusion + * Tweak issue where ctype array ``_base`` was set on empty arrays, now it + is closer to the implementation in CPython + * Fix critical bugs in shadowstack that crashed multithreaded programs and + very rarely showed up even in single threaded programs + * Remove flaky fastpath function call from ctypes + * Support passing a buffersize of 0 to socket.getsockopt + * Avoid hash() returning -1 in cpyext * Performance improvements: * Tweaks made to improve performance by reducing the number of guards inserted in jitted code, based on feedback from users * Add garbage collector memory pressure to some c-level allocations + * Speed up struck.pack, struck.pack_into + * Performance tweaks to round(x, n) for the case n == 0 + * Improve zipfile performance by not doing repeated string concatenation * RPython improvements @@ -119,6 +142,11 @@ blocks are moved off-line. Also, the temporary register used to contain large constants is reused across instructions. This helps CPUs branch predictor + * Refactor rpython.rtyper.controllerentry to use use ``@specialize`` instead + of ``._annspecialcase_`` + * Refactor handling of buffers and memoryviews. Memoryviews will now be + accepted in a few more places, e.g. in compile() + .. _here: http://rpython.readthedocs.io/en/latest/cpython_differences.html @@ -129,6 +157,15 @@ * Implement main part of PEP 489 (multi-phase extension module initialization) * Add docstrings to various modules and functions + * Adapt many CPython bug/feature fixes from CPython 3.5 to PyPy3.5 + * Translation succeeds on Mac OS X, unfortunately our buildbot slave cannot + be updated to the proper development versions of OpenSSL to properly + package a release. + * Implement `` _SSLSocket.server_side`` + * Do not silently ignore ``_swappedbytes_`` in ctypes. We now raise a + ``NotImplementedError`` + * Implement and expose ``msvcrt.SetErrorMode`` + * Implement ``PyModule_GetState`` * Bug Fixes @@ -137,12 +174,19 @@ * OSError(None,None) is different from OSError() * Get closer to supporting 32 bit windows, translation now succeeds and most lib-python/3/test runs + * Call ``sys.__interactivehook__`` at startup * Performance improvements: * Use "<python> -m test" to run the CPython test suite, as documented by CPython, instead of our outdated regrverbose.py script * Change _cffi_src/openssl/callbacks.py to stop relying on the CPython C API. + * Avoid importing the full locale module during _io initialization, + CPython change fbbf8b160e8d + * Avoid freezing many app-level modules at translation, avoid importing many + modules at startup + * Refactor buffers, which allows an optimization for + ``bytearray()[:n].tobytes()`` * The following features of Python 3.5 are not implemented yet in PyPy: diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -5,4 +5,6 @@ .. this is a revision shortly after release-pypy2.7-v5.8.0 .. startrev: 558bd00b3dd8 +.. branch: cffi-complex +Part of the upgrade to cffi 1.11 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 @@ -229,13 +229,27 @@ # this checks that we get a sensible error if we try "int foo(...);" ffi = FFI() e = py.test.raises(CDefError, ffi.cdef, "int foo(...);") - assert str(e.value) == \ - "foo: a function with only '(...)' as argument is not correct C" + assert str(e.value) == ( + "<cdef source string>:1: foo: a function with only '(...)' " + "as argument is not correct C") def test_parse_error(): ffi = FFI() e = py.test.raises(CDefError, ffi.cdef, " x y z ") - assert re.match(r'cannot parse "x y z"\n:\d+:', str(e.value)) + assert str(e.value).startswith( + 'cannot parse "x y z"\n<cdef source string>:1:') + e = py.test.raises(CDefError, ffi.cdef, "\n\n\n x y z ") + assert str(e.value).startswith( + 'cannot parse "x y z"\n<cdef source string>:4:') + +def test_error_custom_lineno(): + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, """ +# 42 "foobar" + + a b c d + """) + assert str(e.value).startswith('parse error\nfoobar:43:') def test_cannot_declare_enum_later(): ffi = FFI() @@ -279,7 +293,8 @@ 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" + assert str(e.value) == ("<cdef source string>:1: f arg 1:" + " unknown type 'foobarbazzz' (if you meant" " to use the old C syntax of giving untyped" " arguments, it is not supported)") @@ -437,3 +452,9 @@ ffi._parser._declarations['extern_python foobar'] != ffi._parser._declarations['function bok'] == ffi._parser._declarations['extern_python bzrrr']) + +def test_error_invalid_syntax_for_cdef(): + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}') + assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: ' + 'this construct is valid C but not valid in cdef()') diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py @@ -240,15 +240,18 @@ tp = model.PrimitiveType(typename) C = tp.is_char_type() F = tp.is_float_type() + X = tp.is_complex_type() I = tp.is_integer_type() assert C == (typename in ('char', 'wchar_t')) assert F == (typename in ('float', 'double', 'long double')) - assert I + F + C == 1 # one and only one of them is true + assert X == (typename in ('float _Complex', 'double _Complex')) + assert I + F + C + X == 1 # one and only one of them is true def test_all_integer_and_float_types(): typenames = [] for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or + all_primitive_types[typename] == 'j' or # complex typename == '_Bool' or typename == 'long double'): pass else: 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 @@ -1705,6 +1705,8 @@ "ptrdiff_t", "size_t", "ssize_t", + 'float _Complex', + 'double _Complex', ]) for name in PRIMITIVE_TO_INDEX: x = ffi.sizeof(name) 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 @@ -156,6 +156,8 @@ ("long int", lib._CFFI_PRIM_LONG), ("unsigned short", lib._CFFI_PRIM_USHORT), ("long double", lib._CFFI_PRIM_LONGDOUBLE), + (" float _Complex", lib._CFFI_PRIM_FLOATCOMPLEX), + ("double _Complex ", lib._CFFI_PRIM_DOUBLECOMPLEX), ]: assert parse(simple_type) == ['->', Prim(expected)] @@ -281,6 +283,11 @@ parse_error("int[5](*)", "unexpected symbol", 6) parse_error("int a(*)", "identifier expected", 6) parse_error("int[123456789012345678901234567890]", "number too large", 4) + # + parse_error("_Complex", "identifier expected", 0) + parse_error("int _Complex", "_Complex type combination unsupported", 4) + parse_error("long double _Complex", "_Complex type combination unsupported", + 12) def test_number_too_large(): num_max = sys.maxsize diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py @@ -48,7 +48,6 @@ for name in cffi_opcode.PRIMITIVE_TO_INDEX: check(name, name) - def check_func(input, expected_output=None): import _cffi_backend ffi = _cffi_backend.FFI() 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 @@ -1553,7 +1553,8 @@ res = lib.bar(4, 5) assert res == 0 assert f.getvalue() == ( - b"extern \"Python\": function bar() called, but no code was attached " + b"extern \"Python\": function _CFFI_test_extern_python_1.bar() called, " + b"but no code was attached " b"to it yet with @ffi.def_extern(). Returning 0.\n") @ffi.def_extern("bar") @@ -2001,6 +2002,60 @@ """) assert lib.f1(52).a == 52 +def test_function_returns_float_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("float _Complex f1(float a, float b);"); + lib = verify(ffi, "test_function_returns_float_complex", """ + #include <complex.h> + static float _Complex f1(float a, float b) { return a + I*2.0*b; } + """) + result = lib.f1(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact + +def test_function_returns_double_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("double _Complex f1(double a, double b);"); + lib = verify(ffi, "test_function_returns_double_complex", """ + #include <complex.h> + static double _Complex f1(double a, double b) { return a + I*2.0*b; } + """) + result = lib.f1(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert result.imag == 2*5.1 # exact + +def test_function_argument_float_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("float f1(float _Complex x);"); + lib = verify(ffi, "test_function_argument_float_complex", """ + #include <complex.h> + static float f1(float _Complex x) { return cabsf(x); } + """) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-5 + +def test_function_argument_double_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("double f1(double _Complex);"); + lib = verify(ffi, "test_function_argument_double_complex", """ + #include <complex.h> + static double f1(double _Complex x) { return cabs(x); } + """) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-11 + def test_typedef_array_dotdotdot(): ffi = FFI() ffi.cdef(""" 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 @@ -220,15 +220,18 @@ tp = model.PrimitiveType(typename) C = tp.is_char_type() F = tp.is_float_type() + X = tp.is_complex_type() I = tp.is_integer_type() assert C == (typename in ('char', 'wchar_t')) assert F == (typename in ('float', 'double', 'long double')) - assert I + F + C == 1 # one and only one of them is true + assert X == (typename in ('float _Complex', 'double _Complex')) + assert I + F + C + X == 1 # one and only one of them is true def test_all_integer_and_float_types(): typenames = [] for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or + all_primitive_types[typename] == 'j' or # complex typename == '_Bool' or typename == 'long double'): pass else: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit