提交 7b2a5c2f 编写于 作者: E Eric Blake 提交者: Markus Armbruster

qapi: Avoid assertion failure on union 'type' collision

The previous commit added two tests that triggered an assertion
failure. It's fairly straightforward to avoid the failure by
just outright forbidding the collision between a union's tag
values and its discriminator name (including the implicit name
'kind' supplied for simple unions [*]).  Ultimately, we'd like
to move the collision detection into QAPISchema*.check(), but
for now it is easier just to enhance the existing checks.

[*] Of course, down the road, we have plans to rename the simple
union tag name to 'type' to match the QMP wire name, but the
idea of the collision will still be present even then.

Technically, we could avoid the collision by naming the C union
members representing each enum value as '_case_value' rather
than 'value'; but until we have an actual qapi client (and not
just our testsuite) that has a legitimate reason to match a
case label to the name of a QMP key and needs the name munging
to satisfy the compiler, it's easier to just reject the qapi
as invalid.
Signed-off-by: NEric Blake <eblake@redhat.com>
Message-Id: <1443565276-4535-7-git-send-email-eblake@redhat.com>
[Polished a few comments]
Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
上级 d220fbcd
......@@ -544,7 +544,7 @@ def check_union(expr, expr_info):
base = expr.get('base')
discriminator = expr.get('discriminator')
members = expr['data']
values = {'MAX': '(automatic)'}
values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
# Two types of unions, determined by discriminator.
......@@ -603,13 +603,19 @@ def check_union(expr, expr_info):
" of branch '%s'" % key)
# If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type.
# of 'data' must also be members of the enum type, which in turn
# must not collide with the discriminator name.
if enum_define:
if key not in enum_define['enum_values']:
raise QAPIExprError(expr_info,
"Discriminator value '%s' is not found in "
"enum '%s'" %
(key, enum_define["enum_name"]))
if discriminator in enum_define['enum_values']:
raise QAPIExprError(expr_info,
"Discriminator name '%s' collides with "
"enum value in '%s'" %
(discriminator, enum_define["enum_name"]))
# Otherwise, check for conflicts in the generated enum
else:
......
Traceback (most recent call last):
File "tests/qapi-schema/test-qapi.py", line 55, in <module>
schema = QAPISchema(sys.argv[1])
File "scripts/qapi.py", line 1116, in __init__
self.check()
File "scripts/qapi.py", line 1299, in check
ent.check(self)
File "scripts/qapi.py", line 962, in check
self.variants.check(schema, members, seen)
File "scripts/qapi.py", line 1024, in check
v.check(schema, self.tag_member.type, vseen)
File "scripts/qapi.py", line 1032, in check
QAPISchemaObjectTypeMember.check(self, schema, [], seen)
File "scripts/qapi.py", line 994, in check
assert self.name not in seen
AssertionError
tests/qapi-schema/flat-union-clash-type.json:11: Discriminator name 'type' collides with enum value in 'TestEnum'
# Flat union branch 'type'
# FIXME: this triggers an assertion failure. But even with that fixed,
# we would have a clash in generated C, between the member 'type'
# inherited from 'Base' and the branch name 'type' within the
# union. We should either reject this, or munge the generated C to let
# it compile.
# Reject this, because we would have a clash in generated C, between the
# outer tag 'type' and the branch name 'type' within the union.
# TODO: We could munge the generated C branch name to let it compile.
{ 'enum': 'TestEnum',
'data': [ 'type' ] }
{ 'struct': 'Base',
......
Traceback (most recent call last):
File "tests/qapi-schema/test-qapi.py", line 55, in <module>
schema = QAPISchema(sys.argv[1])
File "scripts/qapi.py", line 1116, in __init__
self.check()
File "scripts/qapi.py", line 1299, in check
ent.check(self)
File "scripts/qapi.py", line 962, in check
self.variants.check(schema, members, seen)
File "scripts/qapi.py", line 1024, in check
v.check(schema, self.tag_member.type, vseen)
File "scripts/qapi.py", line 1032, in check
QAPISchemaObjectTypeMember.check(self, schema, [], seen)
File "scripts/qapi.py", line 994, in check
assert self.name not in seen
AssertionError
tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'kind' clashes with '(automatic)'
# Union branch 'type'
# FIXME: this triggers an assertion failure. But even with that fixed,
# we would have a clash in generated C, between the simple union's
# implicit tag member 'kind' and the branch name 'kind' within the
# union. We should either reject this, or munge the generated C to let
# it compile.
# Reject this, because we would have a clash in generated C, between the
# simple union's implicit tag member 'kind' and the branch name 'kind'
# within the union.
# TODO: Even when the generated C is switched to use 'type' rather than
# 'kind', to match the QMP spelling, the collision should still be detected.
# Or, we could munge the branch name to allow compilation.
{ 'union': 'TestUnion',
'data': { 'kind': 'int', 'type': 'str' } }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册