aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorAnton Nefedov <anton.nefedov@virtuozzo.com>2018-06-18 11:40:05 +0300
committerMarkus Armbruster <armbru@redhat.com>2018-06-22 16:33:46 +0200
commit800877bb1639d38ffaebe312a37b61c66bb10c83 (patch)
tree766371f9d2bb317d702ed6c4317d9ae75a0bd67f /scripts
parentfe170d8bfaa12d63117cad8707ac18c3b2f3bb8e (diff)
qapi: allow empty branches in flat unions
It often happens that just a few discriminator values imply extra data in a flat union. Existing checks did not make possible to leave other values uncovered. Such cases had to be worked around by either stating a dummy (empty) type or introducing another (subset) discriminator enumeration. Both options create redundant entities in qapi files for little profit. With this patch it is not necessary anymore to add designated union fields for every possible value of a discriminator enumeration. Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com> Message-Id: <1529311206-76847-2-git-send-email-anton.nefedov@virtuozzo.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/qapi/common.py15
-rw-r--r--scripts/qapi/types.py2
-rw-r--r--scripts/qapi/visit.py19
3 files changed, 24 insertions, 12 deletions
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 2462fc0291..4b53f08627 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -779,13 +779,6 @@ def check_union(expr, info):
"enum '%s'"
% (key, enum_define['enum']))
- # If discriminator is user-defined, ensure all values are covered
- if enum_define:
- for value in enum_define['data']:
- if value not in members.keys():
- raise QAPISemError(info, "Union '%s' data missing '%s' branch"
- % (name, value))
-
def check_alternate(expr, info):
name = expr['alternate']
@@ -1357,6 +1350,14 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = seen[c_name(self._tag_name)]
assert self._tag_name == self.tag_member.name
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
+ if self._tag_name: # flat union
+ # branches that are not explicitly covered get an empty type
+ cases = set([v.name for v in self.variants])
+ for val in self.tag_member.type.values:
+ if val.name not in cases:
+ v = QAPISchemaObjectTypeVariant(val.name, 'q_empty')
+ v.set_owner(self.tag_member.owner)
+ self.variants.append(v)
for v in self.variants:
v.check(schema)
# Union names must match enum values; alternate names are
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 64d9c0fb37..a599352e59 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -125,6 +125,8 @@ def gen_variants(variants):
c_name=c_name(variants.tag_member.name))
for var in variants.variants:
+ if var.type.name == 'q_empty':
+ continue
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 3c5ea1289e..bdcafb64ee 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -81,15 +81,24 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
c_name=c_name(variants.tag_member.name))
for var in variants.variants:
- ret += mcgen('''
+ case_str = c_enum_const(variants.tag_member.type.name,
+ var.name,
+ variants.tag_member.type.prefix)
+ if var.type.name == 'q_empty':
+ # valid variant and nothing to do
+ ret += mcgen('''
+ case %(case)s:
+ break;
+''',
+ case=case_str)
+ else:
+ ret += mcgen('''
case %(case)s:
visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err);
break;
''',
- case=c_enum_const(variants.tag_member.type.name,
- var.name,
- variants.tag_member.type.prefix),
- c_type=var.type.c_name(), c_name=c_name(var.name))
+ case=case_str,
+ c_type=var.type.c_name(), c_name=c_name(var.name))
ret += mcgen('''
default: