[pypy-commit] cffi default: Finish hopefully the support for anonymous structs.
arigo
noreply at buildbot.pypy.org
Thu Aug 23 18:18:00 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r889:f738cfcc7b54
Date: 2012-08-23 18:17 +0200
http://bitbucket.org/cffi/cffi/changeset/f738cfcc7b54/
Log: Finish hopefully the support for anonymous structs.
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -255,9 +255,11 @@
#
# nested anonymous structs or unions end up here
if isinstance(typenode, pycparser.c_ast.Struct):
- return self._get_struct_union_enum_type('struct', typenode, name)
+ return self._get_struct_union_enum_type('struct', typenode, name,
+ nested=True)
if isinstance(typenode, pycparser.c_ast.Union):
- return self._get_struct_union_enum_type('union', typenode, name)
+ return self._get_struct_union_enum_type('union', typenode, name,
+ nested=True)
#
raise api.FFIError("bad or unsupported type declaration")
@@ -297,7 +299,7 @@
return const or 'const' in typenode.quals
return False
- def _get_struct_union_enum_type(self, kind, type, name=None):
+ def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
# First, a level of caching on the exact 'type' node of the AST.
# This is obscure, but needed because pycparser "unrolls" declarations
# such as "typedef struct { } foo_t, *foo_p" and we end up with
@@ -380,7 +382,7 @@
# XXX pycparser is inconsistent: 'names' should be a list
# of strings, but is sometimes just one string. Use
# str.join() as a way to cope with both.
- self._make_partial(tp)
+ self._make_partial(tp, nested)
continue
if decl.bitsize is None:
bitsize = -1
@@ -389,7 +391,9 @@
self._partial_length = False
type = self._get_type(decl.type, partial_length_ok=True)
if self._partial_length:
- self._make_partial(tp)
+ self._make_partial(tp, nested)
+ if isinstance(type, model.StructType) and type.partial:
+ self._make_partial(tp, nested)
fldnames.append(decl.name or '')
fldtypes.append(type)
fldbitsize.append(bitsize)
@@ -402,11 +406,11 @@
% (tp,))
return tp
- def _make_partial(self, tp):
+ def _make_partial(self, tp, nested):
if not isinstance(tp, model.StructType):
raise api.CDefError("%s cannot be partial" % (tp,))
- if not tp.has_c_name():
- raise api.CDefError("%s is partial but has no C name" % (tp,))
+ if not tp.has_c_name() and not nested:
+ raise NotImplementedError("%s is partial but has no C name" %(tp,))
tp.partial = True
def _parse_constant(self, exprnode, partial_length_ok=False):
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -186,6 +186,21 @@
else:
yield (name, type, bitsize)
+ def force_flatten(self):
+ # force the struct or union to have a declaration that lists
+ # directly all fields returned by enumfields(), flattening
+ # nested anonymous structs/unions.
+ names = []
+ types = []
+ bitsizes = []
+ for name, type, bitsize in self.enumfields():
+ names.append(name)
+ types.append(type)
+ bitsizes.append(bitsize)
+ self.fldnames = tuple(names)
+ self.fldtypes = tuple(types)
+ self.fldbitsize = tuple(bitsizes)
+
def finish_backend_type(self, ffi):
BType = self.new_btype(ffi)
ffi._cached_btypes[self] = BType
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -450,6 +450,7 @@
totalalignment = layout[1]
fieldofs = layout[2::2]
fieldsize = layout[3::2]
+ tp.force_flatten()
assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -269,6 +269,7 @@
fieldofs.append(x)
fieldsize.append(function(num+1))
num += 2
+ tp.force_flatten()
assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -911,6 +911,8 @@
# assert did not crash
def test_nested_anonymous_struct_exact():
+ if sys.platform == 'win32':
+ py.test.skip("nested anonymous struct/union")
ffi = FFI()
ffi.cdef("""
struct foo_s { struct { int a; char b; }; union { char c, d; }; };
@@ -919,7 +921,7 @@
struct foo_s { struct { int a; char b; }; union { char c, d; }; };
""")
p = ffi.new("struct foo_s *")
- assert ffi.sizeof(p) == 3 * ffi.sizeof("int") # with alignment
+ assert ffi.sizeof(p[0]) == 3 * ffi.sizeof("int") # with alignment
p.a = 1234567
p.b = 'X'
p.c = 'Y'
@@ -929,6 +931,8 @@
assert p.d == 'Y'
def test_nested_anonymous_struct_exact_error():
+ if sys.platform == 'win32':
+ py.test.skip("nested anonymous struct/union")
ffi = FFI()
ffi.cdef("""
struct foo_s { struct { int a; char b; }; union { char c, d; }; };
@@ -939,3 +943,23 @@
py.test.raises(VerificationError, ffi.verify, """
struct foo_s { struct { int a; char e, b; }; union { char c, d; }; };
""")
+
+def test_nested_anonymous_struct_inexact_1():
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo_s { struct { char b; ...; }; union { char c, d; }; };
+ """)
+ ffi.verify("""
+ struct foo_s { int a, padding; char c, d, b; };
+ """)
+ assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
+
+def test_nested_anonymous_struct_inexact_2():
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo_s { union { char c, d; }; struct { int a; char b; }; ...; };
+ """)
+ ffi.verify("""
+ struct foo_s { int a, padding; char c, d, b; };
+ """)
+ assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
More information about the pypy-commit
mailing list