]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/qemu-xen.git/commitdiff
qapi: Avoid assertion failure on union 'type' collision
authorEric Blake <eblake@redhat.com>
Tue, 29 Sep 2015 22:21:04 +0000 (16:21 -0600)
committerMarkus Armbruster <armbru@redhat.com>
Mon, 12 Oct 2015 16:44:54 +0000 (18:44 +0200)
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: Eric Blake <eblake@redhat.com>
Message-Id: <1443565276-4535-7-git-send-email-eblake@redhat.com>
[Polished a few comments]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
scripts/qapi.py
tests/qapi-schema/flat-union-clash-type.err
tests/qapi-schema/flat-union-clash-type.json
tests/qapi-schema/union-clash-type.err
tests/qapi-schema/union-clash-type.json

index 4b5d574e0d62bbb4ebdf162bb14532938f12a9eb..8d2681b24bb79432da9337de20465fb4468a21b2 100644 (file)
@@ -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:
index 6e64d1d81953af7c81c93aa59ac1ddb76ca24aea..b44dd4005c9974181d7ea40183ac136b2bac2185 100644 (file)
@@ -1,16 +1 @@
-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'
index 3db6ea07a8d815b1900003ae6c6778a7dd1e4428..8f710f08aa870056e8e77172df42f4a4650d4318 100644 (file)
@@ -1,9 +1,7 @@
 # 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',
index 6e64d1d81953af7c81c93aa59ac1ddb76ca24aea..a5dead128d578dc85fcd87e3cf9fd0fccb0b676e 100644 (file)
@@ -1,16 +1 @@
-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)'
index 52c21f77ea67c160cc179bc1c5efd33b1fefcef8..cfc256b04d39e87527a6cb39407bf67a3f6cdc8f 100644 (file)
@@ -1,10 +1,9 @@
 # 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' } }