[pypy-commit] pypy default: update to cffi/5ef556ba98f2
arigo
pypy.commits at gmail.com
Thu Oct 27 18:10:17 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r87963:c0bfb0e1b91d
Date: 2016-10-27 17:24 +0200
http://bitbucket.org/pypy/pypy/changeset/c0bfb0e1b91d/
Log: update to cffi/5ef556ba98f2
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
@@ -334,6 +334,8 @@
realtype, quals = self._get_type_and_quals(
decl.type, name=decl.name, partial_length_ok=True)
self._declare('typedef ' + decl.name, realtype, quals=quals)
+ elif decl.__class__.__name__ == 'Pragma':
+ pass # skip pragma, only in pycparser 2.15
else:
raise api.CDefError("unrecognized construct", decl)
except api.FFIError as e:
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
@@ -519,10 +519,18 @@
smallest_value = min(self.enumvalues)
largest_value = max(self.enumvalues)
else:
- raise api.CDefError("%r has no values explicitly defined: "
- "refusing to guess which integer type it is "
- "meant to be (unsigned/signed, int/long)"
- % self._get_c_name())
+ import warnings
+ try:
+ # XXX! The goal is to ensure that the warnings.warn()
+ # will not suppress the warning. We want to get it
+ # several times if we reach this point several times.
+ __warningregistry__.clear()
+ except NameError:
+ pass
+ warnings.warn("%r has no values explicitly defined; "
+ "guessing that it is equivalent to 'unsigned int'"
+ % self._get_c_name())
+ smallest_value = largest_value = 0
if smallest_value < 0: # needs a signed type
sign = 1
candidate1 = PrimitiveType("int")
diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py
--- a/lib_pypy/cffi/setuptools_ext.py
+++ b/lib_pypy/cffi/setuptools_ext.py
@@ -1,4 +1,5 @@
import os
+import sys
try:
basestring
@@ -74,8 +75,13 @@
Add py_limited_api to kwds if setuptools >= 26 is in use.
Do not alter the setting if it already exists.
Setuptools takes care of ignoring the flag on Python 2 and PyPy.
+
+ CPython itself should ignore the flag in a debugging version
+ (by not listing .abi3.so in the extensions it supports), but
+ it doesn't so far, creating troubles. That's why we check
+ for "not sys.flags.debug". (http://bugs.python.org/issue28401)
"""
- if 'py_limited_api' not in kwds:
+ if 'py_limited_api' not in kwds and not sys.flags.debug:
import setuptools
try:
setuptools_major_version = int(setuptools.__version__.partition('.')[0])
diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -2,6 +2,7 @@
from pypy.interpreter.gateway import unwrap_spec, interp2app
from pypy.interpreter.typedef import TypeDef, make_weakref_descr
from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypearray
+from pypy.module._cffi_backend import ctypestruct
from pypy.objspace.std.bufferobject import W_Buffer
from rpython.rlib.buffer import Buffer
@@ -71,7 +72,12 @@
ctype = w_cdata.ctype
if isinstance(ctype, ctypeptr.W_CTypePointer):
if size < 0:
- size = ctype.ctitem.size
+ structobj = w_cdata.get_structobj()
+ if (structobj is not None and
+ isinstance(structobj.ctype, ctypestruct.W_CTypeStructOrUnion)):
+ size = structobj._sizeof()
+ if size < 0:
+ size = ctype.ctitem.size
elif isinstance(ctype, ctypearray.W_CTypeArray):
if size < 0:
size = w_cdata._sizeof()
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -329,7 +329,7 @@
def getattr(self, w_attr):
cfield = self.getcfield(w_attr)
with self as ptr:
- w_res = cfield.read(ptr)
+ w_res = cfield.read(ptr, self)
return w_res
def setattr(self, w_attr, w_value):
@@ -432,6 +432,9 @@
lst = ct.cdata_dir()
return space.newlist([space.wrap(s) for s in lst])
+ def get_structobj(self):
+ return None
+
class W_CDataMem(W_CData):
"""This is used only by the results of cffi.cast('int', x)
@@ -453,28 +456,36 @@
by newp(). They create and free their own memory according to an
allocator."""
- # the 'length' is either >= 0 for arrays, or -1 for pointers.
- _attrs_ = ['length']
- _immutable_fields_ = ['length']
+ # the 'allocated_length' is >= 0 for arrays; for var-sized
+ # structures it is the total size in bytes; otherwise it is -1.
+ _attrs_ = ['allocated_length']
+ _immutable_fields_ = ['allocated_length']
def __init__(self, space, cdata, ctype, length=-1):
W_CData.__init__(self, space, cdata, ctype)
- self.length = length
+ self.allocated_length = length
def _repr_extra(self):
return self._repr_extra_owning()
def _sizeof(self):
ctype = self.ctype
- if self.length >= 0:
+ if self.allocated_length >= 0:
from pypy.module._cffi_backend import ctypearray
- assert isinstance(ctype, ctypearray.W_CTypeArray)
- return self.length * ctype.ctitem.size
+ if isinstance(ctype, ctypearray.W_CTypeArray):
+ return self.allocated_length * ctype.ctitem.size
+ else:
+ return self.allocated_length # var-sized struct size
else:
return ctype.size
def get_array_length(self):
- return self.length
+ from pypy.module._cffi_backend import ctypearray
+ assert isinstance(self.ctype, ctypearray.W_CTypeArray)
+ return self.allocated_length
+
+ def get_structobj(self):
+ return self
class W_CDataNewStd(W_CDataNewOwning):
@@ -508,12 +519,19 @@
self.structobj = structobj
def _repr_extra(self):
- return self._repr_extra_owning()
+ return self.structobj._repr_extra_owning()
def _do_getitem(self, ctype, i):
assert i == 0
return self.structobj
+ def get_structobj(self):
+ structobj = self.structobj
+ if isinstance(structobj, W_CDataNewOwning):
+ return structobj
+ else:
+ return None
+
class W_CDataSliced(W_CData):
"""Subclass with an explicit length, for slices."""
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -211,13 +211,16 @@
# a W_CDataPtrToStruct object which has a strong reference
# to a W_CDataNewOwning that really contains the structure.
#
- if not space.is_w(w_init, space.w_None):
- ctitem.force_lazy_struct()
- if ctitem._with_var_array:
+ varsize_length = -1
+ ctitem.force_lazy_struct()
+ if ctitem._with_var_array:
+ if not space.is_w(w_init, space.w_None):
datasize = ctitem.convert_struct_from_object(
lltype.nullptr(rffi.CCHARP.TO), w_init, datasize)
+ varsize_length = datasize
#
- cdatastruct = allocator.allocate(space, datasize, ctitem)
+ cdatastruct = allocator.allocate(space, datasize, ctitem,
+ length=varsize_length)
ptr = cdatastruct.unsafe_escaping_ptr()
cdata = cdataobj.W_CDataPtrToStructOrUnion(space, ptr,
self, cdatastruct)
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -210,7 +210,7 @@
return W_CField(self.ctype, offset + self.offset,
self.bitshift, self.bitsize, self.flags | fflags)
- def read(self, cdata):
+ def read(self, cdata, w_cdata):
cdata = rffi.ptradd(cdata, self.offset)
if self.bitshift == self.BS_REGULAR:
return self.ctype.convert_to_object(cdata)
@@ -218,6 +218,14 @@
from pypy.module._cffi_backend import ctypearray
ctype = self.ctype
assert isinstance(ctype, ctypearray.W_CTypeArray)
+ structobj = w_cdata.get_structobj()
+ if structobj is not None and self.offset == structobj.ctype.size:
+ # variable-length array
+ size = structobj.allocated_length - self.offset
+ if size >= 0:
+ arraylen = size // ctype.ctitem.size
+ return cdataobj.W_CDataSliced(ctype.space, cdata, ctype,
+ arraylen)
return cdataobj.W_CData(ctype.space, cdata, ctype.ctptr)
else:
return self.convert_bitfield_to_object(cdata)
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -353,7 +353,7 @@
if fbitsize < 0:
# not a bitfield: common case
- if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0:
+ if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length<=0:
bs_flag = ctypestruct.W_CField.BS_EMPTY_ARRAY
else:
bs_flag = ctypestruct.W_CField.BS_REGULAR
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
@@ -3161,17 +3161,19 @@
assert d[1][0] == 'y'
assert d[1][1].type is BArray
assert d[1][1].offset == size_of_int()
- assert d[1][1].bitshift == -1
+ assert d[1][1].bitshift == -2
assert d[1][1].bitsize == -1
#
p = newp(new_pointer_type(BStruct))
p.x = 42
assert p.x == 42
- assert typeof(p.y) is BIntP
+ assert typeof(p.y) is BArray
+ assert len(p.y) == 0
assert p.y == cast(BIntP, p) + 1
#
p = newp(new_pointer_type(BStruct), [100])
assert p.x == 100
+ assert len(p.y) == 0
#
# Tests for
# ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
@@ -3186,6 +3188,10 @@
p.y[0] = 200
assert p.y[2] == 0
p.y[2] = 400
+ assert len(p.y) == 3
+ assert len(p[0].y) == 3
+ assert len(buffer(p)) == sizeof(BInt) * 4
+ assert sizeof(p[0]) == sizeof(BInt) * 4
plist.append(p)
for i in range(20):
p = plist[i]
@@ -3193,13 +3199,31 @@
assert p.y[0] == 200
assert p.y[1] == i
assert p.y[2] == 400
- assert list(p.y[0:3]) == [200, i, 400]
+ assert list(p.y) == [200, i, 400]
#
# the following assignment works, as it normally would, for any array field
- p.y = [500, 600]
- assert list(p.y[0:3]) == [500, 600, 400]
+ p.y = [501, 601]
+ assert list(p.y) == [501, 601, 400]
+ p[0].y = [500, 600]
+ assert list(p[0].y) == [500, 600, 400]
+ assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
+ sizeof(BStruct) + 3 * sizeof(BInt),)
+ assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
+ sizeof(BStruct) + 3 * sizeof(BInt),)
+ assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
+ #
+ # from a non-owning pointer, we can't get the length
+ q = cast(new_pointer_type(BStruct), p)
+ assert q.y[0] == 500
+ assert q[0].y[0] == 500
+ py.test.raises(TypeError, len, q.y)
+ py.test.raises(TypeError, len, q[0].y)
+ assert typeof(q.y) is BIntP
+ assert typeof(q[0].y) is BIntP
+ assert sizeof(q[0]) == sizeof(BStruct)
#
# error cases
+ py.test.raises(IndexError, "p.y[4]")
py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
py.test.raises(TypeError, "p.y = 15")
py.test.raises(TypeError, "p.y = None")
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
@@ -408,11 +408,14 @@
'test_misdeclared_field_1',
"struct foo_s { int a[6]; };")
assert ffi.sizeof("struct foo_s") == 24 # found by the actual C code
- p = ffi.new("struct foo_s *")
- # lazily build the fields and boom:
- e = raises(ffi.error, getattr, p, "a")
- assert str(e.value).startswith("struct foo_s: wrong size for field 'a' "
- "(cdef says 20, but C compiler says 24)")
+ try:
+ # lazily build the fields and boom:
+ p = ffi.new("struct foo_s *")
+ p.a
+ assert False, "should have raised"
+ except ffi.error as e:
+ assert str(e).startswith("struct foo_s: wrong size for field 'a' "
+ "(cdef says 20, but C compiler says 24)")
def test_open_array_in_struct(self):
ffi, lib = self.prepare(
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
@@ -1356,15 +1356,15 @@
assert ffi.getctype("e1*") == 'e1 *'
def test_opaque_enum(self):
+ import warnings
ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo;")
- from cffi import __version_info__
- if __version_info__ < (1, 8):
- py.test.skip("re-enable me in version 1.8")
- e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
- assert str(e.value) == (
- "'enum foo' has no values explicitly defined: refusing to guess "
- "which integer type it is meant to be (unsigned/signed, int/long)")
+ with warnings.catch_warnings(record=True) as log:
+ n = ffi.cast("enum foo", -1)
+ assert int(n) == 0xffffffff
+ assert str(log[0].message) == (
+ "'enum foo' has no values explicitly defined; "
+ "guessing that it is equivalent to 'unsigned int'")
def test_new_ctype(self):
ffi = FFI(backend=self.Backend())
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
@@ -283,10 +283,20 @@
ffi.cdef("struct foo_s { int x; int a[]; };")
p = ffi.new("struct foo_s *", [100, [200, 300, 400]])
assert p.x == 100
- assert ffi.typeof(p.a) is ffi.typeof("int *") # no length available
+ assert ffi.typeof(p.a) is ffi.typeof("int[]")
+ assert len(p.a) == 3 # length recorded
assert p.a[0] == 200
assert p.a[1] == 300
assert p.a[2] == 400
+ assert list(p.a) == [200, 300, 400]
+ q = ffi.cast("struct foo_s *", p)
+ assert q.x == 100
+ assert ffi.typeof(q.a) is ffi.typeof("int *") # no length recorded
+ py.test.raises(TypeError, len, q.a)
+ assert q.a[0] == 200
+ assert q.a[1] == 300
+ assert q.a[2] == 400
+ py.test.raises(TypeError, list, q.a)
@pytest.mark.skipif("sys.platform != 'win32'")
def test_getwinerror(self):
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
@@ -592,10 +592,15 @@
ffi.verify("struct foo_s { int x; int a[]; };")
assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
s = ffi.new("struct foo_s *", [424242, 4])
- assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int') # the same in C
+ assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
+ assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
+ # ^^^ explanation: if you write in C: "char x[5];", then
+ # "sizeof(ax" will evaluate to 5. The behavior above is
+ # a generalization of that to "struct foo_s[len(a)=5] x;"
+ # if you could do that in C.
assert s.a[3] == 0
s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
- assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
+ assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
assert s.a[3] == -10
s = ffi.new("struct foo_s *")
assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
@@ -610,10 +615,10 @@
ffi.verify("struct foo_s { int x, y; int a[]; };")
assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
s = ffi.new("struct foo_s *", [424242, 4])
- assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+ assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
assert s.a[3] == 0
s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
- assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+ assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
assert s.a[3] == -10
s = ffi.new("struct foo_s *")
assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
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
@@ -1634,10 +1634,19 @@
# struct array_no_length { int x; int a[]; };
p = ffi.new("struct array_no_length *", [100, [200, 300, 400]])
assert p.x == 100
- assert ffi.typeof(p.a) is ffi.typeof("int *") # no length available
+ assert ffi.typeof(p.a) is ffi.typeof("int[]") # length available
assert p.a[0] == 200
assert p.a[1] == 300
assert p.a[2] == 400
+ assert len(p.a) == 3
+ assert list(p.a) == [200, 300, 400]
+ q = ffi.cast("struct array_no_length *", p)
+ assert ffi.typeof(q.a) is ffi.typeof("int *") # no length available
+ assert q.a[0] == 200
+ assert q.a[1] == 300
+ assert q.a[2] == 400
+ py.test.raises(TypeError, len, q.a)
+ py.test.raises(TypeError, list, q.a)
def test_from_buffer(self):
import array
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
@@ -400,11 +400,14 @@
pass # ok, fail during compilation already (e.g. C++)
else:
assert ffi.sizeof("struct foo_s") == 24 # found by the actual C code
- p = ffi.new("struct foo_s *")
- # lazily build the fields and boom:
- e = py.test.raises(ffi.error, "p.a")
- assert str(e.value).startswith("struct foo_s: wrong size for field 'a' "
- "(cdef says 20, but C compiler says 24)")
+ try:
+ # lazily build the fields and boom:
+ p = ffi.new("struct foo_s *")
+ p.a
+ assert False, "should have raised"
+ except ffi.error as e:
+ assert str(e).startswith("struct foo_s: wrong size for field 'a' "
+ "(cdef says 20, but C compiler says 24)")
def test_open_array_in_struct():
ffi = FFI()
More information about the pypy-commit
mailing list