qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qapi: Permit omitting all flat union branches

Absent flat union branches default to the empty struct (since commit
800877bb16 "qapi: allow empty branches in flat unions"). But an
attempt to omit all of them is rejected with "Union 'FOO' has no
branches". Harmless oddity, but it's easy to avoid, so do that.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20190913201349.24332-11-armbru@redhat.com>
[Commit message typo fixed]

+27 -14
+1 -2
docs/devel/qapi-code-gen.txt
··· 436 436 variants for an object. There are two flavors: simple (no 437 437 discriminator or base), and flat (both discriminator and base). A union 438 438 type is defined using a data dictionary as explained in the following 439 - paragraphs. The data dictionary for either type of union must not 440 - be empty. 439 + paragraphs. Unions must have at least one branch. 441 440 442 441 A simple union type defines a mapping from automatic discriminator 443 442 values to data types like in this example:
+8 -8
scripts/qapi/common.py
··· 852 852 853 853 # With no discriminator it is a simple union. 854 854 if discriminator is None: 855 - enum_define = None 855 + enum_values = members.keys() 856 856 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum'] 857 857 if base is not None: 858 858 raise QAPISemError(info, "Simple union '%s' must not have a base" % ··· 885 885 'must not be conditional' % 886 886 (base, discriminator, name)) 887 887 enum_define = enum_types.get(discriminator_value['type']) 888 - allow_metas = ['struct'] 889 888 # Do not allow string discriminator 890 889 if not enum_define: 891 890 raise QAPISemError(info, 892 891 "Discriminator '%s' must be of enumeration " 893 892 "type" % discriminator) 893 + enum_values = enum_get_names(enum_define) 894 + allow_metas = ['struct'] 894 895 895 - # Check every branch; don't allow an empty union 896 - if len(members) == 0: 897 - raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name) 896 + if (len(enum_values) == 0): 897 + raise QAPISemError(info, "Union '%s' has no branches" % name) 898 + 898 899 for (key, value) in members.items(): 899 900 check_name(info, "Member of union '%s'" % name, key) 900 901 ··· 907 908 908 909 # If the discriminator names an enum type, then all members 909 910 # of 'data' must also be members of the enum type. 910 - if enum_define: 911 - if key not in enum_get_names(enum_define): 911 + if discriminator is not None: 912 + if key not in enum_values: 912 913 raise QAPISemError(info, 913 914 "Discriminator value '%s' is not found in " 914 915 "enum '%s'" ··· 1578 1579 assert bool(tag_member) != bool(tag_name) 1579 1580 assert (isinstance(tag_name, str) or 1580 1581 isinstance(tag_member, QAPISchemaObjectTypeMember)) 1581 - assert len(variants) > 0 1582 1582 for v in variants: 1583 1583 assert isinstance(v, QAPISchemaObjectTypeVariant) 1584 1584 self._tag_name = tag_name
+1 -1
tests/qapi-schema/flat-union-empty.err
··· 1 - tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data' 1 + tests/qapi-schema/flat-union-empty.json:4: Union 'Union' has no branches
+1 -1
tests/qapi-schema/flat-union-empty.json
··· 1 - # flat unions cannot be empty 1 + # flat union discriminator cannot be empty 2 2 { 'enum': 'Empty', 'data': [ ] } 3 3 { 'struct': 'Base', 'data': { 'type': 'Empty' } } 4 4 { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
+5
tests/qapi-schema/qapi-schema-test.json
··· 25 25 { 'struct': 'Empty1', 'data': { } } 26 26 { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } } 27 27 28 + # Likewise for an empty flat union 29 + { 'union': 'Union', 30 + 'base': { 'type': 'EnumOne' }, 'discriminator': 'type', 31 + 'data': { } } 32 + 28 33 { 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' } 29 34 30 35 # for testing override of default naming heuristic
+9
tests/qapi-schema/qapi-schema-test.out
··· 23 23 object Empty1 24 24 object Empty2 25 25 base Empty1 26 + object q_obj_Union-base 27 + member type: EnumOne optional=False 28 + object Union 29 + base q_obj_Union-base 30 + tag type 31 + case value1: q_empty 32 + case value2: q_empty 33 + case value3: q_empty 34 + case value4: q_empty 26 35 command user_def_cmd0 Empty2 -> Empty2 27 36 gen=True success_response=True boxed=False oob=False preconfig=False 28 37 enum QEnumTwo
+1 -1
tests/qapi-schema/union-empty.err
··· 1 - tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data' 1 + tests/qapi-schema/union-empty.json:2: Union 'Union' has no branches
+1 -1
tests/qapi-schema/union-empty.json
··· 1 - # unions cannot be empty 1 + # simple unions cannot be empty 2 2 { 'union': 'Union', 'data': { } }