Prevent an all-zero struct from having different meanings with different configurations or builds of QEMU.
This needs some changes to doc-good.json, which used unwittingly such an enum. Signed-off-by: Paolo Bonzini <[email protected]> --- scripts/qapi/schema.py | 8 ++++++++ tests/qapi-schema/doc-good.json | 16 ++++++++-------- tests/qapi-schema/doc-good.out | 12 ++++++------ tests/qapi-schema/doc-good.txt | 8 ++++---- tests/qapi-schema/enum-if-first-required.err | 2 ++ tests/qapi-schema/enum-if-first-required.json | 6 ++++++ tests/qapi-schema/enum-if-first-required.out | 0 tests/qapi-schema/meson.build | 1 + 8 files changed, 35 insertions(+), 18 deletions(-) create mode 100644 tests/qapi-schema/enum-if-first-required.err create mode 100644 tests/qapi-schema/enum-if-first-required.json create mode 100644 tests/qapi-schema/enum-if-first-required.out diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 78c2a25fc9a..a5a11298817 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -967,6 +967,14 @@ def check(self, schema: QAPISchema) -> None: assert self.defined_in self.type = schema.resolve_type(self._type_name, self.info, self.describe) + if (not self.optional + and isinstance(self.type, QAPISchemaEnumType) + and self.type.members[0].ifcond.is_present()): + raise QAPISemError( + self.info, + "enum type '%s' of %s has a conditional first value" + " and must be optional" + % (self.type.name, self.describe(self.info))) seen: Dict[str, QAPISchemaMember] = {} for f in self.features: f.check_clash(self.info, seen) diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index fac13425b72..76521ffe9e6 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -73,12 +73,12 @@ # @enum-feat: Also _one_ {and only} # @enum-member-feat: a member feature # -# @two is undocumented +# @zero is undocumented ## { 'enum': 'Enum', - 'data': [ { 'name': 'one', 'if': 'IFONE', - 'features': [ 'enum-member-feat' ] }, - 'two' ], + 'data': [ 'zero', + { 'name': 'one', 'if': 'IFONE', + 'features': [ 'enum-member-feat' ] } ], 'features': [ 'enum-feat' ], 'if': 'IFCOND' } @@ -112,10 +112,10 @@ 'if': 'IFSTR' } } } ## -# @Variant2: +# @Variant0: # ## -{ 'struct': 'Variant2', 'data': {} } +{ 'struct': 'Variant0', 'data': {} } ## # @Object: @@ -128,8 +128,8 @@ 'base': 'Base', 'discriminator': 'base1', 'data': { 'one': 'Variant1', - 'two': { 'type': 'Variant2', - 'if': { 'any': ['IFONE', 'IFTWO'] } } } } + 'zero': { 'type': 'Variant0', + 'if': { 'any': ['IFONE', 'IFTWO'] } } } } ## # @Alternate: diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 04a55072646..bf589061cbc 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -10,10 +10,10 @@ enum QType member qbool module doc-good.json enum Enum + member zero member one if IFONE feature enum-member-feat - member two if IFCOND feature enum-feat object Base @@ -24,12 +24,12 @@ object Variant1 if IFSTR feature member-feat feature variant1-feat -object Variant2 +object Variant0 object Object base Base tag base1 case one: Variant1 - case two: Variant2 + case zero: Variant0 if {'any': ['IFONE', 'IFTWO']} feature union-feat1 alternate Alternate @@ -110,14 +110,14 @@ doc symbol=Enum arg=one The _one_ {and only}, description on the same line - arg=two + arg=zero feature=enum-feat Also _one_ {and only} feature=enum-member-feat a member feature section=Plain -@two is undocumented +@zero is undocumented doc symbol=Base body= @@ -137,7 +137,7 @@ Another paragraph a feature feature=member-feat a member feature -doc symbol=Variant2 +doc symbol=Variant0 body= doc symbol=Object diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt index 74b73681d32..922a61dcf23 100644 --- a/tests/qapi-schema/doc-good.txt +++ b/tests/qapi-schema/doc-good.txt @@ -43,14 +43,14 @@ Enum Enum Values: * **one** -- The _one_ {and only}, description on the same line - * **two** -- Not documented + * **zero** -- Not documented Features: * **enum-feat** -- Also _one_ {and only} * **enum-member-feat** -- a member feature - "two" is undocumented + "zero" is undocumented Object Base *Availability*: "IFALL1 and IFALL2" @@ -75,7 +75,7 @@ Object Variant1 * **member-feat** -- a member feature -Object Variant2 +Object Variant0 Object Object @@ -84,7 +84,7 @@ Object Object * When "base1" is "one": The members of "Variant1". - * When "base1" is "two": The members of "Variant2". + * When "base1" is "zero": The members of "Variant0". Features: * **union-feat1** -- a feature diff --git a/tests/qapi-schema/enum-if-first-required.err b/tests/qapi-schema/enum-if-first-required.err new file mode 100644 index 00000000000..6d8bdcf2507 --- /dev/null +++ b/tests/qapi-schema/enum-if-first-required.err @@ -0,0 +1,2 @@ +enum-if-first-required.json: In struct 'TestStruct': +enum-if-first-required.json:5: enum type 'TestEnum' of member 'field' has a conditional first value and must be optional diff --git a/tests/qapi-schema/enum-if-first-required.json b/tests/qapi-schema/enum-if-first-required.json new file mode 100644 index 00000000000..1769b5fdef9 --- /dev/null +++ b/tests/qapi-schema/enum-if-first-required.json @@ -0,0 +1,6 @@ +# Enum with conditional first value cannot be used in required fields +{ 'enum': 'TestEnum', + 'data': [ { 'name': 'member1', 'if': 'CONFIG_FOO' }, + 'member2' ] } +{ 'struct': 'TestStruct', + 'data': { 'field': 'TestEnum' } } diff --git a/tests/qapi-schema/enum-if-first-required.out b/tests/qapi-schema/enum-if-first-required.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index debff633ac1..3b0c16a8b67 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -97,6 +97,7 @@ schemas = [ 'enum-bad-prefix.json', 'enum-clash-member.json', 'enum-dict-member-unknown.json', + 'enum-if-first-required.json', 'enum-if-invalid.json', 'enum-int-member.json', 'enum-member-case.json', -- 2.54.0
