Author: Romain Guillebert <romain...@gmail.com> Branch: Changeset: r1592:9267d5f13672 Date: 2014-12-17 18:04 +0100 http://bitbucket.org/cffi/cffi/changeset/9267d5f13672/
Log: Merge heads diff --git a/TODO b/TODO --- a/TODO +++ b/TODO @@ -1,10 +1,3 @@ -Next steps ----------- - -verify() handles "typedef ... some_integer_type", but this creates -an opaque type that works like a struct (so we can't get the value -out of it). - -accept and kill "static inline" in the cdefs +Add other required types from stdint.h diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -4765,7 +4765,7 @@ CFieldObject *cf; Py_ssize_t offset; - if (!PyArg_ParseTuple(args, "O!O:typeof", + if (!PyArg_ParseTuple(args, "O!O:typeoffsetof", &CTypeDescr_Type, &ct, &fieldname)) return NULL; diff --git a/cffi/cparser.py b/cffi/cparser.py --- a/cffi/cparser.py +++ b/cffi/cparser.py @@ -208,6 +208,8 @@ def _add_constants(self, key, val): if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations raise api.FFIError( "multiple declarations of constant: %s" % (key,)) self._int_constants[key] = val diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -235,7 +235,8 @@ converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name else: - converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),) + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) errvalue = '-1' # elif isinstance(tp, model.PointerType): @@ -274,8 +275,8 @@ self._prnt(' if (datasize != 0) {') self._prnt(' if (datasize < 0)') self._prnt(' %s;' % errcode) - self._prnt(' %s = alloca(datasize);' % (tovar,)) - self._prnt(' memset((void *)%s, 0, datasize);' % (tovar,)) + self._prnt(' %s = alloca((size_t)datasize);' % (tovar,)) + self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,)) self._prnt(' if (_cffi_convert_array_from_object(' '(char *)%s, _cffi_type(%d), %s) < 0)' % ( tovar, self._gettypenum(tp), fromvar)) @@ -835,12 +836,15 @@ PyLong_FromLongLong((long long)(x))) #define _cffi_from_c_int(x, type) \ - (((type)-1) > 0 ? /* unsigned */ \ - (sizeof(type) < sizeof(long) ? PyInt_FromLong(x) : \ - sizeof(type) == sizeof(long) ? PyLong_FromUnsignedLong(x) : \ - PyLong_FromUnsignedLongLong(x)) \ - : (sizeof(type) <= sizeof(long) ? PyInt_FromLong(x) : \ - PyLong_FromLongLong(x))) + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) #define _cffi_to_c_int(o, type) \ (sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ @@ -851,7 +855,7 @@ : (type)_cffi_to_c_i32(o)) : \ sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ : (type)_cffi_to_c_i64(o)) : \ - (Py_FatalError("unsupported size for type " #type), 0)) + (Py_FatalError("unsupported size for type " #type), (type)0)) #define _cffi_to_c_i8 \ ((int(*)(PyObject *))_cffi_exports[1]) diff --git a/cffi/verifier.py b/cffi/verifier.py --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -16,7 +16,8 @@ class Verifier(object): def __init__(self, ffi, preamble, tmpdir=None, modulename=None, - ext_package=None, tag='', force_generic_engine=False, flags=None, **kwds): + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, **kwds): self.ffi = ffi self.preamble = preamble if not modulename: @@ -44,7 +45,7 @@ k1, k2) suffix = _get_so_suffixes()[0] self.tmpdir = tmpdir or os.environ.get('CFFI_TMPDIR') or _caller_dir_pycache() - self.sourcefilename = os.path.join(self.tmpdir, modulename + '.c') + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) self.ext_package = ext_package self._has_source = False diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -667,7 +667,16 @@ check. Be sure to have other means of clearing the ``tmpdir`` whenever you change your sources. -.. versionadded:: 0.9 +.. versionadded:: 0.8.7 + You can give C++ source code in ``ffi.verify()``:: + + ext = ffi.verify(r''' + extern "C" { + int somefunc(int somearg) { return real_cpp_func(somearg); } + } + ''', source_extension='.cpp', extra_compile_args=['-std=c++11']) + +.. versionadded:: 0.8.7 The optional ``flags`` argument has been added, see ``man dlopen`` (ignored on Windows). It defaults to ``ffi.RTLD_NOW``. @@ -863,7 +872,9 @@ .. versionadded:: 0.8.2 The ``ffi.cdef()`` call takes an optional argument ``packed``: if - True, then all structs declared within this cdef are "packed". This + True, then all structs declared within this cdef are "packed". + (If you need both packed and non-packed structs, + use several cdefs in sequence.) This has a meaning similar to ``__attribute__((packed))`` in GCC. It specifies that all structure fields should have an alignment of one byte. (Note that the packed attribute has no effect on bit fields so diff --git a/testing/backend_tests.py b/testing/backend_tests.py --- a/testing/backend_tests.py +++ b/testing/backend_tests.py @@ -1,7 +1,7 @@ import py import platform import sys, ctypes -from cffi import FFI, CDefError +from cffi import FFI, CDefError, FFIError from testing.support import * SIZE_OF_INT = ctypes.sizeof(ctypes.c_int) @@ -1564,6 +1564,12 @@ p = ffi2.new("foo_p", [142]) assert p.x == 142 + def test_ignore_multiple_declarations_of_constant(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("#define FOO 42") + ffi.cdef("#define FOO 42") + py.test.raises(FFIError, ffi.cdef, "#define FOO 43") + def test_struct_packed(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct nonpacked { char a; int b; };") diff --git a/testing/test_verify.py b/testing/test_verify.py --- a/testing/test_verify.py +++ b/testing/test_verify.py @@ -14,12 +14,13 @@ else: if (sys.platform == 'darwin' and [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]): + # assume a standard clang or gcc + extra_compile_args = ['-Werror', '-Wconversion'] # special things for clang - extra_compile_args = [ - '-Werror', '-Qunused-arguments', '-Wno-error=shorten-64-to-32'] + extra_compile_args.append('-Qunused-arguments') else: # assume a standard gcc - extra_compile_args = ['-Werror'] + extra_compile_args = ['-Werror', '-Wconversion'] class FFI(FFI): def verify(self, *args, **kwds): @@ -89,11 +90,48 @@ lib = ffi.verify('#include <math.h>', libraries=lib_m) assert lib.sin(1.23) == math.sin(1.23) +def _Wconversion(cdef, source, **kargs): + if sys.platform == 'win32': + py.test.skip("needs GCC or Clang") + ffi = FFI() + ffi.cdef(cdef) + py.test.raises(VerificationError, ffi.verify, source, **kargs) + extra_compile_args_orig = extra_compile_args[:] + extra_compile_args.remove('-Wconversion') + try: + lib = ffi.verify(source, **kargs) + finally: + extra_compile_args[:] = extra_compile_args_orig + return lib + +def test_Wconversion_unsigned(): + _Wconversion("unsigned foo(void);", + "int foo(void) { return -1;}") + +def test_Wconversion_integer(): + _Wconversion("short foo(void);", + "long long foo(void) { return 1<<sizeof(short);}") + +def test_Wconversion_floating(): + lib = _Wconversion("float sin(double);", + "#include <math.h>", libraries=lib_m) + res = lib.sin(1.23) + assert res != math.sin(1.23) # not exact, because of double->float + assert abs(res - math.sin(1.23)) < 1E-5 + +def test_Wconversion_float2int(): + _Wconversion("int sinf(float);", + "#include <math.h>", libraries=lib_m) + +def test_Wconversion_double2int(): + _Wconversion("int sin(double);", + "#include <math.h>", libraries=lib_m) + def test_rounding_1(): ffi = FFI() - ffi.cdef("float sin(double x);") + ffi.cdef("double sinf(float x);") lib = ffi.verify('#include <math.h>', libraries=lib_m) - res = lib.sin(1.23) + res = lib.sinf(1.23) assert res != math.sin(1.23) # not exact, because of double->float assert abs(res - math.sin(1.23)) < 1E-5 @@ -112,14 +150,21 @@ assert lib.strlen(b"hi there!") == 9 def test_strlen_approximate(): - ffi = FFI() - ffi.cdef("int strlen(char *s);") - lib = ffi.verify("#include <string.h>") + lib = _Wconversion("int strlen(char *s);", + "#include <string.h>") assert lib.strlen(b"hi there!") == 9 +def test_return_approximate(): + for typename in ['short', 'int', 'long', 'long long']: + ffi = FFI() + ffi.cdef("%s foo(signed char x);" % typename) + lib = ffi.verify("signed char foo(signed char x) { return x;}") + assert lib.foo(-128) == -128 + assert lib.foo(+127) == +127 + def test_strlen_array_of_char(): ffi = FFI() - ffi.cdef("int strlen(char[]);") + ffi.cdef("size_t strlen(char[]);") lib = ffi.verify("#include <string.h>") assert lib.strlen(b"hello") == 5 @@ -208,8 +253,8 @@ ffi = FFI() ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp) for tp in typenames])) - lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return x+1; }" % - (tp, tp.replace(' ', '_'), tp) + lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return (%s)(x+1); }" % + (tp, tp.replace(' ', '_'), tp, tp) for tp in typenames])) for typename in typenames: foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_')) @@ -315,7 +360,7 @@ def test_char_type(): ffi = FFI() ffi.cdef("char foo(char);") - lib = ffi.verify("char foo(char x) { return x+1; }") + lib = ffi.verify("char foo(char x) { return ++x; }") assert lib.foo(b"A") == b"B" py.test.raises(TypeError, lib.foo, b"bar") py.test.raises(TypeError, lib.foo, "bar") @@ -896,7 +941,7 @@ static int foo(token_t *tk) { if (!tk) return -42; - *tk += 1.601; + *tk += 1.601f; return (int)*tk; } #define TOKEN_SIZE sizeof(token_t) @@ -991,7 +1036,7 @@ long a; }; int foo(struct foo_s s) { - return s.a - (int)s.b; + return (int)s.a - (int)s.b; } """) s = ffi.new("struct foo_s *", [100, 1]) @@ -1008,7 +1053,7 @@ long a; }; int foo1(struct foo_s s) { - return s.a - (int)s.b; + return (int)s.a - (int)s.b; } int (*foo)(struct foo_s s) = &foo1; """) @@ -1067,7 +1112,7 @@ def test_array_as_argument(): ffi = FFI() ffi.cdef(""" - int strlen(char string[]); + size_t strlen(char string[]); """) ffi.verify("#include <string.h>") @@ -1079,7 +1124,7 @@ """) lib = ffi.verify(""" enum foo_e { AA, CC, BB }; - int foo_func(enum foo_e e) { return e; } + int foo_func(enum foo_e e) { return (int)e; } """) assert lib.foo_func(lib.BB) == 2 py.test.raises(TypeError, lib.foo_func, "BB") @@ -1092,7 +1137,7 @@ """) lib = ffi.verify(""" enum foo_e { AA, CC, BB }; - enum foo_e foo_func(int x) { return x; } + enum foo_e foo_func(int x) { return (enum foo_e)x; } """) assert lib.foo_func(lib.BB) == lib.BB == 2 @@ -1127,6 +1172,19 @@ assert lib.AA == 0 assert lib.BB == 2 +def test_typedef_enum_as_argument(): + ffi = FFI() + ffi.cdef(""" + typedef enum { AA, BB, ... } foo_t; + int foo_func(foo_t); + """) + lib = ffi.verify(""" + typedef enum { AA, CC, BB } foo_t; + int foo_func(foo_t e) { return (int)e; } + """) + assert lib.foo_func(lib.BB) == lib.BB == 2 + py.test.raises(TypeError, lib.foo_func, "BB") + def test_typedef_enum_as_function_result(): ffi = FFI() ffi.cdef(""" @@ -1135,7 +1193,7 @@ """) lib = ffi.verify(""" typedef enum { AA, CC, BB } foo_t; - foo_t foo_func(int x) { return x; } + foo_t foo_func(int x) { return (foo_t)x; } """) assert lib.foo_func(lib.BB) == lib.BB == 2 @@ -1676,7 +1734,7 @@ static int c_callback(int how_many, ...) { va_list ap; /* collect the "..." arguments into the values[] array */ - int i, *values = alloca(how_many * sizeof(int)); + int i, *values = alloca((size_t)how_many * sizeof(int)); va_start(ap, how_many); for (i=0; i<how_many; i++) values[i] = va_arg(ap, int); @@ -1717,7 +1775,7 @@ ffi.cdef("char sum3chars(char *);") lib = ffi.verify(""" char sum3chars(char *f) { - return f[0] + f[1] + f[2]; + return (char)(f[0] + f[1] + f[2]); } """) assert lib.sum3chars((b'\x10', b'\x20', b'\x30')) == b'\x60' @@ -1817,6 +1875,7 @@ long tf_bl(signed char x, long c); unsigned long tf_bL(signed char x, unsigned long c); long long tf_bq(signed char x, long long c); + unsigned long long tf_bQ(signed char x, unsigned long long c); float tf_bf(signed char x, float c); double tf_bd(signed char x, double c); long double tf_bD(signed char x, long double c); @@ -1834,20 +1893,35 @@ double dvalue; long double Dvalue; - #define S(letter) xvalue = x; letter##value = c; return rvalue; + typedef signed char b_t; + typedef unsigned char B_t; + typedef short h_t; + typedef unsigned short H_t; + typedef int i_t; + typedef unsigned int I_t; + typedef long l_t; + typedef unsigned long L_t; + typedef long long q_t; + typedef unsigned long long Q_t; + typedef float f_t; + typedef double d_t; + typedef long double D_t; + #define S(letter) xvalue = (int)x; letter##value = (letter##_t)c; + #define R(letter) return (letter##_t)rvalue; - signed char tf_bb(signed char x, signed char c) { S(i) } - unsigned char tf_bB(signed char x, unsigned char c) { S(i) } - short tf_bh(signed char x, short c) { S(i) } - unsigned short tf_bH(signed char x, unsigned short c) { S(i) } - int tf_bi(signed char x, int c) { S(i) } - unsigned int tf_bI(signed char x, unsigned int c) { S(i) } - long tf_bl(signed char x, long c) { S(i) } - unsigned long tf_bL(signed char x, unsigned long c) { S(i) } - long long tf_bq(signed char x, long long c) { S(i) } - float tf_bf(signed char x, float c) { S(f) } - double tf_bd(signed char x, double c) { S(d) } - long double tf_bD(signed char x, long double c) { S(D) } + signed char tf_bb(signed char x, signed char c) { S(i) R(b) } + unsigned char tf_bB(signed char x, unsigned char c) { S(i) R(B) } + short tf_bh(signed char x, short c) { S(i) R(h) } + unsigned short tf_bH(signed char x, unsigned short c) { S(i) R(H) } + int tf_bi(signed char x, int c) { S(i) R(i) } + unsigned int tf_bI(signed char x, unsigned int c) { S(i) R(I) } + long tf_bl(signed char x, long c) { S(i) R(l) } + unsigned long tf_bL(signed char x, unsigned long c) { S(i) R(L) } + long long tf_bq(signed char x, long long c) { S(i) R(q) } + unsigned long long tf_bQ(signed char x, unsigned long long c) { S(i) R(Q) } + float tf_bf(signed char x, float c) { S(f) R(f) } + double tf_bd(signed char x, double c) { S(d) R(d) } + long double tf_bD(signed char x, long double c) { S(D) R(D) } """) lib.rvalue = 0x7182838485868788 for kind, cname in [('b', 'signed char'), @@ -1859,6 +1933,7 @@ ('l', 'long'), ('L', 'unsigned long'), ('q', 'long long'), + ('Q', 'unsigned long long'), ('f', 'float'), ('d', 'double'), ('D', 'long double')]: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit