mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 01:55:33 +00:00
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. Backports commit 800877bb1639d38ffaebe312a37b61c66bb10c83 from qemu
This commit is contained in:
parent
6069bb69a7
commit
559833a0d4
|
@ -791,13 +791,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']
|
||||
|
@ -1367,6 +1360,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
|
||||
|
|
|
@ -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;
|
||||
''',
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue