diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 128f074a2de49e7cf200a2ff85487d20822ded05..999f3b98f021d2af25c2d7fd47873f49b42a39ff 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -187,11 +187,11 @@ prevent incomplete include files. Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME } -A struct is a dictionary containing a single 'data' key whose -value is a dictionary. This corresponds to a struct in C or an Object -in JSON. Each value of the 'data' dictionary must be the name of a -type, or a one-element array containing a type name. An example of a -struct is: +A struct is a dictionary containing a single 'data' key whose value is +a dictionary; the dictionary may be empty. This corresponds to a +struct in C or an Object in JSON. Each value of the 'data' dictionary +must be the name of a type, or a one-element array containing a type +name. An example of a struct is: { 'struct': 'MyType', 'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } } @@ -288,9 +288,10 @@ or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME, 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), flat (both discriminator and base). A union +discriminator or base), and flat (both discriminator and base). A union type is defined using a data dictionary as explained in the following -paragraphs. +paragraphs. The data dictionary for either type of union must not +be empty. A simple union type defines a mapping from automatic discriminator values to data types like in this example: diff --git a/scripts/qapi.py b/scripts/qapi.py index f40dc9e777d809b387a833dd492e2d839459d94b..f97236f5098aea44f316090ae176fe153c39aa38 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -590,7 +590,10 @@ def check_union(expr, expr_info): "Discriminator '%s' must be of enumeration " "type" % discriminator) - # Check every branch + # Check every branch; don't allow an empty union + if len(members) == 0: + raise QAPIExprError(expr_info, + "Union '%s' cannot have empty 'data'" % name) for (key, value) in members.items(): check_name(expr_info, "Member of union '%s'" % name, key) @@ -613,7 +616,11 @@ def check_alternate(expr, expr_info): members = expr['data'] types_seen = {} - # Check every branch + # Check every branch; require at least two branches + if len(members) < 2: + raise QAPIExprError(expr_info, + "Alternate '%s' should have at least two branches " + "in 'data'" % name) for (key, value) in members.items(): check_name(expr_info, "Member of alternate '%s'" % name, key) @@ -1059,6 +1066,7 @@ 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 diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb06c5bfec08a9b31324102c75790f2f05574319 100644 --- a/tests/qapi-schema/alternate-empty.err +++ b/tests/qapi-schema/alternate-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data' diff --git a/tests/qapi-schema/alternate-empty.exit b/tests/qapi-schema/alternate-empty.exit index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 --- a/tests/qapi-schema/alternate-empty.exit +++ b/tests/qapi-schema/alternate-empty.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json index db3820f841a5ebb8600acb5aaee7055b697f589f..fff15baf16c2ef48efc4619d21d4a3ded29e2325 100644 --- a/tests/qapi-schema/alternate-empty.json +++ b/tests/qapi-schema/alternate-empty.json @@ -1,2 +1,2 @@ -# FIXME - alternates should list at least two types to be useful +# alternates must list at least two types to be useful { 'alternate': 'Alt', 'data': { 'i': 'int' } } diff --git a/tests/qapi-schema/alternate-empty.out b/tests/qapi-schema/alternate-empty.out index f78f174111c18255a158ac2c58f9d495516b6b1c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/tests/qapi-schema/alternate-empty.out +++ b/tests/qapi-schema/alternate-empty.out @@ -1,5 +0,0 @@ -object :empty -alternate Alt - case i: int -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..15754f54eb9251724eaddb1dc98085fc941b781c 100644 --- a/tests/qapi-schema/flat-union-empty.err +++ b/tests/qapi-schema/flat-union-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data' diff --git a/tests/qapi-schema/flat-union-empty.exit b/tests/qapi-schema/flat-union-empty.exit index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 --- a/tests/qapi-schema/flat-union-empty.exit +++ b/tests/qapi-schema/flat-union-empty.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json index 67dd2978eb173ac639abb7c95306ebb1282a203d..77f1d9abfb8f9b39a0a9dd9a03be3cb4e4343c15 100644 --- a/tests/qapi-schema/flat-union-empty.json +++ b/tests/qapi-schema/flat-union-empty.json @@ -1,4 +1,4 @@ -# FIXME - flat unions should not be empty +# flat unions cannot be empty { 'enum': 'Empty', 'data': [ ] } { 'struct': 'Base', 'data': { 'type': 'Empty' } } { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } } diff --git a/tests/qapi-schema/flat-union-empty.out b/tests/qapi-schema/flat-union-empty.out index eade2d5ac6ec8e1c74d20d0ce58be97b65a3402f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/tests/qapi-schema/flat-union-empty.out +++ b/tests/qapi-schema/flat-union-empty.out @@ -1,9 +0,0 @@ -object :empty -object Base - member type: Empty optional=False -enum Empty [] -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE -object Union - base Base - tag type diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..12c20221bdfb6f7b046a7deaaf1074aa6126b651 100644 --- a/tests/qapi-schema/union-empty.err +++ b/tests/qapi-schema/union-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data' diff --git a/tests/qapi-schema/union-empty.exit b/tests/qapi-schema/union-empty.exit index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 --- a/tests/qapi-schema/union-empty.exit +++ b/tests/qapi-schema/union-empty.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json index 1785007113360147aa09969fce5351ecdfd4c7ac..1f0b13ca21ae25d34b9d67da84df14b88f35e959 100644 --- a/tests/qapi-schema/union-empty.json +++ b/tests/qapi-schema/union-empty.json @@ -1,2 +1,2 @@ -# FIXME - unions should not be empty +# unions cannot be empty { 'union': 'Union', 'data': { } } diff --git a/tests/qapi-schema/union-empty.out b/tests/qapi-schema/union-empty.out index bdf17e5b29500650723dc8c06f5341ad03640d28..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/tests/qapi-schema/union-empty.out +++ b/tests/qapi-schema/union-empty.out @@ -1,6 +0,0 @@ -object :empty -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE -object Union - member type: UnionKind optional=False -enum UnionKind []