Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r78419:3968d9b3c744
Date: 2015-07-03 16:51 +0200
http://bitbucket.org/pypy/pypy/changeset/3968d9b3c744/

Log:    Update to cffi/5fd800db658c

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.1.2
+Version: 1.2.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, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.1.2"
-__version_info__ = (1, 1, 2)
+__version__ = "1.2.0"
+__version_info__ = (1, 2, 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/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -428,6 +428,8 @@
             raise TypeError("ffi.include() expects an argument that is also of"
                             " type cffi.FFI, not %r" % (
                                 type(ffi_to_include).__name__,))
+        if ffi_to_include is self:
+            raise ValueError("self.include(self)")
         with ffi_to_include._lock:
             with self._lock:
                 self._parser.include(ffi_to_include._parser)
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
@@ -53,6 +53,7 @@
 OP_GLOBAL_VAR      = 33
 OP_DLOPEN_FUNC     = 35
 OP_DLOPEN_CONST    = 37
+OP_GLOBAL_VAR_F    = 39
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
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
@@ -633,6 +633,8 @@
 
     def include(self, other):
         for name, tp in other._declarations.items():
+            if name.startswith('anonymous $enum_$'):
+                continue   # fix for test_anonymous_enum_include
             kind = name.split(' ', 1)[0]
             if kind in ('struct', 'union', 'enum', 'anonymous'):
                 self._declare(name, tp, included=True)
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
@@ -35,9 +35,6 @@
     def is_integer_type(self):
         return False
 
-    def sizeof_enabled(self):
-        return False
-
     def get_cached_btype(self, ffi, finishlist, can_delay=False):
         try:
             BType = ffi._cached_btypes[self]
@@ -80,8 +77,7 @@
 
 
 class BasePrimitiveType(BaseType):
-    def sizeof_enabled(self):
-        return True
+    pass
 
 
 class PrimitiveType(BasePrimitiveType):
@@ -205,9 +201,6 @@
 class FunctionPtrType(BaseFunctionType):
     _base_pattern = '(*&)(%s)'
 
-    def sizeof_enabled(self):
-        return True
-
     def build_backend_type(self, ffi, finishlist):
         result = self.result.get_cached_btype(ffi, finishlist)
         args = []
@@ -233,9 +226,6 @@
             extra = self._base_pattern
         self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
 
-    def sizeof_enabled(self):
-        return True
-
     def build_backend_type(self, ffi, finishlist):
         BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
         return global_cache(self, ffi, 'new_pointer_type', BItem)
@@ -276,9 +266,6 @@
         self.c_name_with_marker = (
             self.item.c_name_with_marker.replace('&', brackets))
 
-    def sizeof_enabled(self):
-        return self.item.sizeof_enabled() and self.length is not None
-
     def resolve_length(self, newlength):
         return ArrayType(self.item, newlength)
 
@@ -433,9 +420,6 @@
             from . import ffiplatform
             raise ffiplatform.VerificationMissing(self._get_c_name())
 
-    def sizeof_enabled(self):
-        return self.fldtypes is not None
-
     def build_backend_type(self, ffi, finishlist):
         self.check_not_partial()
         finishlist.append(self)
@@ -464,9 +448,6 @@
         self.baseinttype = baseinttype
         self.build_c_name_with_marker()
 
-    def sizeof_enabled(self):
-        return True     # not strictly true, but external enums are obscure
-
     def force_the_name(self, forcename):
         StructOrUnionOrEnum.force_the_name(self, forcename)
         if self.forcename is None:
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
@@ -26,6 +26,7 @@
 #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
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
@@ -981,10 +981,6 @@
         if not self.target_is_python and tp.is_integer_type():
             type_op = CffiOp(OP_CONSTANT_INT, -1)
         else:
-            if not tp.sizeof_enabled():
-                raise ffiplatform.VerificationError(
-                    "constant '%s' is of type '%s', whose size is not known"
-                    % (name, tp._get_c_name()))
             if self.target_is_python:
                 const_kind = OP_DLOPEN_CONST
             else:
@@ -1069,18 +1065,36 @@
         self._do_collect_type(self._global_type(tp, name))
 
     def _generate_cpy_variable_decl(self, tp, name):
-        pass
+        prnt = self._prnt
+        tp = self._global_type(tp, name)
+        if isinstance(tp, model.ArrayType) and tp.length is None:
+            tp = tp.item
+            ampersand = ''
+        else:
+            ampersand = '&'
+        # This code assumes that casts from "tp *" to "void *" is a
+        # no-op, i.e. a function that returns a "tp *" can be called
+        # as if it returned a "void *".  This should be generally true
+        # on any modern machine.  The only exception to that rule (on
+        # uncommon architectures, and as far as I can tell) might be
+        # if 'tp' were a function type, but that is not possible here.
+        # (If 'tp' is a function _pointer_ type, then casts from "fn_t
+        # **" to "void *" are again no-ops, as far as I can tell.)
+        prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,)))
+        prnt('{')
+        prnt('  return %s(%s);' % (ampersand, name))
+        prnt('}')
+        prnt()
 
     def _generate_cpy_variable_ctx(self, tp, name):
         tp = self._global_type(tp, name)
         type_index = self._typesdict[tp]
-        type_op = CffiOp(OP_GLOBAL_VAR, type_index)
-        if tp.sizeof_enabled():
-            size = "sizeof(%s)" % (name,)
+        if self.target_is_python:
+            op = OP_GLOBAL_VAR
         else:
-            size = 0
+            op = OP_GLOBAL_VAR_F
         self._lsts["global"].append(
-            GlobalExpr(name, '&%s' % name, type_op, size))
+            GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
 
     # ----------
     # emitting the opcodes for individual types
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
@@ -2,7 +2,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rlib import rdynload
 
-VERSION = "1.1.2"
+VERSION = "1.2.0"
 
 
 class Module(MixedModule):
diff --git a/pypy/module/_cffi_backend/cdlopen.py 
b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -36,7 +36,10 @@
                         self.libname)
         try:
             cdata = dlsym(self.libhandle, name)
+            found = bool(cdata)
         except KeyError:
+            found = False
+        if not found:
             raise oefmt(self.ffi.w_FFIError,
                         "symbol '%s' not found in library '%s'",
                         name, self.libname)
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
@@ -53,6 +53,7 @@
 OP_GLOBAL_VAR      = 33
 OP_DLOPEN_FUNC     = 35
 OP_DLOPEN_CONST    = 37
+OP_GLOBAL_VAR_F    = 39
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
diff --git a/pypy/module/_cffi_backend/cglob.py 
b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -2,23 +2,38 @@
 from pypy.interpreter.typedef import TypeDef
 from pypy.module._cffi_backend.cdataobj import W_CData
 from pypy.module._cffi_backend import newtype
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+FNPTR = rffi.CCallback([], rffi.VOIDP)
 
 
 class W_GlobSupport(W_Root):
-    def __init__(self, space, w_ctype, ptr):
+    _immutable_fields_ = ['w_ctype', 'ptr', 'fetch_addr']
+
+    def __init__(self, space, w_ctype, ptr=lltype.nullptr(rffi.CCHARP.TO),
+                 fetch_addr=lltype.nullptr(rffi.VOIDP.TO)):
         self.space = space
         self.w_ctype = w_ctype
         self.ptr = ptr
+        self.fetch_addr = rffi.cast(FNPTR, fetch_addr)
+
+    def fetch_global_var_addr(self):
+        if self.ptr:
+            return self.ptr
+        result = self.fetch_addr()
+        return rffi.cast(rffi.CCHARP, result)
 
     def read_global_var(self):
-        return self.w_ctype.convert_to_object(self.ptr)
+        return self.w_ctype.convert_to_object(self.fetch_global_var_addr())
 
     def write_global_var(self, w_newvalue):
-        self.w_ctype.convert_from_object(self.ptr, w_newvalue)
+        self.w_ctype.convert_from_object(self.fetch_global_var_addr(),
+                                         w_newvalue)
 
     def address(self):
         w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype)
-        return W_CData(self.space, self.ptr, w_ctypeptr)
+        return W_CData(self.space, self.fetch_global_var_addr(), w_ctypeptr)
 
 W_GlobSupport.typedef = TypeDef("FFIGlobSupport")
 W_GlobSupport.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/lib_obj.py 
b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -102,6 +102,8 @@
                 #
             elif op == cffi_opcode.OP_GLOBAL_VAR:
                 # A global variable of the exact type specified here
+                # (nowadays, only used by the ABI mode or backend
+                # compatibility; see OP_GLOBAL_F for the API mode
                 w_ct = realize_c_type.realize_c_type(
                     self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                 g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn)
@@ -113,7 +115,13 @@
                 ptr = rffi.cast(rffi.CCHARP, g.c_address)
                 if not ptr:   # for dlopen() style
                     ptr = self.cdlopen_fetch(attr)
-                w_result = cglob.W_GlobSupport(space, w_ct, ptr)
+                w_result = cglob.W_GlobSupport(space, w_ct, ptr=ptr)
+                #
+            elif op == cffi_opcode.OP_GLOBAL_VAR_F:
+                w_ct = realize_c_type.realize_c_type(
+                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
+                w_result = cglob.W_GlobSupport(space, w_ct,
+                                               fetch_addr=g.c_address)
                 #
             elif (op == cffi_opcode.OP_CONSTANT_INT or
                   op == cffi_opcode.OP_ENUM):
@@ -131,6 +139,9 @@
                     realize_c_type.FUNCPTR_FETCH_CHARP,
                     g.c_address)
                 if w_ct.size <= 0:
+                    raise oefmt(self.ffi.w_FFIError,
+                                "constant '%s' is of type '%s', "
+                                "whose size is not known", attr, w_ct.name)
                     raise oefmt(space.w_SystemError,
                                 "constant has no known size")
                 if not fetch_funcptr:   # for dlopen() style
@@ -172,7 +183,7 @@
             w_value = self._build_attr(attr)
             if w_value is None:
                 if is_getattr and attr == '__all__':
-                    return self.dir1(ignore_type=cffi_opcode.OP_GLOBAL_VAR)
+                    return self.dir1(ignore_global_vars=True)
                 if is_getattr and attr == '__dict__':
                     return self.full_dict_copy()
                 if is_getattr and attr == '__name__':
@@ -206,14 +217,18 @@
     def descr_dir(self):
         return self.dir1()
 
-    def dir1(self, ignore_type=-1):
+    def dir1(self, ignore_global_vars=False):
         space = self.space
         total = rffi.getintfield(self.ctx, 'c_num_globals')
         g = self.ctx.c_globals
         names_w = []
         for i in range(total):
-            if getop(g[i].c_type_op) != ignore_type:
-                names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
+            if ignore_global_vars:
+                op = getop(g[i].c_type_op)
+                if (op == cffi_opcode.OP_GLOBAL_VAR or
+                    op == cffi_opcode.OP_GLOBAL_VAR_F):
+                    continue
+            names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
         return space.newlist(names_w)
 
     def full_dict_copy(self):
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
@@ -3343,4 +3343,4 @@
 
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "1.1.2"
+    assert __version__ == "1.2.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
@@ -16,8 +16,8 @@
         from cffi import ffiplatform
     except ImportError:
         py.test.skip("system cffi module not found or older than 1.0.0")
-    if cffi.__version_info__ < (1, 0, 4):
-        py.test.skip("system cffi module needs to be at least 1.0.4")
+    if cffi.__version_info__ < (1, 2, 0):
+        py.test.skip("system cffi module needs to be at least 1.2.0")
     space.appexec([], """():
         import _cffi_backend     # force it to be initialized
     """)
@@ -500,28 +500,33 @@
             "int foo(int x) { return x + 32; }")
         assert lib.foo(10) == 42
 
-    def test_bad_size_of_global_1(self):
-        ffi, lib = self.prepare(
-            "short glob;",
-            "test_bad_size_of_global_1",
-            "long glob;")
-        raises(ffi.error, getattr, lib, "glob")
-
-    def test_bad_size_of_global_2(self):
-        ffi, lib = self.prepare(
-            "int glob[10];",
-            "test_bad_size_of_global_2",
-            "int glob[9];")
-        e = raises(ffi.error, getattr, lib, "glob")
-        assert str(e.value) == ("global variable 'glob' should be 40 bytes "
-                                "according to the cdef, but is actually 36")
-
-    def test_unspecified_size_of_global(self):
+    def test_unspecified_size_of_global_1(self):
         ffi, lib = self.prepare(
             "int glob[];",
-            "test_unspecified_size_of_global",
+            "test_unspecified_size_of_global_1",
             "int glob[10];")
-        lib.glob    # does not crash
+        assert ffi.typeof(lib.glob) == ffi.typeof("int *")
+
+    def test_unspecified_size_of_global_2(self):
+        ffi, lib = self.prepare(
+            "int glob[][5];",
+            "test_unspecified_size_of_global_2",
+            "int glob[10][5];")
+        assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+    def test_unspecified_size_of_global_3(self):
+        ffi, lib = self.prepare(
+            "int glob[][...];",
+            "test_unspecified_size_of_global_3",
+            "int glob[10][5];")
+        assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+    def test_unspecified_size_of_global_4(self):
+        ffi, lib = self.prepare(
+            "int glob[...][...];",
+            "test_unspecified_size_of_global_4",
+            "int glob[10][5];")
+        assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]")
 
     def test_include_1(self):
         ffi1, lib1 = self.prepare(
@@ -869,11 +874,22 @@
             """)
         assert lib.almost_forty_two == 42.25
 
+    def test_constant_of_unknown_size(self):
+        ffi, lib = self.prepare(
+            "typedef ... opaque_t;"
+            "const opaque_t CONSTANT;",
+            'test_constant_of_unknown_size',
+            "typedef int opaque_t;"
+            "const int CONSTANT = 42;")
+        e = raises(ffi.error, getattr, lib, 'CONSTANT')
+        assert str(e.value) == ("constant 'CONSTANT' is of "
+                                "type 'opaque_t', whose size is not known")
+
     def test_variable_of_unknown_size(self):
         ffi, lib = self.prepare("""
             typedef ... opaque_t;
             opaque_t globvar;
-        """, 'test_constant_of_unknown_size', """
+        """, 'test_variable_of_unknown_size', """
             typedef char opaque_t[6];
             opaque_t globvar = "hello";
         """)
@@ -1012,3 +1028,32 @@
         assert hasattr(lib, '__dict__')
         assert lib.__all__ == ['MYFOO', 'mybar']   # but not 'myvar'
         assert lib.__name__ == repr(lib)
+
+    def test_macro_var_callback(self):
+        ffi, lib = self.prepare(
+            "int my_value; int *(*get_my_value)(void);",
+            'test_macro_var_callback',
+            "int *(*get_my_value)(void);\n"
+            "#define my_value (*get_my_value())")
+        #
+        values = ffi.new("int[50]")
+        def it():
+            for i in range(50):
+                yield i
+        it = it()
+        #
+        @ffi.callback("int *(*)(void)")
+        def get_my_value():
+            return values + it.next()
+        lib.get_my_value = get_my_value
+        #
+        values[0] = 41
+        assert lib.my_value == 41            # [0]
+        p = ffi.addressof(lib, 'my_value')   # [1]
+        assert p == values + 1
+        assert p[-1] == 41
+        assert p[+1] == 0
+        lib.my_value = 42                    # [2]
+        assert values[2] == 42
+        assert p[-1] == 41
+        assert p[+1] == 42
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
@@ -1771,3 +1771,18 @@
         py.test.raises(TypeError, ffi.new, "struct foo_s *")
         ffi.cdef("struct foo_s { int x; };")
         ffi.new("struct foo_s *")
+
+    def test_ffi_self_include(self):
+        ffi = FFI(backend=self.Backend())
+        py.test.raises(ValueError, ffi.include, ffi)
+
+    def test_anonymous_enum_include(self):
+        ffi1 = FFI()
+        ffi1.cdef("enum { EE1 };")
+        ffi = FFI()
+        ffi.include(ffi1)
+        ffi.cdef("enum { EE2, EE3 };")
+        lib = ffi.dlopen(None)
+        assert lib.EE1 == 0
+        assert lib.EE2 == 0
+        assert lib.EE3 == 1
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
@@ -1715,6 +1715,6 @@
         assert myvar == -5     # but can't be changed, so not very useful
         py.test.raises(ImportError, "from _test_import_from_lib.lib import 
bar")
         d = {}
-        exec "from _test_import_from_lib.lib import *" in d
+        exec("from _test_import_from_lib.lib import *", d)
         assert (set(key for key in d if not key.startswith('_')) ==
                 set(['myfunc', 'MYFOO']))
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
@@ -1,4 +1,5 @@
 # Generated by pypy/tool/import_cffi.py
+
 import sys, os, py
 from cffi import FFI, VerificationError
 from cffi import recompiler
@@ -511,22 +512,38 @@
 def test_bad_size_of_global_1():
     ffi = FFI()
     ffi.cdef("short glob;")
-    lib = verify(ffi, "test_bad_size_of_global_1", "long glob;")
-    py.test.raises(ffi.error, "lib.glob")
+    py.test.raises(VerificationError, verify, ffi,
+                   "test_bad_size_of_global_1", "long glob;")
 
 def test_bad_size_of_global_2():
     ffi = FFI()
     ffi.cdef("int glob[10];")
-    lib = verify(ffi, "test_bad_size_of_global_2", "int glob[9];")
-    e = py.test.raises(ffi.error, "lib.glob")
-    assert str(e.value) == ("global variable 'glob' should be 40 bytes "
-                            "according to the cdef, but is actually 36")
+    py.test.raises(VerificationError, verify, ffi,
+                   "test_bad_size_of_global_2", "int glob[9];")
 
-def test_unspecified_size_of_global():
+def test_unspecified_size_of_global_1():
     ffi = FFI()
     ffi.cdef("int glob[];")
-    lib = verify(ffi, "test_unspecified_size_of_global", "int glob[10];")
-    lib.glob    # does not crash
+    lib = verify(ffi, "test_unspecified_size_of_global_1", "int glob[10];")
+    assert ffi.typeof(lib.glob) == ffi.typeof("int *")
+
+def test_unspecified_size_of_global_2():
+    ffi = FFI()
+    ffi.cdef("int glob[][5];")
+    lib = verify(ffi, "test_unspecified_size_of_global_2", "int glob[10][5];")
+    assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+def test_unspecified_size_of_global_3():
+    ffi = FFI()
+    ffi.cdef("int glob[][...];")
+    lib = verify(ffi, "test_unspecified_size_of_global_3", "int glob[10][5];")
+    assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+def test_unspecified_size_of_global_4():
+    ffi = FFI()
+    ffi.cdef("int glob[...][...];")
+    lib = verify(ffi, "test_unspecified_size_of_global_4", "int glob[10][5];")
+    assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]")
 
 def test_include_1():
     ffi1 = FFI()
@@ -839,6 +856,22 @@
     assert isinstance(addr, ffi.CData)
     assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
 
+def test_address_of_function_with_struct():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int x; }; long myfunc(struct foo_s);")
+    lib = verify(ffi, "test_addressof_function_with_struct", """
+        struct foo_s { int x; };
+        char myfunc(struct foo_s input) { return (char)(input.x + 42); }
+    """)
+    s = ffi.new("struct foo_s *", [5])[0]
+    assert lib.myfunc(s) == 47
+    assert not isinstance(lib.myfunc, ffi.CData)
+    assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)")
+    addr = ffi.addressof(lib, 'myfunc')
+    assert addr(s) == 47
+    assert isinstance(addr, ffi.CData)
+    assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")
+
 def test_issue198():
     ffi = FFI()
     ffi.cdef("""
@@ -872,9 +905,11 @@
         typedef ... opaque_t;
         const opaque_t CONSTANT;
     """)
-    e = py.test.raises(VerificationError, verify, ffi,
-                       'test_constant_of_unknown_size', "stuff")
-    assert str(e.value) == ("constant CONSTANT: constant 'CONSTANT' is of "
+    lib = verify(ffi, 'test_constant_of_unknown_size',
+                 "typedef int opaque_t;"
+                 "const int CONSTANT = 42;")
+    e = py.test.raises(ffi.error, getattr, lib, 'CONSTANT')
+    assert str(e.value) == ("constant 'CONSTANT' is of "
                             "type 'opaque_t', whose size is not known")
 
 def test_variable_of_unknown_size():
@@ -883,7 +918,7 @@
         typedef ... opaque_t;
         opaque_t globvar;
     """)
-    lib = verify(ffi, 'test_constant_of_unknown_size', """
+    lib = verify(ffi, 'test_variable_of_unknown_size', """
         typedef char opaque_t[6];
         opaque_t globvar = "hello";
     """)
@@ -1064,3 +1099,33 @@
     assert MYFOO == 42
     assert hasattr(lib, '__dict__')
     assert lib.__all__ == ['MYFOO', 'mybar']   # but not 'myvar'
+    assert lib.__name__ == repr(lib)
+
+def test_macro_var_callback():
+    ffi = FFI()
+    ffi.cdef("int my_value; int *(*get_my_value)(void);")
+    lib = verify(ffi, 'test_macro_var_callback',
+                 "int *(*get_my_value)(void);\n"
+                 "#define my_value (*get_my_value())")
+    #
+    values = ffi.new("int[50]")
+    def it():
+        for i in range(50):
+            yield i
+    it = it()
+    #
+    @ffi.callback("int *(*)(void)")
+    def get_my_value():
+        return values + it.next()
+    lib.get_my_value = get_my_value
+    #
+    values[0] = 41
+    assert lib.my_value == 41            # [0]
+    p = ffi.addressof(lib, 'my_value')   # [1]
+    assert p == values + 1
+    assert p[-1] == 41
+    assert p[+1] == 0
+    lib.my_value = 42                    # [2]
+    assert values[2] == 42
+    assert p[-1] == 41
+    assert p[+1] == 42
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
@@ -2231,3 +2231,39 @@
     #
     ffi.cdef("typedef int... foo_t;")
     py.test.raises(VerificationError, ffi.verify, "typedef float foo_t;")
+
+def test_windows_dllimport_data():
+    if sys.platform != 'win32':
+        py.test.skip("Windows only")
+    from pypy.module.test_lib_pypy.cffi_tests.udir import udir
+    tmpfile = udir.join('dllimport_data.c')
+    tmpfile.write('int my_value = 42;\n')
+    ffi = FFI()
+    ffi.cdef("int my_value;")
+    lib = ffi.verify("extern __declspec(dllimport) int my_value;",
+                     sources = [str(tmpfile)])
+    assert lib.my_value == 42
+
+def test_macro_var():
+    ffi = FFI()
+    ffi.cdef("int myarray[50], my_value;")
+    lib = ffi.verify("""
+        int myarray[50];
+        int *get_my_value(void) {
+            static int index = 0;
+            return &myarray[index++];
+        }
+        #define my_value (*get_my_value())
+    """)
+    assert lib.my_value == 0             # [0]
+    lib.my_value = 42                    # [1]
+    assert lib.myarray[1] == 42
+    assert lib.my_value == 0             # [2]
+    lib.myarray[3] = 63
+    assert lib.my_value == 63            # [3]
+    p = ffi.addressof(lib, 'my_value')   # [4]
+    assert p[-1] == 63
+    assert p[0] == 0
+    assert p == lib.myarray + 4
+    p[1] = 82
+    assert lib.my_value == 82            # [5]
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
@@ -68,6 +68,8 @@
                 name += '.SO'
             if name.startswith('pycparser') and name.endswith('.egg'):
                 continue    # no clue why this shows up sometimes and not 
others
+            if name == '.eggs':
+                continue    # seems new in 3.5, ignore it
             assert name in content, "found unexpected file %r" % (
                 os.path.join(curdir, name),)
             value = content.pop(name)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to