aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/qapi.py19
-rw-r--r--tests/Makefile.include2
-rw-r--r--tests/qapi-schema/alternate-conflict-dict.json2
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-bool.err1
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-bool.exit1
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-bool.json6
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-bool.out0
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-int.err1
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-int.exit1
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-int.json6
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-int.out0
-rw-r--r--tests/qapi-schema/alternate-conflict-string.err2
-rw-r--r--tests/qapi-schema/alternate-conflict-string.json6
-rw-r--r--tests/qapi-schema/qapi-schema-test.json4
-rw-r--r--tests/qapi-schema/qapi-schema-test.out4
-rw-r--r--tests/test-keyval.c18
-rw-r--r--util/keyval.c10
17 files changed, 60 insertions, 23 deletions
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6c4d554165..b7a25e4759 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -812,11 +812,26 @@ def check_alternate(expr, info):
if not qtype:
raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
"type '%s'" % (name, key, value))
- if qtype in types_seen:
+ conflicting = set([qtype])
+ if qtype == 'QTYPE_QSTRING':
+ enum_expr = enum_types.get(value)
+ if enum_expr:
+ for v in enum_expr['data']:
+ if v in ['on', 'off']:
+ conflicting.add('QTYPE_QBOOL')
+ if re.match(r'[-+0-9.]', v): # lazy, could be tightened
+ conflicting.add('QTYPE_QINT')
+ conflicting.add('QTYPE_QFLOAT')
+ else:
+ conflicting.add('QTYPE_QINT')
+ conflicting.add('QTYPE_QFLOAT')
+ conflicting.add('QTYPE_QBOOL')
+ if conflicting & set(types_seen):
raise QAPISemError(info, "Alternate '%s' member '%s' can't "
"be distinguished from member '%s'"
% (name, key, types_seen[qtype]))
- types_seen[qtype] = key
+ for qt in conflicting:
+ types_seen[qt] = key
def check_enum(expr, info):
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 75893838e5..f42f3dfa72 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -342,6 +342,8 @@ qapi-schema += alternate-array.json
qapi-schema += alternate-base.json
qapi-schema += alternate-clash.json
qapi-schema += alternate-conflict-dict.json
+qapi-schema += alternate-conflict-enum-bool.json
+qapi-schema += alternate-conflict-enum-int.json
qapi-schema += alternate-conflict-string.json
qapi-schema += alternate-empty.json
qapi-schema += alternate-nested.json
diff --git a/tests/qapi-schema/alternate-conflict-dict.json b/tests/qapi-schema/alternate-conflict-dict.json
index d566cca816..3d7881279c 100644
--- a/tests/qapi-schema/alternate-conflict-dict.json
+++ b/tests/qapi-schema/alternate-conflict-dict.json
@@ -1,4 +1,4 @@
-# we reject alternates with multiple object branches
+# alternate branches of object type conflict with each other
{ 'struct': 'One',
'data': { 'name': 'str' } }
{ 'struct': 'Two',
diff --git a/tests/qapi-schema/alternate-conflict-enum-bool.err b/tests/qapi-schema/alternate-conflict-enum-bool.err
new file mode 100644
index 0000000000..0dfc00242d
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-bool.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-conflict-enum-bool.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-enum-bool.exit b/tests/qapi-schema/alternate-conflict-enum-bool.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-bool.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-conflict-enum-bool.json b/tests/qapi-schema/alternate-conflict-enum-bool.json
new file mode 100644
index 0000000000..bff25c3147
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-bool.json
@@ -0,0 +1,6 @@
+# alternate branch of 'enum' type that conflicts with bool
+{ 'enum': 'Enum',
+ 'data': [ 'aus', 'off' ] }
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'Enum',
+ 'two': 'bool' } }
diff --git a/tests/qapi-schema/alternate-conflict-enum-bool.out b/tests/qapi-schema/alternate-conflict-enum-bool.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-bool.out
diff --git a/tests/qapi-schema/alternate-conflict-enum-int.err b/tests/qapi-schema/alternate-conflict-enum-int.err
new file mode 100644
index 0000000000..2cc8e7b9aa
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-int.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-conflict-enum-int.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-enum-int.exit b/tests/qapi-schema/alternate-conflict-enum-int.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-int.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-conflict-enum-int.json b/tests/qapi-schema/alternate-conflict-enum-int.json
new file mode 100644
index 0000000000..beb428c10b
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-int.json
@@ -0,0 +1,6 @@
+# alternate branches of 'enum' type that conflicts with numbers
+{ 'enum': 'Enum',
+ 'data': [ '1', '2', '3' ] }
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'Enum',
+ 'two': 'int' } }
diff --git a/tests/qapi-schema/alternate-conflict-enum-int.out b/tests/qapi-schema/alternate-conflict-enum-int.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/alternate-conflict-enum-int.out
diff --git a/tests/qapi-schema/alternate-conflict-string.err b/tests/qapi-schema/alternate-conflict-string.err
index fc523b0879..fe2f188295 100644
--- a/tests/qapi-schema/alternate-conflict-string.err
+++ b/tests/qapi-schema/alternate-conflict-string.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-string.json b/tests/qapi-schema/alternate-conflict-string.json
index 72f04a820a..85adbd4adc 100644
--- a/tests/qapi-schema/alternate-conflict-string.json
+++ b/tests/qapi-schema/alternate-conflict-string.json
@@ -1,6 +1,4 @@
-# we reject alternates with multiple string-like branches
-{ 'enum': 'Enum',
- 'data': [ 'hello', 'world' ] }
+# alternate branches of 'str' type conflict with all scalar types
{ 'alternate': 'Alt',
'data': { 'one': 'str',
- 'two': 'Enum' } }
+ 'two': 'int' } }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 303f2b23cd..17649c6398 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -101,12 +101,14 @@
# for testing use of 'number' within alternates
{ 'alternate': 'AltEnumBool', 'data': { 'e': 'EnumOne', 'b': 'bool' } }
{ 'alternate': 'AltEnumNum', 'data': { 'e': 'EnumOne', 'n': 'number' } }
-{ 'alternate': 'AltNumStr', 'data': { 'n': 'number', 's': 'str' } }
{ 'alternate': 'AltNumEnum', 'data': { 'n': 'number', 'e': 'EnumOne' } }
{ 'alternate': 'AltEnumInt', 'data': { 'e': 'EnumOne', 'i': 'int' } }
{ 'alternate': 'AltIntNum', 'data': { 'i': 'int', 'n': 'number' } }
{ 'alternate': 'AltNumInt', 'data': { 'n': 'number', 'i': 'int' } }
+# for testing use of 'str' within alternates
+{ 'alternate': 'AltStrObj', 'data': { 's': 'str', 'o': 'TestStruct' } }
+
# for testing native lists
{ 'union': 'UserDefNativeListUnion',
'data': { 'integer': ['int'],
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 3081091818..9f68610dc2 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -22,10 +22,10 @@ alternate AltNumInt
tag type
case n: number
case i: int
-alternate AltNumStr
+alternate AltStrObj
tag type
- case n: number
case s: str
+ case o: TestStruct
event EVENT_A None
boxed=False
event EVENT_B None
diff --git a/tests/test-keyval.c b/tests/test-keyval.c
index c556b1b117..c3be00524c 100644
--- a/tests/test-keyval.c
+++ b/tests/test-keyval.c
@@ -614,22 +614,26 @@ static void test_keyval_visit_alternate(void)
Error *err = NULL;
Visitor *v;
QDict *qdict;
- AltNumStr *ans;
+ AltStrObj *aso;
AltNumInt *ani;
+ AltEnumBool *aeb;
/*
* Can't do scalar alternate variants other than string. You get
* the string variant if there is one, else an error.
+ * TODO make it work for unambiguous cases like AltEnumBool below
*/
- qdict = keyval_parse("a=1,b=2", NULL, &error_abort);
+ qdict = keyval_parse("a=1,b=2,c=on", NULL, &error_abort);
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
QDECREF(qdict);
visit_start_struct(v, NULL, NULL, 0, &error_abort);
- visit_type_AltNumStr(v, "a", &ans, &error_abort);
- g_assert_cmpint(ans->type, ==, QTYPE_QSTRING);
- g_assert_cmpstr(ans->u.s, ==, "1");
- qapi_free_AltNumStr(ans);
- visit_type_AltNumInt(v, "a", &ani, &err);
+ visit_type_AltStrObj(v, "a", &aso, &error_abort);
+ g_assert_cmpint(aso->type, ==, QTYPE_QSTRING);
+ g_assert_cmpstr(aso->u.s, ==, "1");
+ qapi_free_AltStrObj(aso);
+ visit_type_AltNumInt(v, "b", &ani, &err);
+ error_free_or_abort(&err);
+ visit_type_AltEnumBool(v, "c", &aeb, &err);
error_free_or_abort(&err);
visit_end_struct(v, NULL);
visit_free(v);
diff --git a/util/keyval.c b/util/keyval.c
index 93d5db6b59..7dbda62305 100644
--- a/util/keyval.c
+++ b/util/keyval.c
@@ -65,11 +65,11 @@
* denote numbers, true, false or null. The special QObject input
* visitor returned by qobject_input_visitor_new_keyval() mostly hides
* this by automatically converting strings to the type the visitor
- * expects. Breaks down for alternate types and type 'any', where the
- * visitor's expectation isn't clear. Code visiting such types needs
- * to do the conversion itself, but only when using this keyval
- * visitor. Awkward. Alternate types without a string member don't
- * work at all.
+ * expects. Breaks down for type 'any', where the visitor's
+ * expectation isn't clear. Code visiting 'any' needs to do the
+ * conversion itself, but only when using this keyval visitor.
+ * Awkward. Note that we carefully restrict alternate types to avoid
+ * similar ambiguity.
*
* Additional syntax for use with an implied key:
*