Commit a8d4a2e4 authored by Eric Blake's avatar Eric Blake Committed by Markus Armbruster
Browse files

qapi: Forbid base without discriminator in unions



None of the existing QMP or QGA interfaces uses a union with a
base type but no discriminator; it is easier to avoid this in the
generator to save room for other future extensions more likely to
be useful.  An earlier commit added a union-base-no-discriminator
test to ensure that we eventually give a decent error message;
likewise, removing UserDefUnion outright is okay, because we moved
all the tests we wish to keep into the tests of the simple union
UserDefNativeListUnion in the previous commit.  Now is the time to
actually forbid simple union with base, and remove the last
vestiges from the testsuite.

Signed-off-by: default avatarEric Blake <eblake@redhat.com>
Reviewed-by: default avatarMarkus Armbruster <armbru@redhat.com>
Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
parent 805017b7
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -242,9 +242,8 @@ struct %(name)s
''')

    if base:
        base_fields = find_struct(base)['data']
        if discriminator:
            base_fields = base_fields.copy()
        assert discriminator
        base_fields = find_struct(base)['data'].copy()
        del base_fields[discriminator]
        ret += generate_struct_fields(base_fields)
    else:
+5 −6
Original line number Diff line number Diff line
@@ -310,15 +310,14 @@ def generate_visit_union(expr):
        ret = ""
        disc_type = enum_define['enum_name']
    else:
        # There will always be a discriminator in the C switch code, by default it
        # is an enum type generated silently as "'%sKind' % (name)"
        # There will always be a discriminator in the C switch code, by default
        # it is an enum type generated silently as "'%sKind' % (name)"
        ret = generate_visit_enum('%sKind' % name, members.keys())
        disc_type = '%sKind' % (name)

    if base:
        base_fields = find_struct(base)['data']
        if discriminator:
            base_fields = base_fields.copy()
        assert discriminator
        base_fields = find_struct(base)['data'].copy()
        del base_fields[discriminator]
        ret += generate_visit_struct_fields(name, "", "", base_fields)

+10 −10
Original line number Diff line number Diff line
@@ -259,22 +259,22 @@ def check_union(expr, expr_info):
    discriminator = expr.get('discriminator')
    members = expr['data']

    # If the object has a member 'base', its value must name a complex type.
    if base:
    # If the object has a member 'base', its value must name a complex type,
    # and there must be a discriminator.
    if base is not None:
        if discriminator is None:
            raise QAPIExprError(expr_info,
                                "Union '%s' requires a discriminator to go "
                                "along with base" %name)
        base_fields = find_base_fields(base)
        if not base_fields:
            raise QAPIExprError(expr_info,
                                "Base '%s' is not a valid type"
                                % base)

    # If the union object has no member 'discriminator', it's an
    # ordinary union.
    if not discriminator:
        enum_define = None

    # Else if the value of member 'discriminator' is {}, it's an
    # anonymous union.
    elif discriminator == {}:
    # If the union object has no member 'discriminator', it's a
    # simple union. If 'discriminator' is {}, it is an anonymous union.
    if not discriminator or discriminator == {}:
        enum_define = None

    # Else, it's a flat union.
+0 −4
Original line number Diff line number Diff line
@@ -36,10 +36,6 @@
{ 'type': 'UserDefC',
  'data': { 'string1': 'str', 'string2': 'str' } }

{ 'union': 'UserDefUnion',
  'base': 'UserDefZero',
  'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } }

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

+0 −2
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@
 OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
 OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
 OrderedDict([('type', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
 OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]),
 OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
 OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
 OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]),
@@ -24,7 +23,6 @@
 OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]),
 OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))])]
[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
 {'enum_name': 'UserDefUnionKind', 'enum_values': None},
 {'enum_name': 'UserDefAnonUnionKind', 'enum_values': None},
 {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}]
[OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
Loading