qapi: Generate a nicer struct for flat unions

The struct generated for a flat union is weird: the members of its
base are at the end, except for the union tag, which is at the
beginning.

Example: qapi-schema-test.json has

{ 'struct': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }

{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }

We generate:

struct UserDefFlatUnion
{
EnumOne enum1;
union {
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
char *string;
};

Change to put all base members at the beginning, unadulterated. Not
only is this easier to understand, it also permits casting the flat
union to its base, if that should become useful.

We now generate:

struct UserDefFlatUnion
{
/* Members inherited from UserDefUnionBase: */
char *string;
EnumOne enum1;
/* Own members: */
union { /* union tag is @enum1 */
void *data;
UserDefA *value1;
UserDefB *value2;
UserDefB *value3;
};
};

Backports commit 1e6c1616a91cdcbe9a8387541f7689b8c11632aa from qemu
This commit is contained in:
Markus Armbruster 2018-02-19 16:14:50 -05:00 committed by Lioncash
parent 8b7252d8c8
commit 389afaa743
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -198,13 +198,30 @@ def generate_union(expr, meta):
ret = mcgen('''
struct %(name)s
{
%(discriminator_type_name)s %(discriminator)s;
union {
''',
name=name)
if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=c_name(base))
base_fields = find_struct(base)['data']
ret += generate_struct_fields(base_fields)
ret += mcgen('''
/* Own members: */
''')
else:
assert not discriminator
ret += mcgen('''
%(discriminator_type_name)s kind;
''',
discriminator_type_name=c_name(discriminator_type_name))
ret += mcgen('''
union { /* union tag is @%(c_name)s */
void *data;
''',
name=name,
discriminator=c_name(discriminator or 'kind'),
discriminator_type_name=c_name(discriminator_type_name))
c_name=c_name(discriminator or 'kind'))
for key in typeinfo:
ret += mcgen('''
@ -215,17 +232,6 @@ struct %(name)s
ret += mcgen('''
};
''')
if base:
assert discriminator
base_fields = find_struct(base)['data'].copy()
del base_fields[discriminator]
ret += generate_struct_fields(base_fields)
else:
assert not discriminator
ret += mcgen('''
};
''')
if meta == 'alternate':