Commit 59a8aebc authored by Armin Rigo's avatar Armin Rigo

Issue #478

Fix a case of nested anonymous struct/unions when recompiling to Python
parent b643ede2c603
......@@ -193,6 +193,17 @@ class Recompiler:
assert isinstance(op, CffiOp)
self.cffi_types = tuple(self.cffi_types) # don't change any more
def _enum_fields(self, tp):
# When producing C, expand all anonymous struct/union fields.
# That's necessary to have C code checking the offsets of the
# individual fields contained in them. When producing Python,
# don't do it and instead write it like it is, with the
# corresponding fields having an empty name. Empty names are
# recognized at runtime when we import the generated Python
# file.
expand_anonymous_struct_union = not self.target_is_python
return tp.enumfields(expand_anonymous_struct_union)
def _do_collect_type(self, tp):
if not isinstance(tp, model.BaseTypeByIdentity):
if isinstance(tp, tuple):
......@@ -206,7 +217,7 @@ class Recompiler:
elif isinstance(tp, model.StructOrUnion):
if tp.fldtypes is not None and (
tp not in self.ffi._parser._included_declarations):
for name1, tp1, _, _ in tp.enumfields():
for name1, tp1, _, _ in self._enum_fields(tp):
self._do_collect_type(self._field_type(tp, name1, tp1))
else:
for _, x in tp._get_items():
......@@ -864,7 +875,7 @@ class Recompiler:
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
for fname, ftype, fbitsize, fqual in tp.enumfields():
for fname, ftype, fbitsize, fqual in self._enum_fields(tp):
try:
if ftype.is_integer_type() or fbitsize >= 0:
# accept all integers, but complain on float or double
......@@ -920,8 +931,7 @@ class Recompiler:
flags = '|'.join(flags) or '0'
c_fields = []
if reason_for_not_expanding is None:
expand_anonymous_struct_union = not self.target_is_python
enumfields = list(tp.enumfields(expand_anonymous_struct_union))
enumfields = list(self._enum_fields(tp))
for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
self._check_not_opaque(fldtype,
......
......@@ -74,6 +74,7 @@ def setup_module(mod):
int strlen(const char *);
struct with_union { union { int a; char b; }; };
union with_struct { struct { int a; char b; }; };
struct with_struct_with_union { struct { union { int x; }; } cp; };
struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; };
typedef struct selfref { struct selfref *next; } *selfref_ptr_t;
""")
......@@ -248,6 +249,10 @@ def test_anonymous_union_inside_struct():
assert ffi.offsetof("union with_struct", "b") == INT
assert ffi.sizeof("union with_struct") >= INT + 1
#
assert ffi.sizeof("struct with_struct_with_union") == INT
p = ffi.new("struct with_struct_with_union *")
assert p.cp.x == 0
#
FLOAT = ffi.sizeof("float")
assert ffi.sizeof("struct NVGcolor") == FLOAT * 4
assert ffi.offsetof("struct NVGcolor", "rgba") == 0
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment