Commit 1e6c1616 authored by Markus Armbruster's avatar Markus Armbruster
Browse files

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;
        };
    };

Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
parent 0f61af3e
Loading
Loading
Loading
Loading
+22 −16
Original line number Diff line number Diff line
@@ -200,14 +200,31 @@ def generate_union(expr, meta):
    ret = mcgen('''
struct %(name)s
{
    %(discriminator_type_name)s %(discriminator)s;
    union {
        void *data;
''',
                name=name,
                discriminator=c_name(discriminator or 'kind'),
                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;
''',
                 c_name=c_name(discriminator or 'kind'))

    for key in typeinfo:
        ret += mcgen('''
        %(c_type)s %(c_name)s;
@@ -217,17 +234,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':