]> git.proxmox.com Git - mirror_qemu.git/commitdiff
qapi: Permit omitting all flat union branches
authorMarkus Armbruster <armbru@redhat.com>
Fri, 13 Sep 2019 20:13:43 +0000 (22:13 +0200)
committerMarkus Armbruster <armbru@redhat.com>
Tue, 24 Sep 2019 12:07:22 +0000 (14:07 +0200)
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]

docs/devel/qapi-code-gen.txt
scripts/qapi/common.py
tests/qapi-schema/flat-union-empty.err
tests/qapi-schema/flat-union-empty.json
tests/qapi-schema/qapi-schema-test.json
tests/qapi-schema/qapi-schema-test.out
tests/qapi-schema/union-empty.err
tests/qapi-schema/union-empty.json

index 4ce67752a7521ff044465d8c1f2079d36b70ae3c..ec2d3744836a46b1a3791b96bc2ca3eee95f5cf2 100644 (file)
@@ -436,8 +436,7 @@ Union types are used to let the user choose between several different
 variants for an object.  There are two flavors: simple (no
 discriminator or base), and flat (both discriminator and base).  A union
 type is defined using a data dictionary as explained in the following
-paragraphs.  The data dictionary for either type of union must not
-be empty.
+paragraphs.  Unions must have at least one branch.
 
 A simple union type defines a mapping from automatic discriminator
 values to data types like in this example:
index 99db18f3d6c53d90bb1013c0a6fecf4a2d175680..3393a049cc7b640c1cf5ec3bd3de1d7e7ec0bee1 100644 (file)
@@ -852,7 +852,7 @@ def check_union(expr, info):
 
     # With no discriminator it is a simple union.
     if discriminator is None:
-        enum_define = None
+        enum_values = members.keys()
         allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
         if base is not None:
             raise QAPISemError(info, "Simple union '%s' must not have a base" %
@@ -885,16 +885,17 @@ def check_union(expr, info):
                                'must not be conditional' %
                                (base, discriminator, name))
         enum_define = enum_types.get(discriminator_value['type'])
-        allow_metas = ['struct']
         # Do not allow string discriminator
         if not enum_define:
             raise QAPISemError(info,
                                "Discriminator '%s' must be of enumeration "
                                "type" % discriminator)
+        enum_values = enum_get_names(enum_define)
+        allow_metas = ['struct']
+
+    if (len(enum_values) == 0):
+        raise QAPISemError(info, "Union '%s' has no branches" % name)
 
-    # Check every branch; don't allow an empty union
-    if len(members) == 0:
-        raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
     for (key, value) in members.items():
         check_name(info, "Member of union '%s'" % name, key)
 
@@ -907,8 +908,8 @@ def check_union(expr, info):
 
         # If the discriminator names an enum type, then all members
         # of 'data' must also be members of the enum type.
-        if enum_define:
-            if key not in enum_get_names(enum_define):
+        if discriminator is not None:
+            if key not in enum_values:
                 raise QAPISemError(info,
                                    "Discriminator value '%s' is not found in "
                                    "enum '%s'"
@@ -1578,7 +1579,6 @@ class QAPISchemaObjectTypeVariants(object):
         assert bool(tag_member) != bool(tag_name)
         assert (isinstance(tag_name, str) or
                 isinstance(tag_member, QAPISchemaObjectTypeMember))
-        assert len(variants) > 0
         for v in variants:
             assert isinstance(v, QAPISchemaObjectTypeVariant)
         self._tag_name = tag_name
index 15754f54eb9251724eaddb1dc98085fc941b781c..fedbc0d1cfee76ab879efe7c6a924bcf1680aca3 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data'
+tests/qapi-schema/flat-union-empty.json:4: Union 'Union' has no branches
index 77f1d9abfb8f9b39a0a9dd9a03be3cb4e4343c15..83e1cc7b96be52b4e9fdcdc4ceaeff1e029315d2 100644 (file)
@@ -1,4 +1,4 @@
-# flat unions cannot be empty
+# flat union discriminator cannot be empty
 { 'enum': 'Empty', 'data': [ ] }
 { 'struct': 'Base', 'data': { 'type': 'Empty' } }
 { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
index 8b0d47c4ab4ed50fea2b3c01b5680c58eaa48946..75c42eb0e3e9eb122c452ed2e9c520dcbd76051f 100644 (file)
 { 'struct': 'Empty1', 'data': { } }
 { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
 
+# Likewise for an empty flat union
+{ 'union': 'Union',
+  'base': { 'type': 'EnumOne' }, 'discriminator': 'type',
+  'data': { } }
+
 { 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
 
 # for testing override of default naming heuristic
index bea7976bbbbd3ac3cc4e9767d64aa72f95f0f386..98031da96f0ceed62fcf578fe8e3ad9bf01a5b54 100644 (file)
@@ -23,6 +23,15 @@ enum MyEnum
 object Empty1
 object Empty2
     base Empty1
+object q_obj_Union-base
+    member type: EnumOne optional=False
+object Union
+    base q_obj_Union-base
+    tag type
+    case value1: q_empty
+    case value2: q_empty
+    case value3: q_empty
+    case value4: q_empty
 command user_def_cmd0 Empty2 -> Empty2
    gen=True success_response=True boxed=False oob=False preconfig=False
 enum QEnumTwo
index 12c20221bdfb6f7b046a7deaaf1074aa6126b651..d4241a38a2c450ab8fe700972821d1caadd928b2 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data'
+tests/qapi-schema/union-empty.json:2: Union 'Union' has no branches
index 1f0b13ca21ae25d34b9d67da84df14b88f35e959..df3e5e639a5e96a43fcd75b30eb3aa2f5f348787 100644 (file)
@@ -1,2 +1,2 @@
-# unions cannot be empty
+# simple unions cannot be empty
 { 'union': 'Union', 'data': { } }