* [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17
@ 2015-12-17 8:33 Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 01/40] qapi: Track simple union tag in object.local_members Markus Armbruster
` (40 more replies)
0 siblings, 41 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
The following changes since commit a8c40fa2d667e585382080db36ac44e216b37a1c:
Update version for v2.5.0 release (2015-12-16 16:10:14 +0000)
are available in the git repository at:
git://repo.or.cz/qemu/armbru.git tags/pull-qapi-2015-12-17
for you to fetch changes up to bac5429ccb4f41d421ec641b11f1852c8420fdb7:
qapi: Detect base class loops (2015-12-17 08:21:29 +0100)
----------------------------------------------------------------
QAPI patches for 2015-12-17
----------------------------------------------------------------
Eric Blake (33):
qapi: Track simple union tag in object.local_members
qapi-types: Consolidate gen_struct() and gen_union()
qapi-types: Simplify gen_struct_field[s]
qapi: Check for QAPI collisions involving variant members
qapi: Factor out QAPISchemaObjectType.check_clash()
qapi: Hoist tag collision check to Variants.check()
qapi: Remove outdated tests related to QMP/branch collisions
qapi: Track owner of each object member
qapi: Detect collisions in C member names
qapi: Fix c_name() munging
qapi: Remove dead visitor code
blkdebug: Merge hand-rolled and qapi BlkdebugEvent enum
blkdebug: Avoid '.' in enum values
qapi: Tighten the regex on valid names
qapi: Don't let implicit enum MAX member collide
qapi: Remove obsolete tests for MAX collision
cpu: Convert CpuInfo into flat union
qapi: Add alias for ErrorClass
qapi: Change munging of CamelCase enum values
qobject: Simplify QObject
qobject: Rename qtype_code to QType
qapi: Convert QType into QAPI built-in enum type
qapi: Simplify visiting of alternate types
qapi-types: Drop unnedeed ._fwdefn
qapi: Inline _make_implicit_tag()
qapi: Fix alternates that accept 'number' but not 'int'
qapi: Simplify visits of optional fields
qapi: Shorter visits of optional fields
qapi: Prepare new QAPISchemaMember base class
qapi: Track enum values by QAPISchemaMember, not string
qapi: Enforce (or whitelist) case conventions on qapi members
qapi: Move duplicate collision checks to schema check()
qapi: Detect base class loops
Markus Armbruster (7):
qapi: Drop obsolete tag value collision assertions
qapi: Simplify QAPISchemaObjectTypeMember.check()
qapi: Clean up after previous commit
qapi: Fix up commit 7618b91's clash sanity checking change
qapi: Eliminate QAPISchemaObjectType.check() variable members
qapi: Factor out QAPISchemaObjectTypeMember.check_clash()
qapi: Simplify QAPISchemaObjectTypeVariants.check()
block.c | 2 +-
block/blkdebug.c | 79 +-----
block/parallels.c | 4 +-
block/qapi.c | 4 +-
block/qcow2.c | 2 +-
block/quorum.c | 2 +-
block/raw-posix.c | 2 +-
blockdev.c | 2 +-
cpus.c | 31 ++-
docs/blkdebug.txt | 7 +-
docs/qapi-code-gen.txt | 30 +--
hmp.c | 44 +--
hw/char/escc.c | 2 +-
hw/i386/pc_piix.c | 2 +-
hw/i386/pc_q35.c | 2 +-
hw/input/hid.c | 6 +-
hw/input/ps2.c | 6 +-
hw/input/virtio-input-hid.c | 12 +-
include/block/block.h | 62 +----
include/block/block_int.h | 2 +-
include/hw/qdev-core.h | 2 +-
include/migration/migration.h | 4 +-
include/qapi/error.h | 14 +
include/qapi/qmp/qbool.h | 1 +
include/qapi/qmp/qdict.h | 1 +
include/qapi/qmp/qfloat.h | 1 +
include/qapi/qmp/qint.h | 1 +
include/qapi/qmp/qlist.h | 1 +
include/qapi/qmp/qobject.h | 50 ++--
include/qapi/qmp/qstring.h | 1 +
include/qapi/visitor-impl.h | 8 +-
include/qapi/visitor.h | 22 +-
include/qemu/typedefs.h | 1 +
migration/migration.c | 4 +-
monitor.c | 18 +-
net/net.c | 4 +-
qapi-schema.json | 120 +++++++--
qapi/block-core.json | 20 +-
qapi/common.json | 5 +-
qapi/opts-visitor.c | 2 +-
qapi/qapi-visit-core.c | 10 +-
qapi/qmp-dispatch.c | 2 +-
qapi/qmp-input-visitor.c | 10 +-
qapi/string-input-visitor.c | 3 +-
qemu-nbd.c | 2 +-
qmp-commands.hx | 4 +
qobject/Makefile.objs | 2 +-
qobject/qbool.c | 11 +-
qobject/qdict.c | 14 +-
qobject/qfloat.c | 11 +-
qobject/qint.c | 11 +-
qobject/qlist.c | 11 +-
qobject/qnull.c | 12 +-
qobject/qobject.c | 34 +++
qobject/qstring.c | 11 +-
replay/replay-input.c | 8 +-
scripts/qapi-types.py | 120 +++------
scripts/qapi-visit.py | 36 ++-
scripts/qapi.py | 295 ++++++++++++---------
tests/Makefile | 14 +-
tests/qapi-schema/alternate-clash.err | 2 +-
tests/qapi-schema/alternate-empty.out | 3 +-
tests/qapi-schema/args-member-case.err | 1 +
.../{union-max.exit => args-member-case.exit} | 0
tests/qapi-schema/args-member-case.json | 2 +
.../{union-max.out => args-member-case.out} | 0
tests/qapi-schema/args-name-clash.err | 1 +
tests/qapi-schema/args-name-clash.exit | 2 +-
tests/qapi-schema/args-name-clash.json | 5 +-
tests/qapi-schema/args-name-clash.out | 6 -
tests/qapi-schema/base-cycle-direct.err | 1 +
...nion-clash-type.exit => base-cycle-direct.exit} | 0
tests/qapi-schema/base-cycle-direct.json | 2 +
...{union-clash-type.out => base-cycle-direct.out} | 0
tests/qapi-schema/base-cycle-indirect.err | 1 +
...on-bad-branch.exit => base-cycle-indirect.exit} | 0
tests/qapi-schema/base-cycle-indirect.json | 3 +
...nion-bad-branch.out => base-cycle-indirect.out} | 0
tests/qapi-schema/comments.out | 2 +
tests/qapi-schema/empty.out | 2 +
tests/qapi-schema/enum-clash-member.err | 2 +-
tests/qapi-schema/enum-clash-member.json | 2 +-
tests/qapi-schema/enum-max-member.err | 1 -
tests/qapi-schema/enum-max-member.json | 3 -
tests/qapi-schema/enum-member-case.err | 1 +
...union-clash-type.exit => enum-member-case.exit} | 0
tests/qapi-schema/enum-member-case.json | 3 +
...t-union-clash-type.out => enum-member-case.out} | 0
tests/qapi-schema/event-case.out | 2 +
tests/qapi-schema/event-max.err | 1 -
tests/qapi-schema/event-max.json | 2 -
tests/qapi-schema/flat-union-clash-branch.exit | 1 -
tests/qapi-schema/flat-union-clash-branch.json | 18 --
tests/qapi-schema/flat-union-clash-branch.out | 14 -
tests/qapi-schema/flat-union-clash-member.err | 2 +-
tests/qapi-schema/flat-union-clash-type.err | 1 -
tests/qapi-schema/flat-union-clash-type.json | 14 -
tests/qapi-schema/flat-union-empty.out | 2 +
tests/qapi-schema/ident-with-escape.out | 2 +
tests/qapi-schema/include-relpath.out | 2 +
tests/qapi-schema/include-repetition.out | 2 +
tests/qapi-schema/include-simple.out | 2 +
tests/qapi-schema/indented-expr.out | 2 +
tests/qapi-schema/qapi-schema-test.json | 5 +-
tests/qapi-schema/qapi-schema-test.out | 13 +-
tests/qapi-schema/reserved-enum-q.err | 1 +
.../{event-max.exit => reserved-enum-q.exit} | 0
tests/qapi-schema/reserved-enum-q.json | 4 +
...-union-clash-branch.err => reserved-enum-q.out} | 0
tests/qapi-schema/reserved-member-underscore.err | 1 +
...member.exit => reserved-member-underscore.exit} | 0
tests/qapi-schema/reserved-member-underscore.json | 4 +
...vent-max.out => reserved-member-underscore.out} | 0
tests/qapi-schema/struct-base-clash-deep.err | 2 +-
tests/qapi-schema/struct-base-clash.err | 2 +-
tests/qapi-schema/union-bad-branch.err | 1 -
tests/qapi-schema/union-bad-branch.json | 8 -
tests/qapi-schema/union-branch-case.err | 1 +
tests/qapi-schema/union-branch-case.exit | 1 +
tests/qapi-schema/union-branch-case.json | 2 +
.../{enum-max-member.out => union-branch-case.out} | 0
tests/qapi-schema/union-clash-branches.err | 2 +-
tests/qapi-schema/union-clash-branches.json | 2 +-
tests/qapi-schema/union-clash-data.out | 3 +
tests/qapi-schema/union-clash-type.err | 1 -
tests/qapi-schema/union-clash-type.json | 9 -
tests/qapi-schema/union-empty.out | 3 +
tests/qapi-schema/union-max.err | 1 -
tests/qapi-schema/union-max.json | 3 -
tests/qemu-iotests/026 | 18 +-
tests/qemu-iotests/026.out | 80 +++---
tests/qemu-iotests/026.out.nocache | 80 +++---
tests/qemu-iotests/077 | 24 +-
tests/test-qmp-commands.c | 4 +
tests/test-qmp-input-visitor.c | 29 +-
tests/test-qmp-output-visitor.c | 10 +-
tests/test-string-output-visitor.c | 4 +-
tpm.c | 10 +-
ui/cocoa.m | 6 +-
ui/console.c | 2 +-
ui/gtk.c | 4 +-
ui/input-keymap.c | 4 +-
ui/input-legacy.c | 10 +-
ui/input.c | 6 +-
ui/sdl.c | 6 +-
ui/sdl2.c | 6 +-
ui/spice-input.c | 6 +-
ui/vnc.c | 6 +-
vl.c | 18 +-
149 files changed, 843 insertions(+), 875 deletions(-)
create mode 100644 qobject/qobject.c
create mode 100644 tests/qapi-schema/args-member-case.err
rename tests/qapi-schema/{union-max.exit => args-member-case.exit} (100%)
create mode 100644 tests/qapi-schema/args-member-case.json
rename tests/qapi-schema/{union-max.out => args-member-case.out} (100%)
create mode 100644 tests/qapi-schema/base-cycle-direct.err
rename tests/qapi-schema/{union-clash-type.exit => base-cycle-direct.exit} (100%)
create mode 100644 tests/qapi-schema/base-cycle-direct.json
rename tests/qapi-schema/{union-clash-type.out => base-cycle-direct.out} (100%)
create mode 100644 tests/qapi-schema/base-cycle-indirect.err
rename tests/qapi-schema/{union-bad-branch.exit => base-cycle-indirect.exit} (100%)
create mode 100644 tests/qapi-schema/base-cycle-indirect.json
rename tests/qapi-schema/{union-bad-branch.out => base-cycle-indirect.out} (100%)
delete mode 100644 tests/qapi-schema/enum-max-member.err
delete mode 100644 tests/qapi-schema/enum-max-member.json
create mode 100644 tests/qapi-schema/enum-member-case.err
rename tests/qapi-schema/{flat-union-clash-type.exit => enum-member-case.exit} (100%)
create mode 100644 tests/qapi-schema/enum-member-case.json
rename tests/qapi-schema/{flat-union-clash-type.out => enum-member-case.out} (100%)
delete mode 100644 tests/qapi-schema/event-max.err
delete mode 100644 tests/qapi-schema/event-max.json
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.exit
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.json
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.out
delete mode 100644 tests/qapi-schema/flat-union-clash-type.err
delete mode 100644 tests/qapi-schema/flat-union-clash-type.json
create mode 100644 tests/qapi-schema/reserved-enum-q.err
rename tests/qapi-schema/{event-max.exit => reserved-enum-q.exit} (100%)
create mode 100644 tests/qapi-schema/reserved-enum-q.json
rename tests/qapi-schema/{flat-union-clash-branch.err => reserved-enum-q.out} (100%)
create mode 100644 tests/qapi-schema/reserved-member-underscore.err
rename tests/qapi-schema/{enum-max-member.exit => reserved-member-underscore.exit} (100%)
create mode 100644 tests/qapi-schema/reserved-member-underscore.json
rename tests/qapi-schema/{event-max.out => reserved-member-underscore.out} (100%)
delete mode 100644 tests/qapi-schema/union-bad-branch.err
delete mode 100644 tests/qapi-schema/union-bad-branch.json
create mode 100644 tests/qapi-schema/union-branch-case.err
create mode 100644 tests/qapi-schema/union-branch-case.exit
create mode 100644 tests/qapi-schema/union-branch-case.json
rename tests/qapi-schema/{enum-max-member.out => union-branch-case.out} (100%)
delete mode 100644 tests/qapi-schema/union-clash-type.err
delete mode 100644 tests/qapi-schema/union-clash-type.json
delete mode 100644 tests/qapi-schema/union-max.err
delete mode 100644 tests/qapi-schema/union-max.json
--
2.4.3
^ permalink raw reply [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 01/40] qapi: Track simple union tag in object.local_members
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 02/40] qapi-types: Consolidate gen_struct() and gen_union() Markus Armbruster
` (39 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
We were previously creating all unions with an empty list for
local_members. However, it will make it easier to unify struct
and union generation if we include the generated tag member in
local_members. That way, we can have a common code pattern:
visit the base (if any), visit the local members (if any), visit
the variants (if any). The local_members of a flat union
remains empty (because the discriminator is already visited as
part of the base). Then, by visiting tag_member.check() during
AlternateType.check(), we no longer need to call it during
Variants.check().
The various front end entities now exist as follows:
struct: optional base, optional local_members, no variants
simple union: no base, one-element local_members, variants with tag_member
from local_members
flat union: base, no local_members, variants with tag_member from base
alternate: no base, no local_members, variants
With the new local members, we require a bit of finesse to
avoid assertions in the clients.
No change to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-2-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi-types.py | 5 ++++-
scripts/qapi-visit.py | 5 ++++-
scripts/qapi.py | 15 ++++++++++-----
tests/qapi-schema/qapi-schema-test.out | 2 ++
tests/qapi-schema/union-clash-data.out | 1 +
tests/qapi-schema/union-empty.out | 1 +
6 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index b37900f..946afab 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -269,7 +269,10 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
def visit_object_type(self, name, info, base, members, variants):
self._fwdecl += gen_fwd_object_or_array(name)
if variants:
- assert not members # not implemented
+ if members:
+ # Members other than variants.tag_member not implemented
+ assert len(members) == 1
+ assert members[0] == variants.tag_member
self.decl += gen_union(name, base, variants)
else:
self.decl += gen_struct(name, base, members)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 3ef5c16..94cd113 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -364,7 +364,10 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def visit_object_type(self, name, info, base, members, variants):
self.decl += gen_visit_decl(name)
if variants:
- assert not members # not implemented
+ if members:
+ # Members other than variants.tag_member not implemented
+ assert len(members) == 1
+ assert members[0] == variants.tag_member
self.defn += gen_visit_union(name, base, variants)
else:
self.defn += gen_visit_struct(name, base, members)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 7c50cc4..687d9dc 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -957,6 +957,9 @@ class QAPISchemaArrayType(QAPISchemaType):
class QAPISchemaObjectType(QAPISchemaType):
def __init__(self, name, info, base, local_members, variants):
+ # struct has local_members, optional base, and no variants
+ # flat union has base, variants, and no local_members
+ # simple union has local_members, variants, and no base
QAPISchemaType.__init__(self, name, info)
assert base is None or isinstance(base, str)
for m in local_members:
@@ -1048,10 +1051,10 @@ class QAPISchemaObjectTypeVariants(object):
self.variants = variants
def check(self, schema, members, seen):
- if self.tag_name:
+ if self.tag_name: # flat union
self.tag_member = seen[self.tag_name]
- else:
- self.tag_member.check(schema, members, seen)
+ if seen:
+ assert self.tag_member in seen.itervalues()
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
vseen = dict(seen)
@@ -1085,6 +1088,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
self.variants = variants
def check(self, schema):
+ self.variants.tag_member.check(schema, [], {})
self.variants.check(schema, [], {})
def json_type(self):
@@ -1270,13 +1274,14 @@ class QAPISchema(object):
if tag_name:
variants = [self._make_variant(key, value)
for (key, value) in data.iteritems()]
+ members = []
else:
variants = [self._make_simple_variant(key, value, info)
for (key, value) in data.iteritems()]
tag_member = self._make_implicit_tag(name, info, variants)
+ members = [tag_member]
self._def_entity(
- QAPISchemaObjectType(name, info, base,
- self._make_members(OrderedDict(), info),
+ QAPISchemaObjectType(name, info, base, members,
QAPISchemaObjectTypeVariants(tag_name,
tag_member,
variants)))
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index e20a823..786024e 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -132,6 +132,7 @@ object UserDefFlatUnion2
case value2: UserDefB
case value3: UserDefA
object UserDefNativeListUnion
+ member type: UserDefNativeListUnionKind optional=False
case integer: :obj-intList-wrapper
case s8: :obj-int8List-wrapper
case s16: :obj-int16List-wrapper
@@ -187,6 +188,7 @@ object __org.qemu_x-Struct
object __org.qemu_x-Struct2
member array: __org.qemu_x-Union1List optional=False
object __org.qemu_x-Union1
+ member type: __org.qemu_x-Union1Kind optional=False
case __org.qemu_x-branch: :obj-str-wrapper
enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
object __org.qemu_x-Union2
diff --git a/tests/qapi-schema/union-clash-data.out b/tests/qapi-schema/union-clash-data.out
index 6277239..cea8551 100644
--- a/tests/qapi-schema/union-clash-data.out
+++ b/tests/qapi-schema/union-clash-data.out
@@ -2,5 +2,6 @@ object :empty
object :obj-int-wrapper
member data: int optional=False
object TestUnion
+ member type: TestUnionKind optional=False
case data: :obj-int-wrapper
enum TestUnionKind ['data']
diff --git a/tests/qapi-schema/union-empty.out b/tests/qapi-schema/union-empty.out
index 8b5a7bf..9c89fd1 100644
--- a/tests/qapi-schema/union-empty.out
+++ b/tests/qapi-schema/union-empty.out
@@ -1,3 +1,4 @@
object :empty
object Union
+ member type: UnionKind optional=False
enum UnionKind []
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 02/40] qapi-types: Consolidate gen_struct() and gen_union()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 01/40] qapi: Track simple union tag in object.local_members Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 03/40] qapi-types: Simplify gen_struct_field[s] Markus Armbruster
` (38 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
These two methods are now close enough that we can finally merge
them, relying on the fact that simple unions now provide a
reasonable local_members. Change gen_struct() to gen_object()
that handles all forms of QAPISchemaObjectType, and rename and
shrink gen_union() to gen_variants() to handle the portion of
gen_object() needed when variants are present.
gen_struct_fields() now has a single caller, so it no longer
needs an optional parameter; however, I did not choose to inline
it into the caller.
No difference to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-3-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi-types.py | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 946afab..403768b 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -51,7 +51,7 @@ def gen_struct_field(member):
return ret
-def gen_struct_fields(local_members, base=None):
+def gen_struct_fields(local_members, base):
ret = ''
if base:
@@ -70,7 +70,7 @@ def gen_struct_fields(local_members, base=None):
return ret
-def gen_struct(name, base, members):
+def gen_object(name, base, members, variants):
ret = mcgen('''
struct %(c_name)s {
@@ -79,11 +79,14 @@ struct %(c_name)s {
ret += gen_struct_fields(members, base)
+ if variants:
+ ret += gen_variants(variants)
+
# Make sure that all structs have at least one field; this avoids
# potential issues with attempting to malloc space for zero-length
# structs in C, and also incompatibility with C++ (where an empty
# struct is size 1).
- if not (base and base.members) and not members:
+ if not (base and base.members) and not members and not variants:
ret += mcgen('''
char qapi_dummy_field_for_empty_struct;
''')
@@ -140,17 +143,7 @@ const int %(c_name)s_qtypes[QTYPE_MAX] = {
return ret
-def gen_union(name, base, variants):
- ret = mcgen('''
-
-struct %(c_name)s {
-''',
- c_name=c_name(name))
- if base:
- ret += gen_struct_fields([], base)
- else:
- ret += gen_struct_field(variants.tag_member)
-
+def gen_variants(variants):
# FIXME: What purpose does data serve, besides preventing a union that
# has a branch named 'data'? We use it in qapi-visit.py to decide
# whether to bypass the switch statement if visiting the discriminator
@@ -159,11 +152,11 @@ struct %(c_name)s {
# should not be any data leaks even without a data pointer. Or, if
# 'data' is merely added to guarantee we don't have an empty union,
# shouldn't we enforce that at .json parse time?
- ret += mcgen('''
+ ret = mcgen('''
union { /* union tag is @%(c_name)s */
void *data;
''',
- c_name=c_name(variants.tag_member.name))
+ c_name=c_name(variants.tag_member.name))
for var in variants.variants:
# Ugly special case for simple union TODO get rid of it
@@ -176,7 +169,6 @@ struct %(c_name)s {
ret += mcgen('''
} u;
-};
''')
return ret
@@ -268,14 +260,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
def visit_object_type(self, name, info, base, members, variants):
self._fwdecl += gen_fwd_object_or_array(name)
- if variants:
- if members:
- # Members other than variants.tag_member not implemented
- assert len(members) == 1
- assert members[0] == variants.tag_member
- self.decl += gen_union(name, base, variants)
- else:
- self.decl += gen_struct(name, base, members)
+ self.decl += gen_object(name, base, members, variants)
if base:
self.decl += gen_upcast(name, base)
self._gen_type_cleanup(name)
@@ -283,7 +268,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
def visit_alternate_type(self, name, info, variants):
self._fwdecl += gen_fwd_object_or_array(name)
self._fwdefn += gen_alternate_qtypes(name, variants)
- self.decl += gen_union(name, None, variants)
+ self.decl += gen_object(name, None, [variants.tag_member], variants)
self.decl += gen_alternate_qtypes_decl(name)
self._gen_type_cleanup(name)
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 03/40] qapi-types: Simplify gen_struct_field[s]
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 01/40] qapi: Track simple union tag in object.local_members Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 02/40] qapi-types: Consolidate gen_struct() and gen_union() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 04/40] qapi: Drop obsolete tag value collision assertions Markus Armbruster
` (37 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Simplify gen_struct_fields() back to a single iteration over a
list of fields (like it was prior to commit f87ab7f9), by moving
the generated comments to gen_object(). Then, inline
gen_struct_field() into its only caller.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-4-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi-types.py | 40 +++++++++++++++-------------------------
1 file changed, 15 insertions(+), 25 deletions(-)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 403768b..2f2f7df 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -36,48 +36,38 @@ struct %(c_name)s {
c_name=c_name(name), c_type=element_type.c_type())
-def gen_struct_field(member):
+def gen_struct_fields(members):
ret = ''
-
- if member.optional:
- ret += mcgen('''
+ for memb in members:
+ if memb.optional:
+ ret += mcgen('''
bool has_%(c_name)s;
''',
- c_name=c_name(member.name))
- ret += mcgen('''
+ c_name=c_name(memb.name))
+ ret += mcgen('''
%(c_type)s %(c_name)s;
''',
- c_type=member.type.c_type(), c_name=c_name(member.name))
+ c_type=memb.type.c_type(), c_name=c_name(memb.name))
return ret
-def gen_struct_fields(local_members, base):
- ret = ''
+def gen_object(name, base, members, variants):
+ ret = mcgen('''
+
+struct %(c_name)s {
+''',
+ c_name=c_name(name))
if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=base.c_name())
- for memb in base.members:
- ret += gen_struct_field(memb)
+ ret += gen_struct_fields(base.members)
ret += mcgen('''
/* Own members: */
''')
-
- for memb in local_members:
- ret += gen_struct_field(memb)
- return ret
-
-
-def gen_object(name, base, members, variants):
- ret = mcgen('''
-
-struct %(c_name)s {
-''',
- c_name=c_name(name))
-
- ret += gen_struct_fields(members, base)
+ ret += gen_struct_fields(members)
if variants:
ret += gen_variants(variants)
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 04/40] qapi: Drop obsolete tag value collision assertions
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (2 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 03/40] qapi-types: Simplify gen_struct_field[s] Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 05/40] qapi: Simplify QAPISchemaObjectTypeMember.check() Markus Armbruster
` (36 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
Union tag values can't clash with member names in generated C anymore
since commit e4ba22b, but QAPISchemaObjectTypeVariants.check() still
asserts they don't. Drop it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-1-git-send-email-armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-5-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 687d9dc..29377d6 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1057,8 +1057,7 @@ class QAPISchemaObjectTypeVariants(object):
assert self.tag_member in seen.itervalues()
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
- vseen = dict(seen)
- v.check(schema, self.tag_member.type, vseen)
+ v.check(schema, self.tag_member.type, {})
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 05/40] qapi: Simplify QAPISchemaObjectTypeMember.check()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (3 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 04/40] qapi: Drop obsolete tag value collision assertions Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 06/40] qapi: Clean up after previous commit Markus Armbruster
` (35 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
QAPISchemaObjectTypeMember.check() currently does four things:
1. Compute self.type
2. Accumulate members in all_members
Only one caller cares: QAPISchemaObjectType.check() uses it to
compute self.members. The other callers pass a throw-away
accumulator.
3. Accumulate a map from names to members in seen
Only one caller cares: QAPISchemaObjectType.check() uses it to
compute its local variable seen, for self.variants.check(), which
uses it to compute self.variants.tag_member from
self.variants.tag_name. The other callers pass a throw-away
accumulator.
4. Check for collisions
This piggybacks on 3: before adding a new entry, we assert it's new.
Only one caller cares: QAPISchemaObjectType.check() uses it to
assert non-variant members don't clash.
Simplify QAPISchemaObjectType.check(): move 2.-4. to
QAPISchemaObjectType.check(), and drop parameters all_members and
seen.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-2-git-send-email-armbru@redhat.com>
[rebase to earlier changes that moved tag_member.check() of
alternate types, commit message typo fix]
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-6-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 29377d6..63d39e4 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -990,7 +990,10 @@ class QAPISchemaObjectType(QAPISchemaType):
assert c_name(m.name) not in seen
seen[m.name] = m
for m in self.local_members:
- m.check(schema, members, seen)
+ m.check(schema)
+ assert m.name not in seen
+ seen[m.name] = m
+ members.append(m)
if self.variants:
self.variants.check(schema, members, seen)
self.members = members
@@ -1027,12 +1030,9 @@ class QAPISchemaObjectTypeMember(object):
self.type = None
self.optional = optional
- def check(self, schema, all_members, seen):
- assert self.name not in seen
+ def check(self, schema):
self.type = schema.lookup_type(self._type_name)
assert self.type
- all_members.append(self)
- seen[self.name] = self
class QAPISchemaObjectTypeVariants(object):
@@ -1065,7 +1065,7 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
def check(self, schema, tag_type, seen):
- QAPISchemaObjectTypeMember.check(self, schema, [], seen)
+ QAPISchemaObjectTypeMember.check(self, schema)
assert self.name in tag_type.values
# This function exists to support ugly simple union special cases
@@ -1087,7 +1087,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
self.variants = variants
def check(self, schema):
- self.variants.tag_member.check(schema, [], {})
+ self.variants.tag_member.check(schema)
self.variants.check(schema, [], {})
def json_type(self):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 06/40] qapi: Clean up after previous commit
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (4 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 05/40] qapi: Simplify QAPISchemaObjectTypeMember.check() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 07/40] qapi: Fix up commit 7618b91's clash sanity checking change Markus Armbruster
` (34 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
QAPISchemaObjectTypeVariants.check() parameter members and
QAPISchemaObjectTypeVariant.check() parameter seen are no longer used,
drop them.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-3-git-send-email-armbru@redhat.com>
[rebase to earlier changes that moved tag_member.check() of
alternate types]
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-7-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 63d39e4..0bf8235 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -995,7 +995,7 @@ class QAPISchemaObjectType(QAPISchemaType):
seen[m.name] = m
members.append(m)
if self.variants:
- self.variants.check(schema, members, seen)
+ self.variants.check(schema, seen)
self.members = members
def is_implicit(self):
@@ -1050,21 +1050,21 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = tag_member
self.variants = variants
- def check(self, schema, members, seen):
+ def check(self, schema, seen):
if self.tag_name: # flat union
self.tag_member = seen[self.tag_name]
if seen:
assert self.tag_member in seen.itervalues()
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
- v.check(schema, self.tag_member.type, {})
+ v.check(schema, self.tag_member.type)
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
def __init__(self, name, typ):
QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
- def check(self, schema, tag_type, seen):
+ def check(self, schema, tag_type):
QAPISchemaObjectTypeMember.check(self, schema)
assert self.name in tag_type.values
@@ -1088,7 +1088,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
def check(self, schema):
self.variants.tag_member.check(schema)
- self.variants.check(schema, [], {})
+ self.variants.check(schema, {})
def json_type(self):
return 'value'
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 07/40] qapi: Fix up commit 7618b91's clash sanity checking change
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (5 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 06/40] qapi: Clean up after previous commit Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 08/40] qapi: Eliminate QAPISchemaObjectType.check() variable members Markus Armbruster
` (33 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
This hunk
@@ -964,6 +965,7 @@ class QAPISchemaObjectType(QAPISchemaType):
members = []
seen = {}
for m in members:
+ assert c_name(m.name) not in seen
seen[m.name] = m
for m in self.local_members:
m.check(schema, members, seen)
is plainly broken.
Asserting the members inherited from base don't clash is somewhat
redundant, because self.base.check() just checked that. But it
doesn't hurt.
The idea to use c_name(m.name) instead of m.name for collision
checking is sound, because we need to catch clashes between the m.name
and between the c_name(m.name), and when two m.name clash, then their
c_name() also clash.
However, using c_name(m.name) instead of m.name in one of several
places doesn't work. See the very next line.
Keep the assertion, but drop the c_name() for now. A future commit
will bring it back.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-4-git-send-email-armbru@redhat.com>
[change TABs in commit message to space]
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-8-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0bf8235..86d2adc 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -987,7 +987,7 @@ class QAPISchemaObjectType(QAPISchemaType):
members = []
seen = {}
for m in members:
- assert c_name(m.name) not in seen
+ assert m.name not in seen
seen[m.name] = m
for m in self.local_members:
m.check(schema)
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 08/40] qapi: Eliminate QAPISchemaObjectType.check() variable members
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (6 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 07/40] qapi: Fix up commit 7618b91's clash sanity checking change Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 09/40] qapi: Factor out QAPISchemaObjectTypeMember.check_clash() Markus Armbruster
` (32 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
We can use seen.values() instead if we make it an OrderedDict.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-5-git-send-email-armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-9-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 86d2adc..44d08c1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -977,26 +977,22 @@ class QAPISchemaObjectType(QAPISchemaType):
if self.members:
return
self.members = False # mark as being checked
+ seen = OrderedDict()
if self._base_name:
self.base = schema.lookup_type(self._base_name)
assert isinstance(self.base, QAPISchemaObjectType)
assert not self.base.variants # not implemented
self.base.check(schema)
- members = list(self.base.members)
- else:
- members = []
- seen = {}
- for m in members:
- assert m.name not in seen
- seen[m.name] = m
+ for m in self.base.members:
+ assert m.name not in seen
+ seen[m.name] = m
for m in self.local_members:
m.check(schema)
assert m.name not in seen
seen[m.name] = m
- members.append(m)
if self.variants:
self.variants.check(schema, seen)
- self.members = members
+ self.members = seen.values()
def is_implicit(self):
# See QAPISchema._make_implicit_object_type()
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 09/40] qapi: Factor out QAPISchemaObjectTypeMember.check_clash()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (7 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 08/40] qapi: Eliminate QAPISchemaObjectType.check() variable members Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 10/40] qapi: Simplify QAPISchemaObjectTypeVariants.check() Markus Armbruster
` (31 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
While there, stick in a TODO change key of seen from QAPI name to C
name. Can't do it right away, because it would fail the assertion for
tests/qapi-schema/args-has-clash.json.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-6-git-send-email-armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-10-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 44d08c1..2a73b2b 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -984,12 +984,10 @@ class QAPISchemaObjectType(QAPISchemaType):
assert not self.base.variants # not implemented
self.base.check(schema)
for m in self.base.members:
- assert m.name not in seen
- seen[m.name] = m
+ m.check_clash(seen)
for m in self.local_members:
m.check(schema)
- assert m.name not in seen
- seen[m.name] = m
+ m.check_clash(seen)
if self.variants:
self.variants.check(schema, seen)
self.members = seen.values()
@@ -1030,6 +1028,11 @@ class QAPISchemaObjectTypeMember(object):
self.type = schema.lookup_type(self._type_name)
assert self.type
+ def check_clash(self, seen):
+ # TODO change key of seen from QAPI name to C name
+ assert self.name not in seen
+ seen[self.name] = self
+
class QAPISchemaObjectTypeVariants(object):
def __init__(self, tag_name, tag_member, variants):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 10/40] qapi: Simplify QAPISchemaObjectTypeVariants.check()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (8 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 09/40] qapi: Factor out QAPISchemaObjectTypeMember.check_clash() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 11/40] qapi: Check for QAPI collisions involving variant members Markus Armbruster
` (30 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
Reduce the ugly flat union / simple union conditional by doing just
the essential work here, namely setting self.tag_member.
Move the rest to callers.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1446559499-26984-7-git-send-email-armbru@redhat.com>
[rebase to earlier changes that moved tag_member.check() of
alternate types, and tweak commit title and wording]
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-11-git-send-email-eblake@redhat.com>
---
scripts/qapi.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 2a73b2b..c6cb17b 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -988,9 +988,10 @@ class QAPISchemaObjectType(QAPISchemaType):
for m in self.local_members:
m.check(schema)
m.check_clash(seen)
+ self.members = seen.values()
if self.variants:
self.variants.check(schema, seen)
- self.members = seen.values()
+ assert self.variants.tag_member in self.members
def is_implicit(self):
# See QAPISchema._make_implicit_object_type()
@@ -1050,10 +1051,8 @@ class QAPISchemaObjectTypeVariants(object):
self.variants = variants
def check(self, schema, seen):
- if self.tag_name: # flat union
+ if not self.tag_member: # flat union
self.tag_member = seen[self.tag_name]
- if seen:
- assert self.tag_member in seen.itervalues()
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
v.check(schema, self.tag_member.type)
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 11/40] qapi: Check for QAPI collisions involving variant members
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (9 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 10/40] qapi: Simplify QAPISchemaObjectTypeVariants.check() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 12/40] qapi: Factor out QAPISchemaObjectType.check_clash() Markus Armbruster
` (29 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Right now, our ad hoc parser ensures that we cannot have a
flat union that introduces any members that would clash with
non-variant members inherited from the union's base type (see
flat-union-clash-member.json). We want QAPISchemaObjectType.check()
to make the same check, so we can later reduce some of the ad
hoc checks.
We already have a map 'seen' of all non-variant members. We
still need to check for collisions between each variant type's
members and the non-variant ones.
To know the variant type's members, we need to call
variant.type.check(). This also detects when a type contains
itself in a variant, exactly like the existing base.check()
detects when a type contains itself as a base. (Except that
we currently forbid anything but a struct as the type of a
variant, so we can't actually trigger this type of loop yet.)
Slight complication: an alternate's variant can have arbitrary
type, but only an object type's check() may be called outside
QAPISchema.check(). We could either skip the call for variants
of alternates, or skip it for non-object types. For now, do
the latter, because it's easier.
Then we call each variant member's check_clash() with the
appropriate 'seen' map. Since members of different variants
can't clash, we have to clone a fresh seen for each variant.
Wrap this in a new helper method
QAPISchemaObjectTypeVariants.check_clash().
Note that cloning 'seen' inside .check_clash() resembles
the one we just removed from .check() in 'qapi: Drop
obsolete tag value collision assertions'; the difference here is
that we are now checking for clashes among the qapi members of
the variant type, rather than for a single clash with the variant
tag name itself.
Note that, by construction, collisions can't actually happen for
simple unions: each variant's type is a wrapper with a single
member 'data', which will never collide with the only non-variant
member 'type'.
For alternates, there's nothing for a variant object type's
members to clash with, and therefore no need to call the new
variants.check_clash().
No change to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-12-git-send-email-eblake@redhat.com>
[Commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index c6cb17b..b2d071f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -992,6 +992,7 @@ class QAPISchemaObjectType(QAPISchemaType):
if self.variants:
self.variants.check(schema, seen)
assert self.variants.tag_member in self.members
+ self.variants.check_clash(schema, seen)
def is_implicit(self):
# See QAPISchema._make_implicit_object_type()
@@ -1056,6 +1057,18 @@ class QAPISchemaObjectTypeVariants(object):
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
v.check(schema, self.tag_member.type)
+ if isinstance(v.type, QAPISchemaObjectType):
+ v.type.check(schema)
+
+ def check_clash(self, schema, seen):
+ for v in self.variants:
+ # Reset seen map for each variant, since qapi names from one
+ # branch do not affect another branch
+ vseen = dict(seen)
+ assert isinstance(v.type, QAPISchemaObjectType)
+ assert not v.type.variants # not implemented
+ for m in v.type.members:
+ m.check_clash(vseen)
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
@@ -1086,6 +1099,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
def check(self, schema):
self.variants.tag_member.check(schema)
+ # Not calling self.variants.check_clash(), because there's nothing
+ # to clash with
self.variants.check(schema, {})
def json_type(self):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 12/40] qapi: Factor out QAPISchemaObjectType.check_clash()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (10 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 11/40] qapi: Check for QAPI collisions involving variant members Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 13/40] qapi: Hoist tag collision check to Variants.check() Markus Armbruster
` (28 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Consolidate two common sequences of clash detection into a
new QAPISchemaObjectType.check_clash() helper method.
No change to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index b2d071f..296b9bb 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -981,10 +981,8 @@ class QAPISchemaObjectType(QAPISchemaType):
if self._base_name:
self.base = schema.lookup_type(self._base_name)
assert isinstance(self.base, QAPISchemaObjectType)
- assert not self.base.variants # not implemented
self.base.check(schema)
- for m in self.base.members:
- m.check_clash(seen)
+ self.base.check_clash(schema, seen)
for m in self.local_members:
m.check(schema)
m.check_clash(seen)
@@ -994,6 +992,11 @@ class QAPISchemaObjectType(QAPISchemaType):
assert self.variants.tag_member in self.members
self.variants.check_clash(schema, seen)
+ def check_clash(self, schema, seen):
+ assert not self.variants # not implemented
+ for m in self.members:
+ m.check_clash(seen)
+
def is_implicit(self):
# See QAPISchema._make_implicit_object_type()
return self.name[0] == ':'
@@ -1064,11 +1067,8 @@ class QAPISchemaObjectTypeVariants(object):
for v in self.variants:
# Reset seen map for each variant, since qapi names from one
# branch do not affect another branch
- vseen = dict(seen)
assert isinstance(v.type, QAPISchemaObjectType)
- assert not v.type.variants # not implemented
- for m in v.type.members:
- m.check_clash(vseen)
+ v.type.check_clash(schema, dict(seen))
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 13/40] qapi: Hoist tag collision check to Variants.check()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (11 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 12/40] qapi: Factor out QAPISchemaObjectType.check_clash() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 14/40] qapi: Remove outdated tests related to QMP/branch collisions Markus Armbruster
` (27 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Checking that a given QAPISchemaObjectTypeVariant.name is a
member of the corresponding QAPISchemaEnumType of the owning
QAPISchemaObjectTypeVariants.tag_member ensures that there are
no collisions in the generated C union for those tag values
(since the enum itself should have no collisions).
However, ever since its introduction in f51d8c3d, this was the
only additional action of of Variant.check(), beyond calling
the superclass Member.check(). This forces a difference in
.check() signatures, just to pass the enum type down.
Simplify things by instead doing the tag name check as part of
Variants.check(), at which point we can rely on inheritance
instead of overriding Variant.check().
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-14-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 296b9bb..c6f3fce 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1059,7 +1059,8 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = seen[self.tag_name]
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
- v.check(schema, self.tag_member.type)
+ v.check(schema)
+ assert v.name in self.tag_member.type.values
if isinstance(v.type, QAPISchemaObjectType):
v.type.check(schema)
@@ -1075,10 +1076,6 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
def __init__(self, name, typ):
QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
- def check(self, schema, tag_type):
- QAPISchemaObjectTypeMember.check(self, schema)
- assert self.name in tag_type.values
-
# This function exists to support ugly simple union special cases
# TODO get rid of them, and drop the function
def simple_union_type(self):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 14/40] qapi: Remove outdated tests related to QMP/branch collisions
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (12 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 13/40] qapi: Hoist tag collision check to Variants.check() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 15/40] qapi: Track owner of each object member Markus Armbruster
` (26 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Now that branches are in a separate C namespace, we can remove
the restrictions in the parser that claim a branch name would
collide with QMP, and delete the negative tests that are no
longer problematic. A separate patch can then add positive
tests to qapi-schema-test to test that any corner cases will
compile correctly.
This reverts the scripts/qapi.py portion of commit 7b2a5c2,
now that the assertions that it plugged are no longer possible.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-15-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 11 ++---------
tests/Makefile | 3 ---
tests/qapi-schema/flat-union-clash-branch.err | 0
tests/qapi-schema/flat-union-clash-branch.exit | 1 -
tests/qapi-schema/flat-union-clash-branch.json | 18 ------------------
tests/qapi-schema/flat-union-clash-branch.out | 14 --------------
tests/qapi-schema/flat-union-clash-type.err | 1 -
tests/qapi-schema/flat-union-clash-type.exit | 1 -
tests/qapi-schema/flat-union-clash-type.json | 14 --------------
tests/qapi-schema/flat-union-clash-type.out | 0
tests/qapi-schema/union-clash-type.err | 1 -
tests/qapi-schema/union-clash-type.exit | 1 -
tests/qapi-schema/union-clash-type.json | 9 ---------
tests/qapi-schema/union-clash-type.out | 0
14 files changed, 2 insertions(+), 72 deletions(-)
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.err
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.exit
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.json
delete mode 100644 tests/qapi-schema/flat-union-clash-branch.out
delete mode 100644 tests/qapi-schema/flat-union-clash-type.err
delete mode 100644 tests/qapi-schema/flat-union-clash-type.exit
delete mode 100644 tests/qapi-schema/flat-union-clash-type.json
delete mode 100644 tests/qapi-schema/flat-union-clash-type.out
delete mode 100644 tests/qapi-schema/union-clash-type.err
delete mode 100644 tests/qapi-schema/union-clash-type.exit
delete mode 100644 tests/qapi-schema/union-clash-type.json
delete mode 100644 tests/qapi-schema/union-clash-type.out
diff --git a/scripts/qapi.py b/scripts/qapi.py
index c6f3fce..6fc14be 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -548,8 +548,7 @@ def check_union(expr, expr_info):
base = expr.get('base')
discriminator = expr.get('discriminator')
members = expr['data']
- values = {'MAX': '(automatic)', 'KIND': '(automatic)',
- 'TYPE': '(automatic)'}
+ values = {'MAX': '(automatic)'}
# Two types of unions, determined by discriminator.
@@ -607,19 +606,13 @@ 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, which in turn
- # must not collide with the discriminator name.
+ # of 'data' must also be members of the enum type.
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:
diff --git a/tests/Makefile b/tests/Makefile
index a1d03b4..6518ef9 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -281,9 +281,7 @@ qapi-schema += flat-union-bad-base.json
qapi-schema += flat-union-bad-discriminator.json
qapi-schema += flat-union-base-any.json
qapi-schema += flat-union-base-union.json
-qapi-schema += flat-union-clash-branch.json
qapi-schema += flat-union-clash-member.json
-qapi-schema += flat-union-clash-type.json
qapi-schema += flat-union-empty.json
qapi-schema += flat-union-inline.json
qapi-schema += flat-union-int-branch.json
@@ -345,7 +343,6 @@ qapi-schema += union-bad-branch.json
qapi-schema += union-base-no-discriminator.json
qapi-schema += union-clash-branches.json
qapi-schema += union-clash-data.json
-qapi-schema += union-clash-type.json
qapi-schema += union-empty.json
qapi-schema += union-invalid-base.json
qapi-schema += union-max.json
diff --git a/tests/qapi-schema/flat-union-clash-branch.err b/tests/qapi-schema/flat-union-clash-branch.err
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/flat-union-clash-branch.exit b/tests/qapi-schema/flat-union-clash-branch.exit
deleted file mode 100644
index 573541a..0000000
--- a/tests/qapi-schema/flat-union-clash-branch.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/flat-union-clash-branch.json b/tests/qapi-schema/flat-union-clash-branch.json
deleted file mode 100644
index e593336..0000000
--- a/tests/qapi-schema/flat-union-clash-branch.json
+++ /dev/null
@@ -1,18 +0,0 @@
-# Flat union branch name collision
-# FIXME: this parses, but then fails to compile due to a duplicate 'c_d'
-# (one from the base member, the other from the branch name). We should
-# either reject the collision at parse time, or munge the generated branch
-# name to allow this to compile.
-{ 'enum': 'TestEnum',
- 'data': [ 'base', 'c-d' ] }
-{ 'struct': 'Base',
- 'data': { 'enum1': 'TestEnum', '*c_d': 'str' } }
-{ 'struct': 'Branch1',
- 'data': { 'string': 'str' } }
-{ 'struct': 'Branch2',
- 'data': { 'value': 'int' } }
-{ 'union': 'TestUnion',
- 'base': 'Base',
- 'discriminator': 'enum1',
- 'data': { 'base': 'Branch1',
- 'c-d': 'Branch2' } }
diff --git a/tests/qapi-schema/flat-union-clash-branch.out b/tests/qapi-schema/flat-union-clash-branch.out
deleted file mode 100644
index 8e0da73..0000000
--- a/tests/qapi-schema/flat-union-clash-branch.out
+++ /dev/null
@@ -1,14 +0,0 @@
-object :empty
-object Base
- member enum1: TestEnum optional=False
- member c_d: str optional=True
-object Branch1
- member string: str optional=False
-object Branch2
- member value: int optional=False
-enum TestEnum ['base', 'c-d']
-object TestUnion
- base Base
- tag enum1
- case base: Branch1
- case c-d: Branch2
diff --git a/tests/qapi-schema/flat-union-clash-type.err b/tests/qapi-schema/flat-union-clash-type.err
deleted file mode 100644
index b44dd40..0000000
--- a/tests/qapi-schema/flat-union-clash-type.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/flat-union-clash-type.json:11: Discriminator name 'type' collides with enum value in 'TestEnum'
diff --git a/tests/qapi-schema/flat-union-clash-type.exit b/tests/qapi-schema/flat-union-clash-type.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/flat-union-clash-type.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/flat-union-clash-type.json b/tests/qapi-schema/flat-union-clash-type.json
deleted file mode 100644
index 8f710f0..0000000
--- a/tests/qapi-schema/flat-union-clash-type.json
+++ /dev/null
@@ -1,14 +0,0 @@
-# Flat union branch 'type'
-# 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',
- 'data': { 'type': 'TestEnum' } }
-{ 'struct': 'Branch1',
- 'data': { 'string': 'str' } }
-{ 'union': 'TestUnion',
- 'base': 'Base',
- 'discriminator': 'type',
- 'data': { 'type': 'Branch1' } }
diff --git a/tests/qapi-schema/flat-union-clash-type.out b/tests/qapi-schema/flat-union-clash-type.out
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/union-clash-type.err b/tests/qapi-schema/union-clash-type.err
deleted file mode 100644
index a5dead1..0000000
--- a/tests/qapi-schema/union-clash-type.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'kind' clashes with '(automatic)'
diff --git a/tests/qapi-schema/union-clash-type.exit b/tests/qapi-schema/union-clash-type.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/union-clash-type.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/union-clash-type.json b/tests/qapi-schema/union-clash-type.json
deleted file mode 100644
index cfc256b..0000000
--- a/tests/qapi-schema/union-clash-type.json
+++ /dev/null
@@ -1,9 +0,0 @@
-# Union branch 'type'
-# 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' } }
diff --git a/tests/qapi-schema/union-clash-type.out b/tests/qapi-schema/union-clash-type.out
deleted file mode 100644
index e69de29..0000000
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 15/40] qapi: Track owner of each object member
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (13 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 14/40] qapi: Remove outdated tests related to QMP/branch collisions Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 16/40] qapi: Detect collisions in C member names Markus Armbruster
` (25 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Future commits will migrate semantic checking away from parsing
and over to the various QAPISchema*.check() methods. But to
report an error message about an incorrect semantic use of a
member of an object type, it helps to know which type, command,
or event owns the member. In particular, when a member is
inherited from a base type, it is desirable to associate the
member name with the base type (and not the type calling
member.check()).
Rather than packing additional information into the seen array
passed to each member.check() (as in seen[m.name] = {'member':m,
'owner':type}), it is easier to have each member track the name
of the owner type in the first place (keeping things simpler
with the existing seen[m.name] = m). The new member.owner field
is set via a new set_owner() method, called when registering
the members and variants arrays with an object or variant type.
Track only a name, and not the actual type object, to avoid
creating a circular python reference chain.
Note that Variants.set_owner() method does not set the owner
for the tag_member field; this field is set earlier either as
part of an object's non-variant members, or explicitly by
alternates.
The source information is intended for human consumption in
error messages, and a new describe() method is added to access
the resulting information. For example, given the qapi:
{ 'command': 'foo', 'data': { 'string': 'str' } }
an implementation of visit_command() that calls
arg_type.members[0].describe()
will see "'string' (parameter of foo)".
To make the human-readable name of implicit types work without
duplicating efforts, the describe() method has to reverse the
name of implicit types, via the helper _pretty_owner().
No change to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-16-git-send-email-eblake@redhat.com>
[Incorrect & unused -wrapper case in _pretty_owner() dropped]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6fc14be..77d3e0a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -957,8 +957,10 @@ class QAPISchemaObjectType(QAPISchemaType):
assert base is None or isinstance(base, str)
for m in local_members:
assert isinstance(m, QAPISchemaObjectTypeMember)
- assert (variants is None or
- isinstance(variants, QAPISchemaObjectTypeVariants))
+ m.set_owner(name)
+ if variants is not None:
+ assert isinstance(variants, QAPISchemaObjectTypeVariants)
+ variants.set_owner(name)
self._base_name = base
self.base = None
self.local_members = local_members
@@ -1013,6 +1015,8 @@ class QAPISchemaObjectType(QAPISchemaType):
class QAPISchemaObjectTypeMember(object):
+ role = 'member'
+
def __init__(self, name, typ, optional):
assert isinstance(name, str)
assert isinstance(typ, str)
@@ -1021,8 +1025,14 @@ class QAPISchemaObjectTypeMember(object):
self._type_name = typ
self.type = None
self.optional = optional
+ self.owner = None
+
+ def set_owner(self, name):
+ assert not self.owner
+ self.owner = name
def check(self, schema):
+ assert self.owner
self.type = schema.lookup_type(self._type_name)
assert self.type
@@ -1031,6 +1041,23 @@ class QAPISchemaObjectTypeMember(object):
assert self.name not in seen
seen[self.name] = self
+ def _pretty_owner(self):
+ owner = self.owner
+ if owner.startswith(':obj-'):
+ # See QAPISchema._make_implicit_object_type() - reverse the
+ # mapping there to create a nice human-readable description
+ owner = owner[5:]
+ if owner.endswith('-arg'):
+ return '(parameter of %s)' % owner[:-4]
+ else:
+ assert owner.endswith('-wrapper')
+ # Unreachable and not implemented
+ assert False
+ return '(%s of %s)' % (self.role, owner)
+
+ def describe(self):
+ return "'%s' %s" % (self.name, self._pretty_owner())
+
class QAPISchemaObjectTypeVariants(object):
def __init__(self, tag_name, tag_member, variants):
@@ -1047,6 +1074,10 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = tag_member
self.variants = variants
+ def set_owner(self, name):
+ for v in self.variants:
+ v.set_owner(name)
+
def check(self, schema, seen):
if not self.tag_member: # flat union
self.tag_member = seen[self.tag_name]
@@ -1066,6 +1097,8 @@ class QAPISchemaObjectTypeVariants(object):
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
+ role = 'branch'
+
def __init__(self, name, typ):
QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
@@ -1085,6 +1118,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
QAPISchemaType.__init__(self, name, info)
assert isinstance(variants, QAPISchemaObjectTypeVariants)
assert not variants.tag_name
+ variants.set_owner(name)
+ variants.tag_member.set_owner(self.name)
self.variants = variants
def check(self, schema):
@@ -1217,6 +1252,7 @@ class QAPISchema(object):
def _make_implicit_object_type(self, name, info, role, members):
if not members:
return None
+ # See also QAPISchemaObjectTypeMember._pretty_owner()
name = ':obj-%s-%s' % (name, role)
if not self.lookup_entity(name, QAPISchemaObjectType):
self._def_entity(QAPISchemaObjectType(name, info, None,
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 16/40] qapi: Detect collisions in C member names
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (14 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 15/40] qapi: Track owner of each object member Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 17/40] qapi: Fix c_name() munging Markus Armbruster
` (24 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Detect attempts to declare two object members that would result
in the same C member name, by keying the 'seen' dictionary off
of the C name rather than the qapi name. It also requires passing
info through the check_clash() methods.
This addresses a TODO and fixes the previously-broken
args-name-clash test. The resulting error message demonstrates
the utility of the .describe() method added previously. No change
to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-17-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 31 +++++++++++++++++++------------
tests/qapi-schema/args-name-clash.err | 1 +
tests/qapi-schema/args-name-clash.exit | 2 +-
tests/qapi-schema/args-name-clash.json | 5 ++---
tests/qapi-schema/args-name-clash.out | 6 ------
5 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 77d3e0a..4870326 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -977,20 +977,23 @@ class QAPISchemaObjectType(QAPISchemaType):
self.base = schema.lookup_type(self._base_name)
assert isinstance(self.base, QAPISchemaObjectType)
self.base.check(schema)
- self.base.check_clash(schema, seen)
+ self.base.check_clash(schema, self.info, seen)
for m in self.local_members:
m.check(schema)
- m.check_clash(seen)
+ m.check_clash(self.info, seen)
self.members = seen.values()
if self.variants:
self.variants.check(schema, seen)
assert self.variants.tag_member in self.members
- self.variants.check_clash(schema, seen)
+ self.variants.check_clash(schema, self.info, seen)
- def check_clash(self, schema, seen):
+ # Check that the members of this type do not cause duplicate JSON fields,
+ # and update seen to track the members seen so far. Report any errors
+ # on behalf of info, which is not necessarily self.info
+ def check_clash(self, schema, info, seen):
assert not self.variants # not implemented
for m in self.members:
- m.check_clash(seen)
+ m.check_clash(info, seen)
def is_implicit(self):
# See QAPISchema._make_implicit_object_type()
@@ -1036,10 +1039,13 @@ class QAPISchemaObjectTypeMember(object):
self.type = schema.lookup_type(self._type_name)
assert self.type
- def check_clash(self, seen):
- # TODO change key of seen from QAPI name to C name
- assert self.name not in seen
- seen[self.name] = self
+ def check_clash(self, info, seen):
+ cname = c_name(self.name)
+ if cname in seen:
+ raise QAPIExprError(info,
+ "%s collides with %s"
+ % (self.describe(), seen[cname].describe()))
+ seen[cname] = self
def _pretty_owner(self):
owner = self.owner
@@ -1080,7 +1086,8 @@ class QAPISchemaObjectTypeVariants(object):
def check(self, schema, seen):
if not self.tag_member: # flat union
- self.tag_member = seen[self.tag_name]
+ self.tag_member = seen[c_name(self.tag_name)]
+ assert self.tag_name == self.tag_member.name
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
v.check(schema)
@@ -1088,12 +1095,12 @@ class QAPISchemaObjectTypeVariants(object):
if isinstance(v.type, QAPISchemaObjectType):
v.type.check(schema)
- def check_clash(self, schema, seen):
+ def check_clash(self, schema, info, seen):
for v in self.variants:
# Reset seen map for each variant, since qapi names from one
# branch do not affect another branch
assert isinstance(v.type, QAPISchemaObjectType)
- v.type.check_clash(schema, dict(seen))
+ v.type.check_clash(schema, info, dict(seen))
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
diff --git a/tests/qapi-schema/args-name-clash.err b/tests/qapi-schema/args-name-clash.err
index e69de29..d953e8d 100644
--- a/tests/qapi-schema/args-name-clash.err
+++ b/tests/qapi-schema/args-name-clash.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops)
diff --git a/tests/qapi-schema/args-name-clash.exit b/tests/qapi-schema/args-name-clash.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/args-name-clash.exit
+++ b/tests/qapi-schema/args-name-clash.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/args-name-clash.json b/tests/qapi-schema/args-name-clash.json
index 9e8f889..61423cb 100644
--- a/tests/qapi-schema/args-name-clash.json
+++ b/tests/qapi-schema/args-name-clash.json
@@ -1,5 +1,4 @@
# C member name collision
-# FIXME - This parses, but fails to compile, because the C struct is given
-# two 'a_b' members. Either reject this at parse time, or munge the C names
-# to avoid the collision.
+# Reject members that clash when mapped to C names (we would have two 'a_b'
+# members).
{ 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }
diff --git a/tests/qapi-schema/args-name-clash.out b/tests/qapi-schema/args-name-clash.out
index 9b2f6e4..e69de29 100644
--- a/tests/qapi-schema/args-name-clash.out
+++ b/tests/qapi-schema/args-name-clash.out
@@ -1,6 +0,0 @@
-object :empty
-object :obj-oops-arg
- member a-b: str optional=False
- member a_b: str optional=False
-command oops :obj-oops-arg -> None
- gen=True success_response=True
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 17/40] qapi: Fix c_name() munging
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (15 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 16/40] qapi: Detect collisions in C member names Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 18/40] qapi: Remove dead visitor code Markus Armbruster
` (23 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
The method c_name() is supposed to do two different actions: munge
'-' into '_', and add a 'q_' prefix to ticklish names. But it did
these steps out of order, making it possible to submit input that
is not ticklish until after munging, where the output then lacked
the desired prefix.
The failure is exposed easily if you have a compiler that recognizes
C11 keywords, and try to name a member '_Thread-local', as it would
result in trying to compile the declaration 'uint64_t _Thread_local;'
which is not valid. However, this name violates our conventions
(ultimately, want to enforce that no qapi names start with single
underscore), so the test is slightly weaker by instead testing
'wchar-t'; the declaration 'uint64_t wchar_t;' is valid in C (where
wchar_t is only a typedef) but would fail with a C++ compiler (where
it is a keyword).
Fix things by reversing the order of actions within c_name().
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-18-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 3 ++-
tests/qapi-schema/qapi-schema-test.json | 5 +++--
tests/qapi-schema/qapi-schema-test.out | 1 +
tests/test-qmp-commands.c | 4 ++++
4 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 4870326..d2ce9b3 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1482,10 +1482,11 @@ def c_name(name, protect=True):
'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
# namespace pollution:
polluted_words = set(['unix', 'errno'])
+ name = name.translate(c_name_trans)
if protect and (name in c89_words | c99_words | c11_words | gcc_words
| cpp_words | polluted_words):
return "q_" + name
- return name.translate(c_name_trans)
+ return name
eatspace = '\033EATSPACE.'
pointer_suffix = ' *' + eatspace
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 44638da..4b89527 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -152,12 +152,13 @@
{ 'event': 'EVENT_D',
'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } }
-# test that we correctly compile downstream extensions
+# test that we correctly compile downstream extensions, as well as munge
+# ticklish names
{ 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] }
{ 'struct': '__org.qemu_x-Base',
'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } }
{ 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base',
- 'data': { '__org.qemu_x-member2': 'str' } }
+ 'data': { '__org.qemu_x-member2': 'str', '*wchar-t': 'int' } }
{ 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } }
{ 'struct': '__org.qemu_x-Struct2',
'data': { 'array': ['__org.qemu_x-Union1'] } }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 786024e..0724a9f 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -185,6 +185,7 @@ enum __org.qemu_x-Enum ['__org.qemu_x-value']
object __org.qemu_x-Struct
base __org.qemu_x-Base
member __org.qemu_x-member2: str optional=False
+ member wchar-t: int optional=True
object __org.qemu_x-Struct2
member array: __org.qemu_x-Union1List optional=False
object __org.qemu_x-Union1
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 888fb5f..9f35b80 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -65,6 +65,10 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
ret->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
ret->u.__org_qemu_x_branch = strdup("blah1");
+ /* Also test that 'wchar-t' was munged to 'q_wchar_t' */
+ if (b && b->value && !b->value->has_q_wchar_t) {
+ b->value->q_wchar_t = 1;
+ }
return ret;
}
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 18/40] qapi: Remove dead visitor code
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (16 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 17/40] qapi: Fix c_name() munging Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 19/40] blkdebug: Merge hand-rolled and qapi BlkdebugEvent enum Markus Armbruster
` (22 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Commit cbc95538 removed unused start_handle() and end_handle(),
but forgot to remove their declarations.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/visitor.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index cfc19a6..a2ad66c 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -27,9 +27,6 @@ typedef struct GenericList
struct GenericList *next;
} GenericList;
-void visit_start_handle(Visitor *v, void **obj, const char *kind,
- const char *name, Error **errp);
-void visit_end_handle(Visitor *v, Error **errp);
void visit_start_struct(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp);
void visit_end_struct(Visitor *v, Error **errp);
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 19/40] blkdebug: Merge hand-rolled and qapi BlkdebugEvent enum
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (17 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 18/40] qapi: Remove dead visitor code Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 20/40] blkdebug: Avoid '.' in enum values Markus Armbruster
` (21 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf
From: Eric Blake <eblake@redhat.com>
No need to keep two separate enums, where editing one is likely
to forget the other. Now that we can specify a qapi enum prefix,
we don't even have to change the bulk of the uses.
get_event_by_name() could perhaps be replaced by qapi_enum_parse(),
but I left that for another day.
CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
block.c | 2 +-
block/blkdebug.c | 79 +++++++----------------------------------------
docs/blkdebug.txt | 7 +++--
include/block/block.h | 62 +------------------------------------
include/block/block_int.h | 2 +-
qapi/block-core.json | 4 ++-
6 files changed, 21 insertions(+), 135 deletions(-)
diff --git a/block.c b/block.c
index 3a7324b..9971976 100644
--- a/block.c
+++ b/block.c
@@ -2851,7 +2851,7 @@ ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs)
return NULL;
}
-void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
+void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{
if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) {
return;
diff --git a/block/blkdebug.c b/block/blkdebug.c
index dee3a0e..6bcb7fa 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -36,7 +36,7 @@ typedef struct BDRVBlkdebugState {
int state;
int new_state;
- QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
+ QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
} BDRVBlkdebugState;
@@ -64,7 +64,7 @@ enum {
};
typedef struct BlkdebugRule {
- BlkDebugEvent event;
+ BlkdebugEvent event;
int action;
int state;
union {
@@ -143,69 +143,12 @@ static QemuOptsList *config_groups[] = {
NULL
};
-static const char *event_names[BLKDBG_EVENT_MAX] = {
- [BLKDBG_L1_UPDATE] = "l1_update",
- [BLKDBG_L1_GROW_ALLOC_TABLE] = "l1_grow.alloc_table",
- [BLKDBG_L1_GROW_WRITE_TABLE] = "l1_grow.write_table",
- [BLKDBG_L1_GROW_ACTIVATE_TABLE] = "l1_grow.activate_table",
-
- [BLKDBG_L2_LOAD] = "l2_load",
- [BLKDBG_L2_UPDATE] = "l2_update",
- [BLKDBG_L2_UPDATE_COMPRESSED] = "l2_update_compressed",
- [BLKDBG_L2_ALLOC_COW_READ] = "l2_alloc.cow_read",
- [BLKDBG_L2_ALLOC_WRITE] = "l2_alloc.write",
-
- [BLKDBG_READ_AIO] = "read_aio",
- [BLKDBG_READ_BACKING_AIO] = "read_backing_aio",
- [BLKDBG_READ_COMPRESSED] = "read_compressed",
-
- [BLKDBG_WRITE_AIO] = "write_aio",
- [BLKDBG_WRITE_COMPRESSED] = "write_compressed",
-
- [BLKDBG_VMSTATE_LOAD] = "vmstate_load",
- [BLKDBG_VMSTATE_SAVE] = "vmstate_save",
-
- [BLKDBG_COW_READ] = "cow_read",
- [BLKDBG_COW_WRITE] = "cow_write",
-
- [BLKDBG_REFTABLE_LOAD] = "reftable_load",
- [BLKDBG_REFTABLE_GROW] = "reftable_grow",
- [BLKDBG_REFTABLE_UPDATE] = "reftable_update",
-
- [BLKDBG_REFBLOCK_LOAD] = "refblock_load",
- [BLKDBG_REFBLOCK_UPDATE] = "refblock_update",
- [BLKDBG_REFBLOCK_UPDATE_PART] = "refblock_update_part",
- [BLKDBG_REFBLOCK_ALLOC] = "refblock_alloc",
- [BLKDBG_REFBLOCK_ALLOC_HOOKUP] = "refblock_alloc.hookup",
- [BLKDBG_REFBLOCK_ALLOC_WRITE] = "refblock_alloc.write",
- [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS] = "refblock_alloc.write_blocks",
- [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE] = "refblock_alloc.write_table",
- [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE] = "refblock_alloc.switch_table",
-
- [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
- [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
- [BLKDBG_CLUSTER_FREE] = "cluster_free",
-
- [BLKDBG_FLUSH_TO_OS] = "flush_to_os",
- [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk",
-
- [BLKDBG_PWRITEV_RMW_HEAD] = "pwritev_rmw.head",
- [BLKDBG_PWRITEV_RMW_AFTER_HEAD] = "pwritev_rmw.after_head",
- [BLKDBG_PWRITEV_RMW_TAIL] = "pwritev_rmw.tail",
- [BLKDBG_PWRITEV_RMW_AFTER_TAIL] = "pwritev_rmw.after_tail",
- [BLKDBG_PWRITEV] = "pwritev",
- [BLKDBG_PWRITEV_ZERO] = "pwritev_zero",
- [BLKDBG_PWRITEV_DONE] = "pwritev_done",
-
- [BLKDBG_EMPTY_IMAGE_PREPARE] = "empty_image_prepare",
-};
-
-static int get_event_by_name(const char *name, BlkDebugEvent *event)
+static int get_event_by_name(const char *name, BlkdebugEvent *event)
{
int i;
- for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
- if (!strcmp(event_names[i], name)) {
+ for (i = 0; i < BLKDBG_MAX; i++) {
+ if (!strcmp(BlkdebugEvent_lookup[i], name)) {
*event = i;
return 0;
}
@@ -224,7 +167,7 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
struct add_rule_data *d = opaque;
BDRVBlkdebugState *s = d->s;
const char* event_name;
- BlkDebugEvent event;
+ BlkdebugEvent event;
struct BlkdebugRule *rule;
/* Find the right event for the rule */
@@ -564,7 +507,7 @@ static void blkdebug_close(BlockDriverState *bs)
BlkdebugRule *rule, *next;
int i;
- for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
+ for (i = 0; i < BLKDBG_MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
remove_rule(rule);
}
@@ -627,13 +570,13 @@ static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
return injected;
}
-static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
+static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{
BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule, *next;
bool injected;
- assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
+ assert((int)event >= 0 && event < BLKDBG_MAX);
injected = false;
s->new_state = s->state;
@@ -648,7 +591,7 @@ static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
{
BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule;
- BlkDebugEvent blkdebug_event;
+ BlkdebugEvent blkdebug_event;
if (get_event_by_name(event, &blkdebug_event) < 0) {
return -ENOENT;
@@ -690,7 +633,7 @@ static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
BlkdebugRule *rule, *next;
int i, ret = -ENOENT;
- for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
+ for (i = 0; i < BLKDBG_MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
if (rule->action == ACTION_SUSPEND &&
!strcmp(rule->options.suspend.tag, tag)) {
diff --git a/docs/blkdebug.txt b/docs/blkdebug.txt
index b67a36d..43d8e8f 100644
--- a/docs/blkdebug.txt
+++ b/docs/blkdebug.txt
@@ -1,6 +1,6 @@
Block I/O error injection using blkdebug
----------------------------------------
-Copyright (C) 2014 Red Hat Inc
+Copyright (C) 2014-2015 Red Hat Inc
This work is licensed under the terms of the GNU GPL, version 2 or later. See
the COPYING file in the top-level directory.
@@ -92,8 +92,9 @@ The core events are:
flush_to_disk - flush the host block device's disk cache
-See block/blkdebug.c:event_names[] for the full list of events. You may need
-to grep block driver source code to understand the meaning of specific events.
+See qapi/block-core.json:BlkdebugEvent for the full list of events.
+You may need to grep block driver source code to understand the
+meaning of specific events.
State transitions
-----------------
diff --git a/include/block/block.h b/include/block/block.h
index 3477328..d048bbf 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -520,66 +520,6 @@ void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason);
bool bdrv_op_blocker_is_empty(BlockDriverState *bs);
-typedef enum {
- BLKDBG_L1_UPDATE,
-
- BLKDBG_L1_GROW_ALLOC_TABLE,
- BLKDBG_L1_GROW_WRITE_TABLE,
- BLKDBG_L1_GROW_ACTIVATE_TABLE,
-
- BLKDBG_L2_LOAD,
- BLKDBG_L2_UPDATE,
- BLKDBG_L2_UPDATE_COMPRESSED,
- BLKDBG_L2_ALLOC_COW_READ,
- BLKDBG_L2_ALLOC_WRITE,
-
- BLKDBG_READ_AIO,
- BLKDBG_READ_BACKING_AIO,
- BLKDBG_READ_COMPRESSED,
-
- BLKDBG_WRITE_AIO,
- BLKDBG_WRITE_COMPRESSED,
-
- BLKDBG_VMSTATE_LOAD,
- BLKDBG_VMSTATE_SAVE,
-
- BLKDBG_COW_READ,
- BLKDBG_COW_WRITE,
-
- BLKDBG_REFTABLE_LOAD,
- BLKDBG_REFTABLE_GROW,
- BLKDBG_REFTABLE_UPDATE,
-
- BLKDBG_REFBLOCK_LOAD,
- BLKDBG_REFBLOCK_UPDATE,
- BLKDBG_REFBLOCK_UPDATE_PART,
- BLKDBG_REFBLOCK_ALLOC,
- BLKDBG_REFBLOCK_ALLOC_HOOKUP,
- BLKDBG_REFBLOCK_ALLOC_WRITE,
- BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS,
- BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE,
- BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE,
-
- BLKDBG_CLUSTER_ALLOC,
- BLKDBG_CLUSTER_ALLOC_BYTES,
- BLKDBG_CLUSTER_FREE,
-
- BLKDBG_FLUSH_TO_OS,
- BLKDBG_FLUSH_TO_DISK,
-
- BLKDBG_PWRITEV_RMW_HEAD,
- BLKDBG_PWRITEV_RMW_AFTER_HEAD,
- BLKDBG_PWRITEV_RMW_TAIL,
- BLKDBG_PWRITEV_RMW_AFTER_TAIL,
- BLKDBG_PWRITEV,
- BLKDBG_PWRITEV_ZERO,
- BLKDBG_PWRITEV_DONE,
-
- BLKDBG_EMPTY_IMAGE_PREPARE,
-
- BLKDBG_EVENT_MAX,
-} BlkDebugEvent;
-
#define BLKDBG_EVENT(child, evt) \
do { \
if (child) { \
@@ -587,7 +527,7 @@ typedef enum {
} \
} while (0)
-void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
+void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event);
int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
const char *tag);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 4012e36..66e208d 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -244,7 +244,7 @@ struct BlockDriver {
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb);
- void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event);
+ void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event);
/* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5a23165..18ba6a6 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1776,8 +1776,10 @@
# @BlkdebugEvent
#
# Trigger events supported by blkdebug.
+#
+# Since: 2.0
##
-{ 'enum': 'BlkdebugEvent',
+{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
'data': [ 'l1_update', 'l1_grow.alloc_table', 'l1_grow.write_table',
'l1_grow.activate_table', 'l2_load', 'l2_update',
'l2_update_compressed', 'l2_alloc.cow_read', 'l2_alloc.write',
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 20/40] blkdebug: Avoid '.' in enum values
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (18 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 19/40] blkdebug: Merge hand-rolled and qapi BlkdebugEvent enum Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 21/40] qapi: Tighten the regex on valid names Markus Armbruster
` (20 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf
From: Eric Blake <eblake@redhat.com>
Our qapi conventions document that '.' should only be used in
the prefix of downstream names. BlkdebugEvent was a lone
exception to this. Changing this is not backwards compatible
to the 'blockdev-add' QMP command; however, that command is
not yet fully stable. It can also be argued that the testsuite
is the biggest user of blkdebug, and that any other user can
be taught to deal with the change by paying attention to
introspection results.
Done with:
$ for str in \
l1_grow.{alloc,write,activate}_table \
l2_alloc.{cow_read,write} \
refblock_alloc.{hookup,write,write_blocks,write_table,switch_table} \
pwritev_rmw.{head,after_head,tail,after_tail}; do
str1=$(echo "$str" | sed 's/\./\\./')
str2=$(echo "$str" | sed 's/\./_/')
git grep -l "$str1" | xargs -r sed -i "s/$str1/$str2/g"
done
followed by a manual touchup to test 77 to keep the test working.
Reported-by: Markus Armbruster <armbru@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-21-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
qapi/block-core.json | 16 ++++----
tests/qemu-iotests/026 | 18 ++++-----
tests/qemu-iotests/026.out | 80 +++++++++++++++++++-------------------
tests/qemu-iotests/026.out.nocache | 80 +++++++++++++++++++-------------------
tests/qemu-iotests/077 | 24 ++++++------
5 files changed, 109 insertions(+), 109 deletions(-)
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 18ba6a6..1a5d9ce 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1780,19 +1780,19 @@
# Since: 2.0
##
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
- 'data': [ 'l1_update', 'l1_grow.alloc_table', 'l1_grow.write_table',
- 'l1_grow.activate_table', 'l2_load', 'l2_update',
- 'l2_update_compressed', 'l2_alloc.cow_read', 'l2_alloc.write',
+ 'data': [ 'l1_update', 'l1_grow_alloc_table', 'l1_grow_write_table',
+ 'l1_grow_activate_table', 'l2_load', 'l2_update',
+ 'l2_update_compressed', 'l2_alloc_cow_read', 'l2_alloc_write',
'read_aio', 'read_backing_aio', 'read_compressed', 'write_aio',
'write_compressed', 'vmstate_load', 'vmstate_save', 'cow_read',
'cow_write', 'reftable_load', 'reftable_grow', 'reftable_update',
'refblock_load', 'refblock_update', 'refblock_update_part',
- 'refblock_alloc', 'refblock_alloc.hookup', 'refblock_alloc.write',
- 'refblock_alloc.write_blocks', 'refblock_alloc.write_table',
- 'refblock_alloc.switch_table', 'cluster_alloc',
+ 'refblock_alloc', 'refblock_alloc_hookup', 'refblock_alloc_write',
+ 'refblock_alloc_write_blocks', 'refblock_alloc_write_table',
+ 'refblock_alloc_switch_table', 'cluster_alloc',
'cluster_alloc_bytes', 'cluster_free', 'flush_to_os',
- 'flush_to_disk', 'pwritev_rmw.head', 'pwritev_rmw.after_head',
- 'pwritev_rmw.tail', 'pwritev_rmw.after_tail', 'pwritev',
+ 'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head',
+ 'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] }
##
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index 0fc3244..ba1047c 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -66,7 +66,7 @@ for event in \
\
l2_load \
l2_update \
- l2_alloc.write \
+ l2_alloc_write \
\
write_aio \
\
@@ -126,11 +126,11 @@ CLUSTER_SIZE=512
for event in \
- refblock_alloc.hookup \
- refblock_alloc.write \
- refblock_alloc.write_blocks \
- refblock_alloc.write_table \
- refblock_alloc.switch_table \
+ refblock_alloc_hookup \
+ refblock_alloc_write \
+ refblock_alloc_write_blocks \
+ refblock_alloc_write_table \
+ refblock_alloc_switch_table \
do
@@ -170,9 +170,9 @@ CLUSTER_SIZE=1024
for event in \
- l1_grow.alloc_table \
- l1_grow.write_table \
- l1_grow.activate_table \
+ l1_grow_alloc_table \
+ l1_grow_write_table \
+ l1_grow_activate_table \
do
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index 5e964fb..d84d82c 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -195,24 +195,24 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: on; write
+Event: l2_alloc_write; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
+Event: l2_alloc_write; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: off; write
+Event: l2_alloc_write; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
+Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
@@ -221,24 +221,24 @@ write failed: Input/output error
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: on; write
+Event: l2_alloc_write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
+Event: l2_alloc_write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: off; write
+Event: l2_alloc_write; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
+Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -490,17 +490,17 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -509,7 +509,7 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -518,41 +518,41 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_write; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -561,7 +561,7 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -570,17 +570,17 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -589,7 +589,7 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -598,17 +598,17 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -617,7 +617,7 @@ write failed: No space left on device
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
@@ -629,60 +629,60 @@ This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
+Event: l1_grow_alloc_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
+Event: l1_grow_alloc_table; errno: 5; imm: off; once: off
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
+Event: l1_grow_alloc_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
+Event: l1_grow_alloc_table; errno: 28; imm: off; once: off
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 5; imm: off; once: on
+Event: l1_grow_write_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 5; imm: off; once: off
+Event: l1_grow_write_table; errno: 5; imm: off; once: off
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 28; imm: off; once: on
+Event: l1_grow_write_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 28; imm: off; once: off
+Event: l1_grow_write_table; errno: 28; imm: off; once: off
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 5; imm: off; once: on
+Event: l1_grow_activate_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 5; imm: off; once: off
+Event: l1_grow_activate_table; errno: 5; imm: off; once: off
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
@@ -691,12 +691,12 @@ write failed: Input/output error
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 28; imm: off; once: on
+Event: l1_grow_activate_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 28; imm: off; once: off
+Event: l1_grow_activate_table; errno: 28; imm: off; once: off
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache
index c9d242e..a5000d5 100644
--- a/tests/qemu-iotests/026.out.nocache
+++ b/tests/qemu-iotests/026.out.nocache
@@ -179,44 +179,44 @@ wrote 131072/131072 bytes at offset 0
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: on; write
+Event: l2_alloc_write; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
+Event: l2_alloc_write; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: off; write
+Event: l2_alloc_write; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
+Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: on; write
+Event: l2_alloc_write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
+Event: l2_alloc_write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: off; write
+Event: l2_alloc_write; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
+Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
@@ -426,116 +426,116 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write
write failed: No space left on device
55 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
251 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_write; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
+Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
@@ -545,64 +545,64 @@ This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
+Event: l1_grow_alloc_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
+Event: l1_grow_alloc_table; errno: 5; imm: off; once: off
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
+Event: l1_grow_alloc_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
+Event: l1_grow_alloc_table; errno: 28; imm: off; once: off
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 5; imm: off; once: on
+Event: l1_grow_write_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 5; imm: off; once: off
+Event: l1_grow_write_table; errno: 5; imm: off; once: off
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 28; imm: off; once: on
+Event: l1_grow_write_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.write_table; errno: 28; imm: off; once: off
+Event: l1_grow_write_table; errno: 28; imm: off; once: off
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 5; imm: off; once: on
+Event: l1_grow_activate_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 5; imm: off; once: off
+Event: l1_grow_activate_table; errno: 5; imm: off; once: off
write failed: Input/output error
96 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 28; imm: off; once: on
+Event: l1_grow_activate_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
-Event: l1_grow.activate_table; errno: 28; imm: off; once: off
+Event: l1_grow_activate_table; errno: 28; imm: off; once: off
write failed: No space left on device
96 leaked clusters were found on the image.
diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077
index 42a9085..8a7223f 100755
--- a/tests/qemu-iotests/077
+++ b/tests/qemu-iotests/077
@@ -63,7 +63,7 @@ EOF
off=0x1000
for ev in "head" "after_head" "tail" "after_tail"; do
cat <<EOF
-break pwritev_rmw.$ev A
+break pwritev_rmw_$ev A
aio_write -P 10 $((off + 0x200)) 0x200
wait_break A
aio_write -P 11 $((off + 0x400)) 0x200
@@ -76,7 +76,7 @@ done
# Chained dependencies
cat <<EOF
-break pwritev_rmw.after_tail A
+break pwritev_rmw_after_tail A
aio_write -P 10 0x5000 0x200
wait_break A
aio_write -P 11 0x5200 0x200
@@ -93,10 +93,10 @@ EOF
# Overlapping multiple requests
cat <<EOF
-break pwritev_rmw.after_tail A
+break pwritev_rmw_after_tail A
aio_write -P 10 0x6000 0x200
wait_break A
-break pwritev_rmw.after_head B
+break pwritev_rmw_after_head B
aio_write -P 10 0x7e00 0x200
wait_break B
aio_write -P 11 0x6800 0x1000
@@ -107,10 +107,10 @@ aio_flush
EOF
cat <<EOF
-break pwritev_rmw.after_tail A
+break pwritev_rmw_after_tail A
aio_write -P 10 0x8000 0x200
wait_break A
-break pwritev_rmw.after_head B
+break pwritev_rmw_after_head B
aio_write -P 10 0x9e00 0x200
wait_break B
aio_write -P 11 0x8800 0x1000
@@ -121,11 +121,11 @@ aio_flush
EOF
cat <<EOF
-break pwritev_rmw.after_tail A
+break pwritev_rmw_after_tail A
aio_write -P 10 0xa000 0x200
wait_break A
aio_write -P 11 0xa800 0x1000
-break pwritev_rmw.after_head B
+break pwritev_rmw_after_head B
aio_write -P 10 0xbe00 0x200
wait_break B
resume A
@@ -135,11 +135,11 @@ aio_flush
EOF
cat <<EOF
-break pwritev_rmw.after_tail A
+break pwritev_rmw_after_tail A
aio_write -P 10 0xc000 0x200
wait_break A
aio_write -P 11 0xc800 0x1000
-break pwritev_rmw.after_head B
+break pwritev_rmw_after_head B
aio_write -P 10 0xde00 0x200
wait_break B
resume B
@@ -150,7 +150,7 @@ EOF
# Only RMW for the tail part
cat <<EOF
-break pwritev_rmw.after_tail A
+break pwritev_rmw_after_tail A
aio_write -P 10 0xe000 0x1800
wait_break A
aio_write -P 11 0xf000 0xc00
@@ -163,7 +163,7 @@ cat <<EOF
break pwritev A
aio_write -P 10 0x10000 0x800
wait_break A
-break pwritev_rmw.after_tail B
+break pwritev_rmw_after_tail B
aio_write -P 11 0x10000 0x400
break pwritev_done C
resume A
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 21/40] qapi: Tighten the regex on valid names
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (19 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 20/40] blkdebug: Avoid '.' in enum values Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 22/40] qapi: Don't let implicit enum MAX member collide Markus Armbruster
` (19 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
We already documented that qapi names should match specific
patterns (such as starting with a letter unless it was an enum
value or a downstream extension). Tighten that from a suggestion
into a hard requirement, which frees up names beginning with a
single underscore for qapi internal usage.
The tighter regex doesn't forbid everything insane that a user
could provide (for example, a user could name a type 'Foo-lookup'
to collide with the generated 'Foo_lookup[]' for an enum 'Foo'),
but does a good job at protecting the most obvious uses, and
also happens to reserve single leading underscore for later use.
The handling of enum values starting with a digit is tricky:
commit 9fb081e introduced a subtle bug by using c_name() on
a munged value, which would allow an enum to include the
member 'q-int' in spite of our reservation. Furthermore,
munging with a leading '_' would fail our tighter regex. So
fix it by only munging for leading digits (which are never
ticklish in c_name()) and by using a different prefix (I
picked 'D', although any letter should do).
Add new tests, reserved-member-underscore and reserved-enum-q,
to demonstrate the tighter checking.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-22-git-send-email-eblake@redhat.com>
Message-Id: <1447883135-18020-1-git-send-email-eblake@redhat.com>
[Eric's fixup squashed in]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
docs/qapi-code-gen.txt | 22 +++++++++++-----------
scripts/qapi.py | 12 +++++++-----
tests/Makefile | 2 ++
tests/qapi-schema/reserved-enum-q.err | 1 +
tests/qapi-schema/reserved-enum-q.exit | 1 +
tests/qapi-schema/reserved-enum-q.json | 4 ++++
tests/qapi-schema/reserved-enum-q.out | 0
tests/qapi-schema/reserved-member-underscore.err | 1 +
tests/qapi-schema/reserved-member-underscore.exit | 1 +
tests/qapi-schema/reserved-member-underscore.json | 4 ++++
tests/qapi-schema/reserved-member-underscore.out | 0
11 files changed, 32 insertions(+), 16 deletions(-)
create mode 100644 tests/qapi-schema/reserved-enum-q.err
create mode 100644 tests/qapi-schema/reserved-enum-q.exit
create mode 100644 tests/qapi-schema/reserved-enum-q.json
create mode 100644 tests/qapi-schema/reserved-enum-q.out
create mode 100644 tests/qapi-schema/reserved-member-underscore.err
create mode 100644 tests/qapi-schema/reserved-member-underscore.exit
create mode 100644 tests/qapi-schema/reserved-member-underscore.json
create mode 100644 tests/qapi-schema/reserved-member-underscore.out
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index ceb9a78..32cc68f 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -118,17 +118,17 @@ tracking optional fields.
Any name (command, event, type, field, or enum value) beginning with
"x-" is marked experimental, and may be withdrawn or changed
-incompatibly in a future release. Downstream vendors may add
-extensions; such extensions should begin with a prefix matching
-"__RFQDN_" (for the reverse-fully-qualified-domain-name of the
-vendor), even if the rest of the name uses dash (example:
-__com.redhat_drive-mirror). Other than downstream extensions (with
-leading underscore and the use of dots), all names should begin with a
-letter, and contain only ASCII letters, digits, dash, and underscore.
-Names beginning with 'q_' are reserved for the generator: QMP names
-that resemble C keywords or other problematic strings will be munged
-in C to use this prefix. For example, a field named "default" in
-qapi becomes "q_default" in the generated C code.
+incompatibly in a future release. All names must begin with a letter,
+and contain only ASCII letters, digits, dash, and underscore. There
+are two exceptions: enum values may start with a digit, and any
+extensions added by downstream vendors should start with a prefix
+matching "__RFQDN_" (for the reverse-fully-qualified-domain-name of
+the vendor), even if the rest of the name uses dash (example:
+__com.redhat_drive-mirror). Names beginning with 'q_' are reserved
+for the generator: QMP names that resemble C keywords or other
+problematic strings will be munged in C to use this prefix. For
+example, a field named "default" in qapi becomes "q_default" in the
+generated C code.
In the rest of this document, usage lines are given for each
expression type, with literal strings written in lower case and
diff --git a/scripts/qapi.py b/scripts/qapi.py
index d2ce9b3..3e5caa8 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -353,9 +353,11 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type)
-# FIXME should enforce "other than downstream extensions [...], all
-# names should begin with a letter".
-valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
+# Names must be letters, numbers, -, and _. They must start with letter,
+# except for downstream extensions which must start with __RFQDN_.
+# Dots are only valid in the downstream extension prefix.
+valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
+ '[a-zA-Z][a-zA-Z0-9_-]*$')
def check_name(expr_info, source, name, allow_optional=False,
@@ -374,8 +376,8 @@ def check_name(expr_info, source, name, allow_optional=False,
% (source, name))
# Enum members can start with a digit, because the generated C
# code always prefixes it with the enum name
- if enum_member:
- membername = '_' + membername
+ if enum_member and membername[0].isdigit():
+ membername = 'D' + membername
# Reserve the entire 'q_' namespace for c_name()
if not valid_name.match(membername) or \
c_name(membername, False).startswith('q_'):
diff --git a/tests/Makefile b/tests/Makefile
index 6518ef9..2f6b234 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -318,9 +318,11 @@ qapi-schema += redefined-command.json
qapi-schema += redefined-event.json
qapi-schema += redefined-type.json
qapi-schema += reserved-command-q.json
+qapi-schema += reserved-enum-q.json
qapi-schema += reserved-member-has.json
qapi-schema += reserved-member-q.json
qapi-schema += reserved-member-u.json
+qapi-schema += reserved-member-underscore.json
qapi-schema += reserved-type-kind.json
qapi-schema += reserved-type-list.json
qapi-schema += returns-alternate.json
diff --git a/tests/qapi-schema/reserved-enum-q.err b/tests/qapi-schema/reserved-enum-q.err
new file mode 100644
index 0000000..e1c3480
--- /dev/null
+++ b/tests/qapi-schema/reserved-enum-q.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-enum-q.json:4: Member of enum 'Foo' uses invalid name 'q-Unix'
diff --git a/tests/qapi-schema/reserved-enum-q.exit b/tests/qapi-schema/reserved-enum-q.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/reserved-enum-q.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/reserved-enum-q.json b/tests/qapi-schema/reserved-enum-q.json
new file mode 100644
index 0000000..3593a76
--- /dev/null
+++ b/tests/qapi-schema/reserved-enum-q.json
@@ -0,0 +1,4 @@
+# C entity name collision
+# We reject names like 'q-unix', because they can collide with the mangled
+# name for 'unix' in generated C.
+{ 'enum': 'Foo', 'data': [ 'unix', 'q-Unix' ] }
diff --git a/tests/qapi-schema/reserved-enum-q.out b/tests/qapi-schema/reserved-enum-q.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/reserved-member-underscore.err b/tests/qapi-schema/reserved-member-underscore.err
new file mode 100644
index 0000000..65ff0da
--- /dev/null
+++ b/tests/qapi-schema/reserved-member-underscore.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member-underscore.json:4: Member of 'data' for struct 'Oops' uses invalid name '_oops'
diff --git a/tests/qapi-schema/reserved-member-underscore.exit b/tests/qapi-schema/reserved-member-underscore.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/reserved-member-underscore.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/reserved-member-underscore.json b/tests/qapi-schema/reserved-member-underscore.json
new file mode 100644
index 0000000..4a3a017
--- /dev/null
+++ b/tests/qapi-schema/reserved-member-underscore.json
@@ -0,0 +1,4 @@
+# C member name collision
+# We reject use of a single leading underscore in all names (names must
+# begin with a letter or a downstream extension double-underscore prefix).
+{ 'struct': 'Oops', 'data': { '_oops': 'str' } }
diff --git a/tests/qapi-schema/reserved-member-underscore.out b/tests/qapi-schema/reserved-member-underscore.out
new file mode 100644
index 0000000..e69de29
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 22/40] qapi: Don't let implicit enum MAX member collide
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (20 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 21/40] qapi: Tighten the regex on valid names Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 23/40] qapi: Remove obsolete tests for MAX collision Markus Armbruster
` (18 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
block/blkdebug.c | 10 +++++-----
block/parallels.c | 4 ++--
block/qcow2.c | 2 +-
block/quorum.c | 2 +-
block/raw-posix.c | 2 +-
blockdev.c | 2 +-
docs/qapi-code-gen.txt | 4 ++--
hmp.c | 14 +++++++-------
hw/char/escc.c | 2 +-
hw/i386/pc_piix.c | 2 +-
hw/i386/pc_q35.c | 2 +-
hw/input/hid.c | 2 +-
hw/input/ps2.c | 2 +-
hw/input/virtio-input-hid.c | 8 ++++----
include/migration/migration.h | 4 ++--
migration/migration.c | 4 ++--
monitor.c | 14 +++++++-------
net/net.c | 4 ++--
qemu-nbd.c | 2 +-
replay/replay-input.c | 8 ++++----
scripts/qapi.py | 6 +++---
tests/test-qmp-output-visitor.c | 6 +++---
tests/test-string-output-visitor.c | 4 ++--
tpm.c | 10 +++++-----
ui/cocoa.m | 2 +-
ui/console.c | 2 +-
ui/input-keymap.c | 4 ++--
ui/input-legacy.c | 6 +++---
ui/input.c | 6 +++---
ui/sdl.c | 2 +-
ui/sdl2.c | 2 +-
ui/spice-input.c | 2 +-
ui/vnc.c | 2 +-
vl.c | 18 +++++++++---------
34 files changed, 83 insertions(+), 83 deletions(-)
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 6bcb7fa..59c61eb 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -36,7 +36,7 @@ typedef struct BDRVBlkdebugState {
int state;
int new_state;
- QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_MAX];
+ QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
} BDRVBlkdebugState;
@@ -147,7 +147,7 @@ static int get_event_by_name(const char *name, BlkdebugEvent *event)
{
int i;
- for (i = 0; i < BLKDBG_MAX; i++) {
+ for (i = 0; i < BLKDBG__MAX; i++) {
if (!strcmp(BlkdebugEvent_lookup[i], name)) {
*event = i;
return 0;
@@ -507,7 +507,7 @@ static void blkdebug_close(BlockDriverState *bs)
BlkdebugRule *rule, *next;
int i;
- for (i = 0; i < BLKDBG_MAX; i++) {
+ for (i = 0; i < BLKDBG__MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
remove_rule(rule);
}
@@ -576,7 +576,7 @@ static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
struct BlkdebugRule *rule, *next;
bool injected;
- assert((int)event >= 0 && event < BLKDBG_MAX);
+ assert((int)event >= 0 && event < BLKDBG__MAX);
injected = false;
s->new_state = s->state;
@@ -633,7 +633,7 @@ static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
BlkdebugRule *rule, *next;
int i, ret = -ENOENT;
- for (i = 0; i < BLKDBG_MAX; i++) {
+ for (i = 0; i < BLKDBG__MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
if (rule->action == ACTION_SUSPEND &&
!strcmp(rule->options.suspend.tag, tag)) {
diff --git a/block/parallels.c b/block/parallels.c
index f689fde..e4a56a5 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -61,7 +61,7 @@ typedef struct ParallelsHeader {
typedef enum ParallelsPreallocMode {
PRL_PREALLOC_MODE_FALLOCATE = 0,
PRL_PREALLOC_MODE_TRUNCATE = 1,
- PRL_PREALLOC_MODE_MAX = 2,
+ PRL_PREALLOC_MODE__MAX = 2,
} ParallelsPreallocMode;
static const char *prealloc_mode_lookup[] = {
@@ -660,7 +660,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS);
buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE);
s->prealloc_mode = qapi_enum_parse(prealloc_mode_lookup, buf,
- PRL_PREALLOC_MODE_MAX, PRL_PREALLOC_MODE_FALLOCATE, &local_err);
+ PRL_PREALLOC_MODE__MAX, PRL_PREALLOC_MODE_FALLOCATE, &local_err);
g_free(buf);
if (local_err != NULL) {
goto fail_options;
diff --git a/block/qcow2.c b/block/qcow2.c
index 88f56c8..5b59fa3 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2269,7 +2269,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
DEFAULT_CLUSTER_SIZE);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
- PREALLOC_MODE_MAX, PREALLOC_MODE_OFF,
+ PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/block/quorum.c b/block/quorum.c
index b9ba028..d162459 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -847,7 +847,7 @@ static int parse_read_pattern(const char *opt)
return QUORUM_READ_PATTERN_QUORUM;
}
- for (i = 0; i < QUORUM_READ_PATTERN_MAX; i++) {
+ for (i = 0; i < QUORUM_READ_PATTERN__MAX; i++) {
if (!strcmp(opt, QuorumReadPattern_lookup[i])) {
return i;
}
diff --git a/block/raw-posix.c b/block/raw-posix.c
index d9162fd..ffeebe1 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1636,7 +1636,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
- PREALLOC_MODE_MAX, PREALLOC_MODE_OFF,
+ PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
&local_err);
g_free(buf);
if (local_err) {
diff --git a/blockdev.c b/blockdev.c
index 80932e8..13eaa77 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -454,7 +454,7 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
*detect_zeroes =
qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
qemu_opt_get(opts, "detect-zeroes"),
- BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
+ BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
&local_error);
if (local_error) {
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 32cc68f..2becba9 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -1053,7 +1053,7 @@ Example:
const char *const example_QAPIEvent_lookup[] = {
[EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT",
- [EXAMPLE_QAPI_EVENT_MAX] = NULL,
+ [EXAMPLE_QAPI_EVENT__MAX] = NULL,
};
$ cat qapi-generated/example-qapi-event.h
[Uninteresting stuff omitted...]
@@ -1070,7 +1070,7 @@ Example:
typedef enum example_QAPIEvent {
EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
- EXAMPLE_QAPI_EVENT_MAX = 1,
+ EXAMPLE_QAPI_EVENT__MAX = 1,
} example_QAPIEvent;
extern const char *const example_QAPIEvent_lookup[];
diff --git a/hmp.c b/hmp.c
index 2140605..1b402c4 100644
--- a/hmp.c
+++ b/hmp.c
@@ -855,7 +855,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
tpo->has_cancel_path ? ",cancel-path=" : "",
tpo->has_cancel_path ? tpo->cancel_path : "");
break;
- case TPM_TYPE_OPTIONS_KIND_MAX:
+ case TPM_TYPE_OPTIONS_KIND__MAX:
break;
}
monitor_printf(mon, "\n");
@@ -1203,7 +1203,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
int i;
- for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
if (strcmp(cap, MigrationCapability_lookup[i]) == 0) {
caps->value = g_malloc0(sizeof(*caps->value));
caps->value->capability = i;
@@ -1214,7 +1214,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
}
}
- if (i == MIGRATION_CAPABILITY_MAX) {
+ if (i == MIGRATION_CAPABILITY__MAX) {
error_setg(&err, QERR_INVALID_PARAMETER, cap);
}
@@ -1239,7 +1239,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
bool has_x_cpu_throttle_increment = false;
int i;
- for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) {
+ for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
switch (i) {
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
@@ -1268,7 +1268,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
}
}
- if (i == MIGRATION_PARAMETER_MAX) {
+ if (i == MIGRATION_PARAMETER__MAX) {
error_setg(&err, QERR_INVALID_PARAMETER, param);
}
@@ -1368,7 +1368,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
if (read_only) {
read_only_mode =
qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup,
- read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE_MAX,
+ read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE__MAX,
BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
if (err) {
hmp_handle_error(mon, &err);
@@ -1771,7 +1771,7 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
keylist->value->u.number = value;
} else {
int idx = index_from_key(keyname_buf);
- if (idx == Q_KEY_CODE_MAX) {
+ if (idx == Q_KEY_CODE__MAX) {
goto err_out;
}
keylist->value->type = KEY_VALUE_KIND_QCODE;
diff --git a/hw/char/escc.c b/hw/char/escc.c
index c9840e1..b351214 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -714,7 +714,7 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
return &d->mmio;
}
-static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = {
+static const uint8_t qcode_to_keycode[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_SHIFT] = 99,
[Q_KEY_CODE_SHIFT_R] = 110,
[Q_KEY_CODE_ALT] = 19,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 2e41efe..abb377a 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -225,7 +225,7 @@ static void pc_init1(MachineState *machine,
pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
- assert(pcms->vmport != ON_OFF_AUTO_MAX);
+ assert(pcms->vmport != ON_OFF_AUTO__MAX);
if (pcms->vmport == ON_OFF_AUTO_AUTO) {
pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 133bc68..9a12068 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -233,7 +233,7 @@ static void pc_q35_init(MachineState *machine)
pc_register_ferr_irq(gsi[13]);
- assert(pcms->vmport != ON_OFF_AUTO_MAX);
+ assert(pcms->vmport != ON_OFF_AUTO__MAX);
if (pcms->vmport == ON_OFF_AUTO_AUTO) {
pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
}
diff --git a/hw/input/hid.c b/hw/input/hid.c
index e39269f..12075c9 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -108,7 +108,7 @@ void hid_set_next_idle(HIDState *hs)
static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
- static const int bmap[INPUT_BUTTON_MAX] = {
+ static const int bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_RIGHT] = 0x02,
[INPUT_BUTTON_MIDDLE] = 0x04,
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 3d6d496..9096d21 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -382,7 +382,7 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
- static const int bmap[INPUT_BUTTON_MAX] = {
+ static const int bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index bdd479c..5d00a03 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -21,7 +21,7 @@
/* ----------------------------------------------------------------- */
-static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = {
+static const unsigned int keymap_qcode[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_ESC] = KEY_ESC,
[Q_KEY_CODE_1] = KEY_1,
[Q_KEY_CODE_2] = KEY_2,
@@ -138,7 +138,7 @@ static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = {
[Q_KEY_CODE_MENU] = KEY_MENU,
};
-static const unsigned int keymap_button[INPUT_BUTTON_MAX] = {
+static const unsigned int keymap_button[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = BTN_LEFT,
[INPUT_BUTTON_RIGHT] = BTN_RIGHT,
[INPUT_BUTTON_MIDDLE] = BTN_MIDDLE,
@@ -146,12 +146,12 @@ static const unsigned int keymap_button[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN,
};
-static const unsigned int axismap_rel[INPUT_AXIS_MAX] = {
+static const unsigned int axismap_rel[INPUT_AXIS__MAX] = {
[INPUT_AXIS_X] = REL_X,
[INPUT_AXIS_Y] = REL_Y,
};
-static const unsigned int axismap_abs[INPUT_AXIS_MAX] = {
+static const unsigned int axismap_abs[INPUT_AXIS__MAX] = {
[INPUT_AXIS_X] = ABS_X,
[INPUT_AXIS_Y] = ABS_Y,
};
diff --git a/include/migration/migration.h b/include/migration/migration.h
index fd018b7..d9494b8 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -133,7 +133,7 @@ struct MigrationState
QemuThread thread;
QEMUBH *cleanup_bh;
QEMUFile *file;
- int parameters[MIGRATION_PARAMETER_MAX];
+ int parameters[MIGRATION_PARAMETER__MAX];
int state;
MigrationParams params;
@@ -151,7 +151,7 @@ struct MigrationState
int64_t expected_downtime;
int64_t dirty_pages_rate;
int64_t dirty_bytes_rate;
- bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+ bool enabled_capabilities[MIGRATION_CAPABILITY__MAX];
int64_t xbzrle_cache_size;
int64_t setup_time;
int64_t dirty_sync_count;
diff --git a/migration/migration.c b/migration/migration.c
index adc6b6f..c842499 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -202,7 +202,7 @@ static int global_state_post_load(void *opaque, int version_id)
s->received = true;
trace_migrate_global_state_post_load(runstate);
- r = qapi_enum_parse(RunState_lookup, runstate, RUN_STATE_MAX,
+ r = qapi_enum_parse(RunState_lookup, runstate, RUN_STATE__MAX,
-1, &local_err);
if (r == -1) {
@@ -479,7 +479,7 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
int i;
caps = NULL; /* silence compiler warning */
- for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
if (head == NULL) {
head = g_malloc0(sizeof(*caps));
caps = head;
diff --git a/monitor.c b/monitor.c
index 9a35d72..5546f8a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -441,7 +441,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data,
}
-static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT_MAX] = {
+static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
/* Limit guest-triggerable events to 1 per second */
[QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
[QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS },
@@ -481,7 +481,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
MonitorQAPIEventConf *evconf;
MonitorQAPIEventState *evstate;
- assert(event < QAPI_EVENT_MAX);
+ assert(event < QAPI_EVENT__MAX);
evconf = &monitor_qapi_event_conf[event];
trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
@@ -946,7 +946,7 @@ EventInfoList *qmp_query_events(Error **errp)
EventInfoList *info, *ev_list = NULL;
QAPIEvent e;
- for (e = 0 ; e < QAPI_EVENT_MAX ; e++) {
+ for (e = 0 ; e < QAPI_EVENT__MAX ; e++) {
const char *event_name = QAPIEvent_lookup[e];
assert(event_name != NULL);
info = g_malloc0(sizeof(*info));
@@ -1386,7 +1386,7 @@ static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
static void hmp_mouse_button(Monitor *mon, const QDict *qdict)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
@@ -3217,7 +3217,7 @@ void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
}
len = strlen(str);
readline_set_completion_index(rs, len);
- for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ for (i = 0; i < Q_KEY_CODE__MAX; i++) {
if (!strncmp(str, QKeyCode_lookup[i], len)) {
readline_add_completion(rs, QKeyCode_lookup[i]);
}
@@ -3316,7 +3316,7 @@ void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
readline_set_completion_index(rs, len);
if (nb_args == 2) {
int i;
- for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
const char *name = MigrationCapability_lookup[i];
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
@@ -3337,7 +3337,7 @@ void migrate_set_parameter_completion(ReadLineState *rs, int nb_args,
readline_set_completion_index(rs, len);
if (nb_args == 2) {
int i;
- for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) {
+ for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
const char *name = MigrationParameter_lookup[i];
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
diff --git a/net/net.c b/net/net.c
index ade6051..87dd356 100644
--- a/net/net.c
+++ b/net/net.c
@@ -943,7 +943,7 @@ static int net_init_nic(const NetClientOptions *opts, const char *name,
}
-static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
+static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])(
const NetClientOptions *opts,
const char *name,
NetClientState *peer, Error **errp) = {
@@ -1296,7 +1296,7 @@ void qmp_set_link(const char *name, bool up, Error **errp)
int queues, i;
queues = qemu_find_net_clients_except(name, ncs,
- NET_CLIENT_OPTIONS_KIND_MAX,
+ NET_CLIENT_OPTIONS_KIND__MAX,
MAX_QUEUE_NUM);
if (queues == 0) {
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 3afec76..65dc30c 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -487,7 +487,7 @@ int main(int argc, char **argv)
detect_zeroes =
qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
optarg,
- BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
+ BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
&local_err);
if (local_err) {
diff --git a/replay/replay-input.c b/replay/replay-input.c
index 9879895..bc15f59 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -61,7 +61,7 @@ void replay_save_input_event(InputEvent *evt)
replay_put_dword(evt->u.key->key->u.qcode);
replay_put_byte(evt->u.key->down);
break;
- case KEY_VALUE_KIND_MAX:
+ case KEY_VALUE_KIND__MAX:
/* keep gcc happy */
break;
}
@@ -78,7 +78,7 @@ void replay_save_input_event(InputEvent *evt)
replay_put_dword(evt->u.abs->axis);
replay_put_qword(evt->u.abs->value);
break;
- case INPUT_EVENT_KIND_MAX:
+ case INPUT_EVENT_KIND__MAX:
/* keep gcc happy */
break;
}
@@ -109,7 +109,7 @@ InputEvent *replay_read_input_event(void)
evt.u.key->key->u.qcode = (QKeyCode)replay_get_dword();
evt.u.key->down = replay_get_byte();
break;
- case KEY_VALUE_KIND_MAX:
+ case KEY_VALUE_KIND__MAX:
/* keep gcc happy */
break;
}
@@ -129,7 +129,7 @@ InputEvent *replay_read_input_event(void)
evt.u.abs->axis = (InputAxis)replay_get_dword();
evt.u.abs->value = replay_get_qword();
break;
- case INPUT_EVENT_KIND_MAX:
+ case INPUT_EVENT_KIND__MAX:
/* keep gcc happy */
break;
}
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 3e5caa8..9c541e0 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -918,7 +918,7 @@ class QAPISchemaEnumType(QAPISchemaType):
return c_name(self.name)
def c_null(self):
- return c_enum_const(self.name, (self.values + ['MAX'])[0],
+ return c_enum_const(self.name, (self.values + ['_MAX'])[0],
self.prefix)
def json_type(self):
@@ -1568,7 +1568,7 @@ const char *const %(c_name)s_lookup[] = {
''',
index=index, value=value)
- max_index = c_enum_const(name, 'MAX', prefix)
+ max_index = c_enum_const(name, '_MAX', prefix)
ret += mcgen('''
[%(max_index)s] = NULL,
};
@@ -1579,7 +1579,7 @@ const char *const %(c_name)s_lookup[] = {
def gen_enum(name, values, prefix=None):
# append automatically generated _MAX value
- enum_values = values + ['MAX']
+ enum_values = values + ['_MAX']
ret = mcgen('''
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 0d0c859..4196e66 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -128,7 +128,7 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
QObject *obj;
EnumOne i;
- for (i = 0; i < ENUM_ONE_MAX; i++) {
+ for (i = 0; i < ENUM_ONE__MAX; i++) {
visit_type_EnumOne(data->ov, &i, "unused", &error_abort);
obj = qmp_output_get_qobject(data->qov);
@@ -143,7 +143,7 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
const void *unused)
{
- EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
+ EnumOne i, bad_values[] = { ENUM_ONE__MAX, -1 };
Error *err;
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
@@ -247,7 +247,7 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
const void *unused)
{
- EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
+ EnumOne bad_values[] = { ENUM_ONE__MAX, -1 };
UserDefOne u = {0};
UserDefOne *pu = &u;
Error *err;
diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c
index fd5e67b..9585252 100644
--- a/tests/test-string-output-visitor.c
+++ b/tests/test-string-output-visitor.c
@@ -194,7 +194,7 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
char *str;
EnumOne i;
- for (i = 0; i < ENUM_ONE_MAX; i++) {
+ for (i = 0; i < ENUM_ONE__MAX; i++) {
char *str_human;
visit_type_EnumOne(data->ov, &i, "unused", &err);
@@ -217,7 +217,7 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
const void *unused)
{
- EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
+ EnumOne i, bad_values[] = { ENUM_ONE__MAX, -1 };
Error *err;
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
diff --git a/tpm.c b/tpm.c
index f2c59d1..0a3e3d5 100644
--- a/tpm.c
+++ b/tpm.c
@@ -32,7 +32,7 @@ static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
};
static enum TpmModel tpm_models[TPM_MAX_MODELS] = {
- TPM_MODEL_MAX,
+ TPM_MODEL__MAX,
};
int tpm_register_model(enum TpmModel model)
@@ -40,7 +40,7 @@ int tpm_register_model(enum TpmModel model)
int i;
for (i = 0; i < TPM_MAX_MODELS; i++) {
- if (tpm_models[i] == TPM_MODEL_MAX) {
+ if (tpm_models[i] == TPM_MODEL__MAX) {
tpm_models[i] = model;
return 0;
}
@@ -272,7 +272,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
tpo->has_cancel_path = true;
}
break;
- case TPM_TYPE_MAX:
+ case TPM_TYPE__MAX:
break;
}
@@ -311,7 +311,7 @@ TpmTypeList *qmp_query_tpm_types(Error **errp)
unsigned int i = 0;
TpmTypeList *head = NULL, *prev = NULL, *cur_item;
- for (i = 0; i < TPM_TYPE_MAX; i++) {
+ for (i = 0; i < TPM_TYPE__MAX; i++) {
if (!tpm_driver_find_by_type(i)) {
continue;
}
@@ -335,7 +335,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp)
unsigned int i = 0;
TpmModelList *head = NULL, *prev = NULL, *cur_item;
- for (i = 0; i < TPM_MODEL_MAX; i++) {
+ for (i = 0; i < TPM_MODEL__MAX; i++) {
if (!tpm_model_is_registered(i)) {
continue;
}
diff --git a/ui/cocoa.m b/ui/cocoa.m
index d76b942..7477d58 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -733,7 +733,7 @@ QemuCocoaView *cocoaView;
*/
if ((isMouseGrabbed || [[self window] isKeyWindow]) &&
(last_buttons != buttons)) {
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
diff --git a/ui/console.c b/ui/console.c
index 745c354..27a2cdc 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1108,7 +1108,7 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
}
}
-static const int qcode_to_keysym[Q_KEY_CODE_MAX] = {
+static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_UP] = QEMU_KEY_UP,
[Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
[Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT,
diff --git a/ui/input-keymap.c b/ui/input-keymap.c
index d36be4b..63d71d2 100644
--- a/ui/input-keymap.c
+++ b/ui/input-keymap.c
@@ -132,7 +132,7 @@ static const int qcode_to_number[] = {
[Q_KEY_CODE_RO] = 0x73,
[Q_KEY_CODE_KP_COMMA] = 0x7e,
- [Q_KEY_CODE_MAX] = 0,
+ [Q_KEY_CODE__MAX] = 0,
};
static int number_to_qcode[0x100];
@@ -154,7 +154,7 @@ int qemu_input_key_number_to_qcode(uint8_t nr)
if (first) {
int qcode, number;
first = false;
- for (qcode = 0; qcode < Q_KEY_CODE_MAX; qcode++) {
+ for (qcode = 0; qcode < Q_KEY_CODE__MAX; qcode++) {
number = qcode_to_number[qcode];
assert(number < ARRAY_SIZE(number_to_qcode));
number_to_qcode[number] = qcode;
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index e0a39f0..3bc29bd 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -38,7 +38,7 @@ struct QEMUPutMouseEntry {
/* new input core */
QemuInputHandler h;
QemuInputHandlerState *s;
- int axis[INPUT_AXIS_MAX];
+ int axis[INPUT_AXIS__MAX];
int buttons;
};
@@ -67,7 +67,7 @@ int index_from_key(const char *key)
}
}
- /* Return Q_KEY_CODE_MAX if the key is invalid */
+ /* Return Q_KEY_CODE__MAX if the key is invalid */
return i;
}
@@ -143,7 +143,7 @@ QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
- static const int bmap[INPUT_BUTTON_MAX] = {
+ static const int bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
diff --git a/ui/input.c b/ui/input.c
index a0f9873..006667b 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -211,7 +211,7 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
name = QKeyCode_lookup[evt->u.key->key->u.qcode];
trace_input_event_key_qcode(idx, name, evt->u.key->down);
break;
- case KEY_VALUE_KIND_MAX:
+ case KEY_VALUE_KIND__MAX:
/* keep gcc happy */
break;
}
@@ -228,7 +228,7 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
name = InputAxis_lookup[evt->u.abs->axis];
trace_input_event_abs(idx, name, evt->u.abs->value);
break;
- case INPUT_EVENT_KIND_MAX:
+ case INPUT_EVENT_KIND__MAX:
/* keep gcc happy */
break;
}
@@ -430,7 +430,7 @@ void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
InputButton btn;
uint32_t mask;
- for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
+ for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) {
mask = button_map[btn];
if ((button_old & mask) == (button_new & mask)) {
continue;
diff --git a/ui/sdl.c b/ui/sdl.c
index 570cb99..f4aa0f2 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -465,7 +465,7 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 5cb75aa..4be992a 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -256,7 +256,7 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy,
int x, int y, int state)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
diff --git a/ui/spice-input.c b/ui/spice-input.c
index c342e0d..96f19aa 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -107,7 +107,7 @@ typedef struct QemuSpicePointer {
static void spice_update_buttons(QemuSpicePointer *pointer,
int wheel, uint32_t button_mask)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x04,
[INPUT_BUTTON_RIGHT] = 0x02,
diff --git a/ui/vnc.c b/ui/vnc.c
index cbe4d33..fe7ff26 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1676,7 +1676,7 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
static void pointer_event(VncState *vs, int button_mask, int x, int y)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x02,
[INPUT_BUTTON_RIGHT] = 0x04,
diff --git a/vl.c b/vl.c
index 4211ff1..5aaea77 100644
--- a/vl.c
+++ b/vl.c
@@ -570,8 +570,8 @@ static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp)
static RunState current_run_state = RUN_STATE_PRELAUNCH;
-/* We use RUN_STATE_MAX but any invalid value will do */
-static RunState vmstop_requested = RUN_STATE_MAX;
+/* We use RUN_STATE__MAX but any invalid value will do */
+static RunState vmstop_requested = RUN_STATE__MAX;
static QemuMutex vmstop_lock;
typedef struct {
@@ -642,10 +642,10 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING },
{ RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE },
- { RUN_STATE_MAX, RUN_STATE_MAX },
+ { RUN_STATE__MAX, RUN_STATE__MAX },
};
-static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX];
+static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX];
bool runstate_check(RunState state)
{
@@ -669,7 +669,7 @@ static void runstate_init(void)
const RunStateTransition *p;
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
- for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) {
+ for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) {
runstate_valid_transitions[p->from][p->to] = true;
}
@@ -679,7 +679,7 @@ static void runstate_init(void)
/* This function will abort() on invalid state transitions */
void runstate_set(RunState new_state)
{
- assert(new_state < RUN_STATE_MAX);
+ assert(new_state < RUN_STATE__MAX);
if (!runstate_valid_transitions[current_run_state][new_state]) {
error_report("invalid runstate transition: '%s' -> '%s'",
@@ -717,9 +717,9 @@ static bool qemu_vmstop_requested(RunState *r)
{
qemu_mutex_lock(&vmstop_lock);
*r = vmstop_requested;
- vmstop_requested = RUN_STATE_MAX;
+ vmstop_requested = RUN_STATE__MAX;
qemu_mutex_unlock(&vmstop_lock);
- return *r < RUN_STATE_MAX;
+ return *r < RUN_STATE__MAX;
}
void qemu_system_vmstop_request_prepare(void)
@@ -739,7 +739,7 @@ void vm_start(void)
RunState requested;
qemu_vmstop_requested(&requested);
- if (runstate_is_running() && requested == RUN_STATE_MAX) {
+ if (runstate_is_running() && requested == RUN_STATE__MAX) {
return;
}
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 23/40] qapi: Remove obsolete tests for MAX collision
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (21 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 22/40] qapi: Don't let implicit enum MAX member collide Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 24/40] cpu: Convert CpuInfo into flat union Markus Armbruster
` (17 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Now that we no longer collide with an implicit _MAX enum member,
we no longer need to reject it in the ad hoc parser, and can
remove several tests that are no longer needed.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-24-git-send-email-eblake@redhat.com>
[Commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 8 +++-----
tests/Makefile | 3 ---
tests/qapi-schema/enum-max-member.err | 1 -
tests/qapi-schema/enum-max-member.exit | 1 -
tests/qapi-schema/enum-max-member.json | 3 ---
tests/qapi-schema/enum-max-member.out | 0
tests/qapi-schema/event-max.err | 1 -
tests/qapi-schema/event-max.exit | 1 -
tests/qapi-schema/event-max.json | 2 --
tests/qapi-schema/event-max.out | 0
tests/qapi-schema/union-max.err | 1 -
tests/qapi-schema/union-max.exit | 1 -
tests/qapi-schema/union-max.json | 3 ---
tests/qapi-schema/union-max.out | 0
14 files changed, 3 insertions(+), 22 deletions(-)
delete mode 100644 tests/qapi-schema/enum-max-member.err
delete mode 100644 tests/qapi-schema/enum-max-member.exit
delete mode 100644 tests/qapi-schema/enum-max-member.json
delete mode 100644 tests/qapi-schema/enum-max-member.out
delete mode 100644 tests/qapi-schema/event-max.err
delete mode 100644 tests/qapi-schema/event-max.exit
delete mode 100644 tests/qapi-schema/event-max.json
delete mode 100644 tests/qapi-schema/event-max.out
delete mode 100644 tests/qapi-schema/union-max.err
delete mode 100644 tests/qapi-schema/union-max.exit
delete mode 100644 tests/qapi-schema/union-max.json
delete mode 100644 tests/qapi-schema/union-max.out
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 9c541e0..6acef1f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -537,8 +537,6 @@ def check_event(expr, expr_info):
global events
name = expr['event']
- if name.upper() == 'MAX':
- raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
events.append(name)
check_type(expr_info, "'data' for event '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
@@ -550,7 +548,7 @@ def check_union(expr, expr_info):
base = expr.get('base')
discriminator = expr.get('discriminator')
members = expr['data']
- values = {'MAX': '(automatic)'}
+ values = {}
# Two types of unions, determined by discriminator.
@@ -629,7 +627,7 @@ def check_union(expr, expr_info):
def check_alternate(expr, expr_info):
name = expr['alternate']
members = expr['data']
- values = {'MAX': '(automatic)'}
+ values = {}
types_seen = {}
# Check every branch
@@ -662,7 +660,7 @@ def check_enum(expr, expr_info):
name = expr['enum']
members = expr.get('data')
prefix = expr.get('prefix')
- values = {'MAX': '(automatic)'}
+ values = {}
if not isinstance(members, list):
raise QAPIExprError(expr_info,
diff --git a/tests/Makefile b/tests/Makefile
index 2f6b234..0f4914c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -267,14 +267,12 @@ qapi-schema += enum-bad-prefix.json
qapi-schema += enum-clash-member.json
qapi-schema += enum-dict-member.json
qapi-schema += enum-int-member.json
-qapi-schema += enum-max-member.json
qapi-schema += enum-missing-data.json
qapi-schema += enum-wrong-data.json
qapi-schema += escape-outside-string.json
qapi-schema += escape-too-big.json
qapi-schema += escape-too-short.json
qapi-schema += event-case.json
-qapi-schema += event-max.json
qapi-schema += event-nest-struct.json
qapi-schema += flat-union-array-branch.json
qapi-schema += flat-union-bad-base.json
@@ -347,7 +345,6 @@ qapi-schema += union-clash-branches.json
qapi-schema += union-clash-data.json
qapi-schema += union-empty.json
qapi-schema += union-invalid-base.json
-qapi-schema += union-max.json
qapi-schema += union-optional-branch.json
qapi-schema += union-unknown.json
qapi-schema += unknown-escape.json
diff --git a/tests/qapi-schema/enum-max-member.err b/tests/qapi-schema/enum-max-member.err
deleted file mode 100644
index f77837f..0000000
--- a/tests/qapi-schema/enum-max-member.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/enum-max-member.json:3: Enum 'MyEnum' member 'max' clashes with '(automatic)'
diff --git a/tests/qapi-schema/enum-max-member.exit b/tests/qapi-schema/enum-max-member.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/enum-max-member.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/enum-max-member.json b/tests/qapi-schema/enum-max-member.json
deleted file mode 100644
index 4bcda0b..0000000
--- a/tests/qapi-schema/enum-max-member.json
+++ /dev/null
@@ -1,3 +0,0 @@
-# we reject user-supplied 'max' for clashing with implicit enum end
-# TODO: should we instead munge the implicit value to avoid the clash?
-{ 'enum': 'MyEnum', 'data': [ 'max' ] }
diff --git a/tests/qapi-schema/enum-max-member.out b/tests/qapi-schema/enum-max-member.out
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/event-max.err b/tests/qapi-schema/event-max.err
deleted file mode 100644
index c856534..0000000
--- a/tests/qapi-schema/event-max.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/event-max.json:2: Event name 'MAX' cannot be created
diff --git a/tests/qapi-schema/event-max.exit b/tests/qapi-schema/event-max.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/event-max.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/event-max.json b/tests/qapi-schema/event-max.json
deleted file mode 100644
index f3d7de2..0000000
--- a/tests/qapi-schema/event-max.json
+++ /dev/null
@@ -1,2 +0,0 @@
-# an event named 'MAX' would conflict with implicit C enum
-{ 'event': 'MAX' }
diff --git a/tests/qapi-schema/event-max.out b/tests/qapi-schema/event-max.out
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/union-max.err b/tests/qapi-schema/union-max.err
deleted file mode 100644
index 55ce439..0000000
--- a/tests/qapi-schema/union-max.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/union-max.json:2: Union 'Union' member 'max' clashes with '(automatic)'
diff --git a/tests/qapi-schema/union-max.exit b/tests/qapi-schema/union-max.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/union-max.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/union-max.json b/tests/qapi-schema/union-max.json
deleted file mode 100644
index d6ad986..0000000
--- a/tests/qapi-schema/union-max.json
+++ /dev/null
@@ -1,3 +0,0 @@
-# we reject 'max' branch in a union, for collision with C enum
-{ 'union': 'Union',
- 'data': { 'max': 'int' } }
diff --git a/tests/qapi-schema/union-max.out b/tests/qapi-schema/union-max.out
deleted file mode 100644
index e69de29..0000000
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 24/40] cpu: Convert CpuInfo into flat union
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (22 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 23/40] qapi: Remove obsolete tests for MAX collision Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 25/40] qapi: Add alias for ErrorClass Markus Armbruster
` (16 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
The CpuInfo struct is used only by the 'query-cpus' output
command, so we are free to modify it by adding fields (clients
are already supposed to ignore unknown output fields), or by
changing optional members to mandatory, while still keeping
QMP wire compatibility with older versions of qemu.
When qapi type CpuInfo was originally created for 0.14, we had
no notion of a flat union, and instead just listed a bunch of
optional fields with documentation about the mutually-exclusive
choice of which instruction pointer field(s) would be provided
for a given architecture. But now that we have flat unions and
introspection, it is better to segregate off which fields will
be provided according to the actual architecture. With this in
place, we no longer need the fields to be optional, because the
choice of the new 'arch' discriminator serves that role.
This has an additional benefit: the old all-in-one struct was
the only place in the code base that had a case-sensitive
naming of members 'pc' vs. 'PC'. Separating these spellings
into different branches of the flat union will allow us to add
restrictions against future case-insensitive collisions, since
that is generally a poor interface practice.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-25-git-send-email-eblake@redhat.com>
[Spelling of CPUInfo{SPARC,PPC,MIPS} fixed]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
cpus.c | 31 ++++++++------
hmp.c | 30 +++++++++-----
qapi-schema.json | 120 ++++++++++++++++++++++++++++++++++++++++++++++---------
qmp-commands.hx | 4 ++
4 files changed, 143 insertions(+), 42 deletions(-)
diff --git a/cpus.c b/cpus.c
index 43676fa..ea29584 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1558,22 +1558,29 @@ CpuInfoList *qmp_query_cpus(Error **errp)
info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
info->value->thread_id = cpu->thread_id;
#if defined(TARGET_I386)
- info->value->has_pc = true;
- info->value->pc = env->eip + env->segs[R_CS].base;
+ info->value->arch = CPU_INFO_ARCH_X86;
+ info->value->u.x86 = g_new0(CpuInfoX86, 1);
+ info->value->u.x86->pc = env->eip + env->segs[R_CS].base;
#elif defined(TARGET_PPC)
- info->value->has_nip = true;
- info->value->nip = env->nip;
+ info->value->arch = CPU_INFO_ARCH_PPC;
+ info->value->u.ppc = g_new0(CpuInfoPPC, 1);
+ info->value->u.ppc->nip = env->nip;
#elif defined(TARGET_SPARC)
- info->value->has_pc = true;
- info->value->pc = env->pc;
- info->value->has_npc = true;
- info->value->npc = env->npc;
+ info->value->arch = CPU_INFO_ARCH_SPARC;
+ info->value->u.sparc = g_new0(CpuInfoSPARC, 1);
+ info->value->u.sparc->pc = env->pc;
+ info->value->u.sparc->npc = env->npc;
#elif defined(TARGET_MIPS)
- info->value->has_PC = true;
- info->value->PC = env->active_tc.PC;
+ info->value->arch = CPU_INFO_ARCH_MIPS;
+ info->value->u.mips = g_new0(CpuInfoMIPS, 1);
+ info->value->u.mips->PC = env->active_tc.PC;
#elif defined(TARGET_TRICORE)
- info->value->has_PC = true;
- info->value->PC = env->PC;
+ info->value->arch = CPU_INFO_ARCH_TRICORE;
+ info->value->u.tricore = g_new0(CpuInfoTricore, 1);
+ info->value->u.tricore->PC = env->PC;
+#else
+ info->value->arch = CPU_INFO_ARCH_OTHER;
+ info->value->u.other = g_new0(CpuInfoOther, 1);
#endif
/* XXX: waiting for the qapi to support GSList */
diff --git a/hmp.c b/hmp.c
index 1b402c4..c2b2c16 100644
--- a/hmp.c
+++ b/hmp.c
@@ -311,17 +311,25 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->CPU);
- if (cpu->value->has_pc) {
- monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->pc);
- }
- if (cpu->value->has_nip) {
- monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->nip);
- }
- if (cpu->value->has_npc) {
- monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->npc);
- }
- if (cpu->value->has_PC) {
- monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->PC);
+ switch (cpu->value->arch) {
+ case CPU_INFO_ARCH_X86:
+ monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86->pc);
+ break;
+ case CPU_INFO_ARCH_PPC:
+ monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc->nip);
+ break;
+ case CPU_INFO_ARCH_SPARC:
+ monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.sparc->pc);
+ monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->u.sparc->npc);
+ break;
+ case CPU_INFO_ARCH_MIPS:
+ monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.mips->PC);
+ break;
+ case CPU_INFO_ARCH_TRICORE:
+ monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore->PC);
+ break;
+ default:
+ break;
}
if (cpu->value->halted) {
diff --git a/qapi-schema.json b/qapi-schema.json
index 8b1a423..f014a80 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -744,43 +744,125 @@
{ 'command': 'query-mice', 'returns': ['MouseInfo'] }
##
-# @CpuInfo:
+# @CpuInfoArch:
#
-# Information about a virtual CPU
+# An enumeration of cpu types that enable additional information during
+# @query-cpus.
+#
+# Since: 2.6
+##
+{ 'enum': 'CpuInfoArch',
+ 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }
+
+##
+# @CpuInfoBase:
+#
+# Common information about a virtual CPU
#
# @CPU: the index of the virtual CPU
#
-# @current: this only exists for backwards compatible and should be ignored
+# @current: this only exists for backwards compatibility and should be ignored
#
# @halted: true if the virtual CPU is in the halt state. Halt usually refers
# to a processor specific low power mode.
#
# @qom_path: path to the CPU object in the QOM tree (since 2.4)
#
-# @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction
-# pointer.
-# If the target is Sparc, this is the PC component of the
-# instruction pointer.
-#
-# @nip: #optional If the target is PPC, the instruction pointer
-#
-# @npc: #optional If the target is Sparc, the NPC component of the instruction
-# pointer
-#
-# @PC: #optional If the target is MIPS, the instruction pointer
-#
# @thread_id: ID of the underlying host thread
#
+# @arch: architecture of the cpu, which determines which additional fields
+# will be listed (since 2.6)
+#
# Since: 0.14.0
#
# Notes: @halted is a transient state that changes frequently. By the time the
# data is sent to the client, the guest may no longer be halted.
##
-{ 'struct': 'CpuInfo',
+{ 'struct': 'CpuInfoBase',
'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
- 'qom_path': 'str',
- '*pc': 'int', '*nip': 'int', '*npc': 'int', '*PC': 'int',
- 'thread_id': 'int'} }
+ 'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' } }
+
+##
+# @CpuInfo:
+#
+# Information about a virtual CPU
+#
+# Since: 0.14.0
+##
+{ 'union': 'CpuInfo', 'base': 'CpuInfoBase', 'discriminator': 'arch',
+ 'data': { 'x86': 'CpuInfoX86',
+ 'sparc': 'CpuInfoSPARC',
+ 'ppc': 'CpuInfoPPC',
+ 'mips': 'CpuInfoMIPS',
+ 'tricore': 'CpuInfoTricore',
+ 'other': 'CpuInfoOther' } }
+
+##
+# @CpuInfoX86:
+#
+# Additional information about a virtual i386 or x86_64 CPU
+#
+# @pc: the 64-bit instruction pointer
+#
+# Since 2.6
+##
+{ 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
+
+##
+# @CpuInfoSPARC:
+#
+# Additional information about a virtual SPARC CPU
+#
+# @pc: the PC component of the instruction pointer
+#
+# @npc: the NPC component of the instruction pointer
+#
+# Since 2.6
+##
+{ 'struct': 'CpuInfoSPARC', 'data': { 'pc': 'int', 'npc': 'int' } }
+
+##
+# @CpuInfoPPC:
+#
+# Additional information about a virtual PPC CPU
+#
+# @nip: the instruction pointer
+#
+# Since 2.6
+##
+{ 'struct': 'CpuInfoPPC', 'data': { 'nip': 'int' } }
+
+##
+# @CpuInfoMIPS:
+#
+# Additional information about a virtual MIPS CPU
+#
+# @PC: the instruction pointer
+#
+# Since 2.6
+##
+{ 'struct': 'CpuInfoMIPS', 'data': { 'PC': 'int' } }
+
+##
+# @CpuInfoTricore:
+#
+# Additional information about a virtual Tricore CPU
+#
+# @PC: the instruction pointer
+#
+# Since 2.6
+##
+{ 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
+
+##
+# @CpuInfoOther:
+#
+# No additional information is available about the virtual CPU
+#
+# Since 2.6
+#
+##
+{ 'struct': 'CpuInfoOther', 'data': { } }
##
# @query-cpus:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 20a92f9..6f3a25d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2765,6 +2765,8 @@ Return a json-array. Each CPU is represented by a json-object, which contains:
- "current": true if this is the current CPU, false otherwise (json-bool)
- "halted": true if the cpu is halted, false otherwise (json-bool)
- "qom_path": path to the CPU object in the QOM tree (json-str)
+- "arch": architecture of the cpu, which determines what additional
+ keys will be present (json-str)
- Current program counter. The key's name depends on the architecture:
"pc": i386/x86_64 (json-int)
"nip": PPC (json-int)
@@ -2782,6 +2784,7 @@ Example:
"current":true,
"halted":false,
"qom_path":"/machine/unattached/device[0]",
+ "arch":"x86",
"pc":3227107138,
"thread_id":3134
},
@@ -2790,6 +2793,7 @@ Example:
"current":false,
"halted":true,
"qom_path":"/machine/unattached/device[2]",
+ "arch":"x86",
"pc":7108165,
"thread_id":3135
}
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 25/40] qapi: Add alias for ErrorClass
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (23 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 24/40] cpu: Convert CpuInfo into flat union Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 26/40] qapi: Change munging of CamelCase enum values Markus Armbruster
` (15 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
The qapi enum ErrorClass is unusual that it uses 'CamelCase' names,
contrary to our documented convention of preferring 'lower-case'.
However, this enum is entrenched in the API; we cannot change
what strings QMP outputs. Meanwhile, we want to simplify how
c_enum_const() is used to generate enum constants, by moving away
from the heuristics of camel_to_upper() to a more straightforward
c_name(N).upper() - but doing so will rename all of the ErrorClass
constants and cause churn to all client files, where the new names
are aesthetically less pleasing (ERROR_CLASS_DEVICENOTFOUND looks
like we can't make up our minds on whether to break between words).
So as always in computer science, solve the problem by some more
indirection: rename the qapi type to QapiErrorClass, and add a
new enum ErrorClass in error.h whose members are aliases of the
qapi type, but with the spelling expected elsewhere in the tree.
Then, when c_enum_const() changes the munging, we only have to
adjust the one alias spot.
Suggested by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-26-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/error.h | 14 ++++++++++++++
monitor.c | 2 +-
qapi/common.json | 5 +++--
qapi/qmp-dispatch.c | 2 +-
4 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/include/qapi/error.h b/include/qapi/error.h
index 4d42cdc..3060b0c 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -91,6 +91,20 @@
typedef struct Error Error;
/*
+ * Overall category of an error.
+ * Based on the qapi type QapiErrorClass, but reproduced here for nicer
+ * enum names.
+ */
+typedef enum ErrorClass {
+ ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERIC_ERROR,
+ ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMAND_NOT_FOUND,
+ ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICE_ENCRYPTED,
+ ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICE_NOT_ACTIVE,
+ ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICE_NOT_FOUND,
+ ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVM_MISSING_CAP,
+} ErrorClass;
+
+/*
* Get @err's human-readable error message.
*/
const char *error_get_pretty(Error *err);
diff --git a/monitor.c b/monitor.c
index 5546f8a..289c118 100644
--- a/monitor.c
+++ b/monitor.c
@@ -403,7 +403,7 @@ static QDict *build_qmp_error_dict(Error *err)
QObject *obj;
obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
- ErrorClass_lookup[error_get_class(err)],
+ QapiErrorClass_lookup[error_get_class(err)],
error_get_pretty(err));
return qobject_to_qdict(obj);
diff --git a/qapi/common.json b/qapi/common.json
index bad56bf..6fb40e7 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -3,7 +3,7 @@
# QAPI common definitions
##
-# @ErrorClass
+# @QapiErrorClass
#
# QEMU error classes
#
@@ -24,7 +24,8 @@
#
# Since: 1.2
##
-{ 'enum': 'ErrorClass',
+{ 'enum': 'QapiErrorClass',
+ # Keep this in sync with ErrorClass in error.h
'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] }
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 7bcc860..f36933d 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -114,7 +114,7 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
QObject *qmp_build_error_object(Error *err)
{
return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
- ErrorClass_lookup[error_get_class(err)],
+ QapiErrorClass_lookup[error_get_class(err)],
error_get_pretty(err));
}
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 26/40] qapi: Change munging of CamelCase enum values
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (24 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 25/40] qapi: Add alias for ErrorClass Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 27/40] qobject: Simplify QObject Markus Armbruster
` (14 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
When munging enum values, the fact that we were passing the entire
prefix + value through camel_to_upper() meant that enum values
spelled with CamelCase could be turned into CAMEL_CASE. However,
this provides a potential collision (both OneTwo and One-Two would
munge into ONE_TWO) for enum types, when the same two names are
valid side-by-side as QAPI member names. By changing the generation
of enum constants to always be prefix + '_' + c_name(value,
False).upper(), and ensuring that there are no case collisions (in
the next patches), we no longer have to worry about names that
would be distinct as QAPI members but collide as variant tag names,
without having to think about what munging the heuristics in
camel_to_upper() will actually perform on an enum value.
Making the change will affect enums that did not follow coding
conventions, using 'CamelCase' rather than desired 'lower-case'.
Thankfully, there are only two culprits: InputButton and ErrorClass.
We already tweaked ErrorClass to make it an alias of QapiErrorClass,
where only the alias needs changing rather than the whole tree. So
the bulk of this change is modifying INPUT_BUTTON_WHEEL_UP to the
new INPUT_BUTTON_WHEELUP (and likewise for WHEELDOWN). That part
of this commit may later need reverting if we rename the enum
constants from 'WheelUp' to 'wheel-up' as part of moving
x-input-send-event to a stable interface; but at least we have
documentation bread crumbs in place to remind us (commit 513e7cd),
and it matches the fact that SDL constants are also spelled
SDL_BUTTON_WHEELUP.
Suggested by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-27-git-send-email-eblake@redhat.com>
[Commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
hw/input/hid.c | 4 ++--
hw/input/ps2.c | 4 ++--
hw/input/virtio-input-hid.c | 4 ++--
include/qapi/error.h | 12 ++++++------
monitor.c | 2 +-
scripts/qapi.py | 2 +-
ui/cocoa.m | 4 ++--
ui/gtk.c | 4 ++--
ui/input-legacy.c | 4 ++--
ui/sdl.c | 4 ++--
ui/sdl2.c | 4 ++--
ui/spice-input.c | 4 ++--
ui/vnc.c | 4 ++--
13 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 12075c9..3221d29 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -139,9 +139,9 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
case INPUT_EVENT_KIND_BTN:
if (evt->u.btn->down) {
e->buttons_state |= bmap[evt->u.btn->button];
- if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
+ if (evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
e->dz--;
- } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+ } else if (evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
e->dz++;
}
} else {
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 9096d21..79754cd 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -405,9 +405,9 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
case INPUT_EVENT_KIND_BTN:
if (evt->u.btn->down) {
s->mouse_buttons |= bmap[evt->u.btn->button];
- if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
+ if (evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
s->mouse_dz--;
- } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+ } else if (evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
s->mouse_dz++;
}
} else {
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 5d00a03..a78d11c 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -142,8 +142,8 @@ static const unsigned int keymap_button[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = BTN_LEFT,
[INPUT_BUTTON_RIGHT] = BTN_RIGHT,
[INPUT_BUTTON_MIDDLE] = BTN_MIDDLE,
- [INPUT_BUTTON_WHEEL_UP] = BTN_GEAR_UP,
- [INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN,
+ [INPUT_BUTTON_WHEELUP] = BTN_GEAR_UP,
+ [INPUT_BUTTON_WHEELDOWN] = BTN_GEAR_DOWN,
};
static const unsigned int axismap_rel[INPUT_AXIS__MAX] = {
diff --git a/include/qapi/error.h b/include/qapi/error.h
index 3060b0c..6285cf5 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -96,12 +96,12 @@ typedef struct Error Error;
* enum names.
*/
typedef enum ErrorClass {
- ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERIC_ERROR,
- ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMAND_NOT_FOUND,
- ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICE_ENCRYPTED,
- ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICE_NOT_ACTIVE,
- ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICE_NOT_FOUND,
- ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVM_MISSING_CAP,
+ ERROR_CLASS_GENERIC_ERROR = QAPI_ERROR_CLASS_GENERICERROR,
+ ERROR_CLASS_COMMAND_NOT_FOUND = QAPI_ERROR_CLASS_COMMANDNOTFOUND,
+ ERROR_CLASS_DEVICE_ENCRYPTED = QAPI_ERROR_CLASS_DEVICEENCRYPTED,
+ ERROR_CLASS_DEVICE_NOT_ACTIVE = QAPI_ERROR_CLASS_DEVICENOTACTIVE,
+ ERROR_CLASS_DEVICE_NOT_FOUND = QAPI_ERROR_CLASS_DEVICENOTFOUND,
+ ERROR_CLASS_KVM_MISSING_CAP = QAPI_ERROR_CLASS_KVMMISSINGCAP,
} ErrorClass;
/*
diff --git a/monitor.c b/monitor.c
index 289c118..e7e7ae2 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1375,7 +1375,7 @@ static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
if (dz_str) {
dz = strtol(dz_str, NULL, 0);
if (dz != 0) {
- button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
+ button = (dz > 0) ? INPUT_BUTTON_WHEELUP : INPUT_BUTTON_WHEELDOWN;
qemu_input_queue_btn(NULL, button, true);
qemu_input_event_sync();
qemu_input_queue_btn(NULL, button, false);
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6acef1f..10fcfbc 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1440,7 +1440,7 @@ def camel_to_upper(value):
def c_enum_const(type_name, const_name, prefix=None):
if prefix is not None:
type_name = prefix
- return camel_to_upper(type_name + '_' + const_name)
+ return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
c_name_trans = string.maketrans('.-', '__')
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 7477d58..d866f23 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -737,8 +737,8 @@ QemuCocoaView *cocoaView;
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
- [INPUT_BUTTON_WHEEL_UP] = MOUSE_EVENT_WHEELUP,
- [INPUT_BUTTON_WHEEL_DOWN] = MOUSE_EVENT_WHEELDN,
+ [INPUT_BUTTON_WHEELUP] = MOUSE_EVENT_WHEELUP,
+ [INPUT_BUTTON_WHEELDOWN] = MOUSE_EVENT_WHEELDN,
};
qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons);
last_buttons = buttons;
diff --git a/ui/gtk.c b/ui/gtk.c
index 47b37e1..40e78c5 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -965,9 +965,9 @@ static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll,
InputButton btn;
if (scroll->direction == GDK_SCROLL_UP) {
- btn = INPUT_BUTTON_WHEEL_UP;
+ btn = INPUT_BUTTON_WHEELUP;
} else if (scroll->direction == GDK_SCROLL_DOWN) {
- btn = INPUT_BUTTON_WHEEL_DOWN;
+ btn = INPUT_BUTTON_WHEELDOWN;
} else {
return TRUE;
}
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index 3bc29bd..35dfc27 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -157,7 +157,7 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
} else {
s->buttons &= ~bmap[evt->u.btn->button];
}
- if (evt->u.btn->down && evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
+ if (evt->u.btn->down && evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
s->axis[INPUT_AXIS_X],
s->axis[INPUT_AXIS_Y],
@@ -165,7 +165,7 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
s->buttons);
}
if (evt->u.btn->down &&
- evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+ evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
s->axis[INPUT_AXIS_X],
s->axis[INPUT_AXIS_Y],
diff --git a/ui/sdl.c b/ui/sdl.c
index f4aa0f2..c837436 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -469,8 +469,8 @@ static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state)
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
- [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
- [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
+ [INPUT_BUTTON_WHEELUP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
+ [INPUT_BUTTON_WHEELDOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
};
static uint32_t prev_state;
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 4be992a..cf38df2 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -504,9 +504,9 @@ static void handle_mousewheel(SDL_Event *ev)
InputButton btn;
if (wev->y > 0) {
- btn = INPUT_BUTTON_WHEEL_UP;
+ btn = INPUT_BUTTON_WHEELUP;
} else if (wev->y < 0) {
- btn = INPUT_BUTTON_WHEEL_DOWN;
+ btn = INPUT_BUTTON_WHEELDOWN;
} else {
return;
}
diff --git a/ui/spice-input.c b/ui/spice-input.c
index 96f19aa..2b3b9ed 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -111,8 +111,8 @@ static void spice_update_buttons(QemuSpicePointer *pointer,
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x04,
[INPUT_BUTTON_RIGHT] = 0x02,
- [INPUT_BUTTON_WHEEL_UP] = 0x10,
- [INPUT_BUTTON_WHEEL_DOWN] = 0x20,
+ [INPUT_BUTTON_WHEELUP] = 0x10,
+ [INPUT_BUTTON_WHEELDOWN] = 0x20,
};
if (wheel < 0) {
diff --git a/ui/vnc.c b/ui/vnc.c
index fe7ff26..b9c57ff 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1680,8 +1680,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x02,
[INPUT_BUTTON_RIGHT] = 0x04,
- [INPUT_BUTTON_WHEEL_UP] = 0x08,
- [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
+ [INPUT_BUTTON_WHEELUP] = 0x08,
+ [INPUT_BUTTON_WHEELDOWN] = 0x10,
};
QemuConsole *con = vs->vd->dcl.con;
int width = pixman_image_get_width(vs->vd->server);
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 27/40] qobject: Simplify QObject
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (25 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 26/40] qapi: Change munging of CamelCase enum values Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 28/40] qobject: Rename qtype_code to QType Markus Armbruster
` (13 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
The QObject hierarchy is small enough, and unlikely to grow further
(since we only use it to map to JSON and already cover all JSON
types), that we can simplify things by not tracking a separate
vtable, but just inline the code element of the vtable QType
directly into QObject (renamed to type), and track a separate array
of destroy functions. We can drop qnull_destroy_obj() in the
process.
The remaining QObject subclasses must export their destructor.
This also has the nice benefit of moving the typename 'QType'
out of the way, so that the next patch can repurpose it for a
nicer name for 'qtype_code'.
The various objects are still the same size (so no change in cache
line pressure), but now have less indirection (although I didn't
bother benchmarking to see if there is a noticeable speedup, as
we don't have hard evidence that this was in a performance hotspot
in the first place).
A future patch could drop the refcnt size to 32 bits for a smaller
struct on 64-bit architectures, if desired (we have limits on the
largest JSON that we are willing to parse, and will probably never
need to take full advantage of a 64-bit refcnt).
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-2-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/qmp/qbool.h | 1 +
include/qapi/qmp/qdict.h | 1 +
include/qapi/qmp/qfloat.h | 1 +
include/qapi/qmp/qint.h | 1 +
include/qapi/qmp/qlist.h | 1 +
include/qapi/qmp/qobject.h | 31 +++++++++++++++----------------
include/qapi/qmp/qstring.h | 1 +
qobject/Makefile.objs | 2 +-
qobject/qbool.c | 11 ++---------
qobject/qdict.c | 11 ++---------
qobject/qfloat.c | 11 ++---------
qobject/qint.c | 11 ++---------
qobject/qlist.c | 11 ++---------
qobject/qnull.c | 12 +-----------
qobject/qobject.c | 34 ++++++++++++++++++++++++++++++++++
qobject/qstring.c | 11 ++---------
16 files changed, 69 insertions(+), 82 deletions(-)
create mode 100644 qobject/qobject.c
diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h
index d9256e4..836d078 100644
--- a/include/qapi/qmp/qbool.h
+++ b/include/qapi/qmp/qbool.h
@@ -25,5 +25,6 @@ typedef struct QBool {
QBool *qbool_from_bool(bool value);
bool qbool_get_bool(const QBool *qb);
QBool *qobject_to_qbool(const QObject *obj);
+void qbool_destroy_obj(QObject *obj);
#endif /* QBOOL_H */
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index 787c658..6c2a0e5 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -48,6 +48,7 @@ void qdict_iter(const QDict *qdict,
void *opaque);
const QDictEntry *qdict_first(const QDict *qdict);
const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry);
+void qdict_destroy_obj(QObject *obj);
/* Helper to qdict_put_obj(), accepts any object */
#define qdict_put(qdict, key, obj) \
diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h
index 46745e5..a8af2a8 100644
--- a/include/qapi/qmp/qfloat.h
+++ b/include/qapi/qmp/qfloat.h
@@ -25,5 +25,6 @@ typedef struct QFloat {
QFloat *qfloat_from_double(double value);
double qfloat_get_double(const QFloat *qi);
QFloat *qobject_to_qfloat(const QObject *obj);
+void qfloat_destroy_obj(QObject *obj);
#endif /* QFLOAT_H */
diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h
index 339a9ab..049e528 100644
--- a/include/qapi/qmp/qint.h
+++ b/include/qapi/qmp/qint.h
@@ -24,5 +24,6 @@ typedef struct QInt {
QInt *qint_from_int(int64_t value);
int64_t qint_get_int(const QInt *qi);
QInt *qobject_to_qint(const QObject *obj);
+void qint_destroy_obj(QObject *obj);
#endif /* QINT_H */
diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h
index b1bf785..a84117e 100644
--- a/include/qapi/qmp/qlist.h
+++ b/include/qapi/qmp/qlist.h
@@ -49,6 +49,7 @@ QObject *qlist_peek(QList *qlist);
int qlist_empty(const QList *qlist);
size_t qlist_size(const QList *qlist);
QList *qobject_to_qlist(const QObject *obj);
+void qlist_destroy_obj(QObject *obj);
static inline const QListEntry *qlist_first(const QList *qlist)
{
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index 4b96ed5..550ba40 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -47,15 +47,8 @@ typedef enum {
QTYPE_MAX,
} qtype_code;
-struct QObject;
-
-typedef struct QType {
- qtype_code code;
- void (*destroy)(struct QObject *);
-} QType;
-
typedef struct QObject {
- const QType *type;
+ qtype_code type;
size_t refcnt;
} QObject;
@@ -71,9 +64,12 @@ typedef struct QObject {
qobject_decref(obj ? QOBJECT(obj) : NULL)
/* Initialize an object to default values */
-#define QOBJECT_INIT(obj, qtype_type) \
- obj->base.refcnt = 1; \
- obj->base.type = qtype_type
+static inline void qobject_init(QObject *obj, qtype_code type)
+{
+ assert(QTYPE_NONE < type && type < QTYPE_MAX);
+ obj->refcnt = 1;
+ obj->type = type;
+}
/**
* qobject_incref(): Increment QObject's reference count
@@ -85,6 +81,11 @@ static inline void qobject_incref(QObject *obj)
}
/**
+ * qobject_destroy(): Free resources used by the object
+ */
+void qobject_destroy(QObject *obj);
+
+/**
* qobject_decref(): Decrement QObject's reference count, deallocate
* when it reaches zero
*/
@@ -92,9 +93,7 @@ static inline void qobject_decref(QObject *obj)
{
assert(!obj || obj->refcnt);
if (obj && --obj->refcnt == 0) {
- assert(obj->type != NULL);
- assert(obj->type->destroy != NULL);
- obj->type->destroy(obj);
+ qobject_destroy(obj);
}
}
@@ -103,8 +102,8 @@ static inline void qobject_decref(QObject *obj)
*/
static inline qtype_code qobject_type(const QObject *obj)
{
- assert(obj->type != NULL);
- return obj->type->code;
+ assert(QTYPE_NONE < obj->type && obj->type < QTYPE_MAX);
+ return obj->type;
}
extern QObject qnull_;
diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h
index 34675a7..df7df55 100644
--- a/include/qapi/qmp/qstring.h
+++ b/include/qapi/qmp/qstring.h
@@ -32,5 +32,6 @@ void qstring_append_int(QString *qstring, int64_t value);
void qstring_append(QString *qstring, const char *str);
void qstring_append_chr(QString *qstring, int c);
QString *qobject_to_qstring(const QObject *obj);
+void qstring_destroy_obj(QObject *obj);
#endif /* QSTRING_H */
diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs
index 0031e8b..bed5508 100644
--- a/qobject/Makefile.objs
+++ b/qobject/Makefile.objs
@@ -1,2 +1,2 @@
util-obj-y = qnull.o qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
-util-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
+util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o
diff --git a/qobject/qbool.c b/qobject/qbool.c
index bc6535f..856c743 100644
--- a/qobject/qbool.c
+++ b/qobject/qbool.c
@@ -15,13 +15,6 @@
#include "qapi/qmp/qobject.h"
#include "qemu-common.h"
-static void qbool_destroy_obj(QObject *obj);
-
-static const QType qbool_type = {
- .code = QTYPE_QBOOL,
- .destroy = qbool_destroy_obj,
-};
-
/**
* qbool_from_bool(): Create a new QBool from a bool
*
@@ -32,8 +25,8 @@ QBool *qbool_from_bool(bool value)
QBool *qb;
qb = g_malloc(sizeof(*qb));
+ qobject_init(QOBJECT(qb), QTYPE_QBOOL);
qb->value = value;
- QOBJECT_INIT(qb, &qbool_type);
return qb;
}
@@ -61,7 +54,7 @@ QBool *qobject_to_qbool(const QObject *obj)
* qbool_destroy_obj(): Free all memory allocated by a
* QBool object
*/
-static void qbool_destroy_obj(QObject *obj)
+void qbool_destroy_obj(QObject *obj)
{
assert(obj != NULL);
g_free(qobject_to_qbool(obj));
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 2d67bf1..eeade15 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -19,13 +19,6 @@
#include "qemu/queue.h"
#include "qemu-common.h"
-static void qdict_destroy_obj(QObject *obj);
-
-static const QType qdict_type = {
- .code = QTYPE_QDICT,
- .destroy = qdict_destroy_obj,
-};
-
/**
* qdict_new(): Create a new QDict
*
@@ -36,7 +29,7 @@ QDict *qdict_new(void)
QDict *qdict;
qdict = g_malloc0(sizeof(*qdict));
- QOBJECT_INIT(qdict, &qdict_type);
+ qobject_init(QOBJECT(qdict), QTYPE_QDICT);
return qdict;
}
@@ -441,7 +434,7 @@ void qdict_del(QDict *qdict, const char *key)
/**
* qdict_destroy_obj(): Free all the memory allocated by a QDict
*/
-static void qdict_destroy_obj(QObject *obj)
+void qdict_destroy_obj(QObject *obj)
{
int i;
QDict *qdict;
diff --git a/qobject/qfloat.c b/qobject/qfloat.c
index c865163..87d89a7 100644
--- a/qobject/qfloat.c
+++ b/qobject/qfloat.c
@@ -15,13 +15,6 @@
#include "qapi/qmp/qobject.h"
#include "qemu-common.h"
-static void qfloat_destroy_obj(QObject *obj);
-
-static const QType qfloat_type = {
- .code = QTYPE_QFLOAT,
- .destroy = qfloat_destroy_obj,
-};
-
/**
* qfloat_from_int(): Create a new QFloat from a float
*
@@ -32,8 +25,8 @@ QFloat *qfloat_from_double(double value)
QFloat *qf;
qf = g_malloc(sizeof(*qf));
+ qobject_init(QOBJECT(qf), QTYPE_QFLOAT);
qf->value = value;
- QOBJECT_INIT(qf, &qfloat_type);
return qf;
}
@@ -61,7 +54,7 @@ QFloat *qobject_to_qfloat(const QObject *obj)
* qfloat_destroy_obj(): Free all memory allocated by a
* QFloat object
*/
-static void qfloat_destroy_obj(QObject *obj)
+void qfloat_destroy_obj(QObject *obj)
{
assert(obj != NULL);
g_free(qobject_to_qfloat(obj));
diff --git a/qobject/qint.c b/qobject/qint.c
index 999688e..7cba9ad 100644
--- a/qobject/qint.c
+++ b/qobject/qint.c
@@ -14,13 +14,6 @@
#include "qapi/qmp/qobject.h"
#include "qemu-common.h"
-static void qint_destroy_obj(QObject *obj);
-
-static const QType qint_type = {
- .code = QTYPE_QINT,
- .destroy = qint_destroy_obj,
-};
-
/**
* qint_from_int(): Create a new QInt from an int64_t
*
@@ -31,8 +24,8 @@ QInt *qint_from_int(int64_t value)
QInt *qi;
qi = g_malloc(sizeof(*qi));
+ qobject_init(QOBJECT(qi), QTYPE_QINT);
qi->value = value;
- QOBJECT_INIT(qi, &qint_type);
return qi;
}
@@ -60,7 +53,7 @@ QInt *qobject_to_qint(const QObject *obj)
* qint_destroy_obj(): Free all memory allocated by a
* QInt object
*/
-static void qint_destroy_obj(QObject *obj)
+void qint_destroy_obj(QObject *obj)
{
assert(obj != NULL);
g_free(qobject_to_qint(obj));
diff --git a/qobject/qlist.c b/qobject/qlist.c
index 298003a..3c045ae 100644
--- a/qobject/qlist.c
+++ b/qobject/qlist.c
@@ -15,13 +15,6 @@
#include "qemu/queue.h"
#include "qemu-common.h"
-static void qlist_destroy_obj(QObject *obj);
-
-static const QType qlist_type = {
- .code = QTYPE_QLIST,
- .destroy = qlist_destroy_obj,
-};
-
/**
* qlist_new(): Create a new QList
*
@@ -32,8 +25,8 @@ QList *qlist_new(void)
QList *qlist;
qlist = g_malloc(sizeof(*qlist));
+ qobject_init(QOBJECT(qlist), QTYPE_QLIST);
QTAILQ_INIT(&qlist->head);
- QOBJECT_INIT(qlist, &qlist_type);
return qlist;
}
@@ -151,7 +144,7 @@ QList *qobject_to_qlist(const QObject *obj)
/**
* qlist_destroy_obj(): Free all the memory allocated by a QList
*/
-static void qlist_destroy_obj(QObject *obj)
+void qlist_destroy_obj(QObject *obj)
{
QList *qlist;
QListEntry *entry, *next_entry;
diff --git a/qobject/qnull.c b/qobject/qnull.c
index 9873e26..5f7ba4d 100644
--- a/qobject/qnull.c
+++ b/qobject/qnull.c
@@ -13,17 +13,7 @@
#include "qemu-common.h"
#include "qapi/qmp/qobject.h"
-static void qnull_destroy_obj(QObject *obj)
-{
- assert(0);
-}
-
-static const QType qnull_type = {
- .code = QTYPE_QNULL,
- .destroy = qnull_destroy_obj,
-};
-
QObject qnull_ = {
- .type = &qnull_type,
+ .type = QTYPE_QNULL,
.refcnt = 1,
};
diff --git a/qobject/qobject.c b/qobject/qobject.c
new file mode 100644
index 0000000..1df315a
--- /dev/null
+++ b/qobject/qobject.c
@@ -0,0 +1,34 @@
+/*
+ * QObject
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1
+ * or later. See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qfloat.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qstring.h"
+
+static void (*qdestroy[QTYPE_MAX])(QObject *) = {
+ [QTYPE_NONE] = NULL, /* No such object exists */
+ [QTYPE_QNULL] = NULL, /* qnull_ is indestructible */
+ [QTYPE_QINT] = qint_destroy_obj,
+ [QTYPE_QSTRING] = qstring_destroy_obj,
+ [QTYPE_QDICT] = qdict_destroy_obj,
+ [QTYPE_QLIST] = qlist_destroy_obj,
+ [QTYPE_QFLOAT] = qfloat_destroy_obj,
+ [QTYPE_QBOOL] = qbool_destroy_obj,
+};
+
+void qobject_destroy(QObject *obj)
+{
+ assert(!obj->refcnt);
+ assert(QTYPE_QNULL < obj->type && obj->type < QTYPE_MAX);
+ qdestroy[obj->type](obj);
+}
diff --git a/qobject/qstring.c b/qobject/qstring.c
index cb72dfb..f44c5c4 100644
--- a/qobject/qstring.c
+++ b/qobject/qstring.c
@@ -14,13 +14,6 @@
#include "qapi/qmp/qstring.h"
#include "qemu-common.h"
-static void qstring_destroy_obj(QObject *obj);
-
-static const QType qstring_type = {
- .code = QTYPE_QSTRING,
- .destroy = qstring_destroy_obj,
-};
-
/**
* qstring_new(): Create a new empty QString
*
@@ -49,6 +42,7 @@ QString *qstring_from_substr(const char *str, int start, int end)
QString *qstring;
qstring = g_malloc(sizeof(*qstring));
+ qobject_init(QOBJECT(qstring), QTYPE_QSTRING);
qstring->length = end - start + 1;
qstring->capacity = qstring->length;
@@ -57,7 +51,6 @@ QString *qstring_from_substr(const char *str, int start, int end)
memcpy(qstring->string, str + start, qstring->length);
qstring->string[qstring->length] = 0;
- QOBJECT_INIT(qstring, &qstring_type);
return qstring;
}
@@ -138,7 +131,7 @@ const char *qstring_get_str(const QString *qstring)
* qstring_destroy_obj(): Free all memory allocated by a QString
* object
*/
-static void qstring_destroy_obj(QObject *obj)
+void qstring_destroy_obj(QObject *obj)
{
QString *qs;
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 28/40] qobject: Rename qtype_code to QType
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (26 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 27/40] qobject: Simplify QObject Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 29/40] qapi: Convert QType into QAPI built-in enum type Markus Armbruster
` (12 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
The name QType matches our CODING_STYLE conventions for type names
in CamelCase. It also matches the fact that we are already naming
all the enum members with a prefix of QTYPE, not QTYPE_CODE. And
doing the rename will also make it easier for the next patch to use
QAPI for providing the enum, which also wants CamelCase type names.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-3-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
block/qapi.c | 4 ++--
include/hw/qdev-core.h | 2 +-
include/qapi/qmp/qobject.h | 8 ++++----
qobject/qdict.c | 3 +--
scripts/qapi.py | 2 +-
5 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/block/qapi.c b/block/qapi.c
index 267f147..c0e877e 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -588,7 +588,7 @@ static void dump_qlist(fprintf_function func_fprintf, void *f, int indentation,
int i = 0;
for (entry = qlist_first(list); entry; entry = qlist_next(entry), i++) {
- qtype_code type = qobject_type(entry->value);
+ QType type = qobject_type(entry->value);
bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
const char *format = composite ? "%*s[%i]:\n" : "%*s[%i]: ";
@@ -606,7 +606,7 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
const QDictEntry *entry;
for (entry = qdict_first(dict); entry; entry = qdict_next(dict, entry)) {
- qtype_code type = qobject_type(entry->value);
+ QType type = qobject_type(entry->value);
bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
const char *format = composite ? "%*s%s:\n" : "%*s%s: ";
char key[strlen(entry->key) + 1];
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index c537969..abcdee8 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -239,7 +239,7 @@ struct Property {
PropertyInfo *info;
ptrdiff_t offset;
uint8_t bitnr;
- qtype_code qtype;
+ QType qtype;
int64_t defval;
int arrayoffset;
PropertyInfo *arrayinfo;
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index 550ba40..c0f1e99 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -45,10 +45,10 @@ typedef enum {
QTYPE_QFLOAT,
QTYPE_QBOOL,
QTYPE_MAX,
-} qtype_code;
+} QType;
typedef struct QObject {
- qtype_code type;
+ QType type;
size_t refcnt;
} QObject;
@@ -64,7 +64,7 @@ typedef struct QObject {
qobject_decref(obj ? QOBJECT(obj) : NULL)
/* Initialize an object to default values */
-static inline void qobject_init(QObject *obj, qtype_code type)
+static inline void qobject_init(QObject *obj, QType type)
{
assert(QTYPE_NONE < type && type < QTYPE_MAX);
obj->refcnt = 1;
@@ -100,7 +100,7 @@ static inline void qobject_decref(QObject *obj)
/**
* qobject_type(): Return the QObject's type
*/
-static inline qtype_code qobject_type(const QObject *obj)
+static inline QType qobject_type(const QObject *obj)
{
assert(QTYPE_NONE < obj->type && obj->type < QTYPE_MAX);
return obj->type;
diff --git a/qobject/qdict.c b/qobject/qdict.c
index eeade15..19df837 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -177,8 +177,7 @@ size_t qdict_size(const QDict *qdict)
/**
* qdict_get_obj(): Get a QObject of a specific type
*/
-static QObject *qdict_get_obj(const QDict *qdict, const char *key,
- qtype_code type)
+static QObject *qdict_get_obj(const QDict *qdict, const char *key, QType type)
{
QObject *obj;
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 10fcfbc..b336fbd 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -33,7 +33,7 @@ builtin_types = {
'uint32': 'QTYPE_QINT',
'uint64': 'QTYPE_QINT',
'size': 'QTYPE_QINT',
- 'any': None, # any qtype_code possible, actually
+ 'any': None, # any QType possible, actually
}
# Whitelist of commands allowed to return a non-dictionary
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 29/40] qapi: Convert QType into QAPI built-in enum type
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (27 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 28/40] qobject: Rename qtype_code to QType Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 30/40] qapi: Simplify visiting of alternate types Markus Armbruster
` (11 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
What's more meta than using qapi to define qapi? :)
Convert QType into a full-fledged[*] builtin qapi enum type, so
that a subsequent patch can then use it as the discriminator
type of qapi alternate types. Fortunately, the judicious use of
'prefix' in the qapi definition avoids churn to the spelling of
the enum constants.
To avoid circular definitions, we have to flip the order of
inclusion between "qobject.h" vs. "qapi-types.h". Back in commit
28770e0, we had the latter include the former, so that we could
use 'QObject *' for our implementation of 'any'. But that usage
also works with only a forward declaration, whereas the
definition of QObject requires QType to be a complete type.
[*] The type has to be builtin, rather than declared in
qapi/common.json, because we want to use it for alternates even
when common.json is not included. But since it is the first
builtin enum type, we have to add special cases to qapi-types
and qapi-visit to only emit definitions once, even when two
qapi files are being compiled into the same binary (the way we
already handled builtin list types like 'intList'). We may
need to revisit how multiple qapi files share common types,
but that's a project for another day.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-4-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
docs/qapi-code-gen.txt | 1 +
include/qapi/qmp/qobject.h | 21 +++++----------------
include/qemu/typedefs.h | 1 +
qobject/qobject.c | 4 ++--
scripts/qapi-types.py | 16 ++++++++++++----
scripts/qapi-visit.py | 11 +++++++++--
scripts/qapi.py | 6 ++++++
tests/qapi-schema/alternate-empty.out | 2 ++
| 2 ++
tests/qapi-schema/empty.out | 2 ++
tests/qapi-schema/event-case.out | 2 ++
tests/qapi-schema/flat-union-empty.out | 2 ++
tests/qapi-schema/ident-with-escape.out | 2 ++
tests/qapi-schema/include-relpath.out | 2 ++
tests/qapi-schema/include-repetition.out | 2 ++
tests/qapi-schema/include-simple.out | 2 ++
tests/qapi-schema/indented-expr.out | 2 ++
tests/qapi-schema/qapi-schema-test.out | 2 ++
tests/qapi-schema/union-clash-data.out | 2 ++
tests/qapi-schema/union-empty.out | 2 ++
20 files changed, 62 insertions(+), 24 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 2becba9..79bf072 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -160,6 +160,7 @@ The following types are predefined, and map to C as follows:
accepts size suffixes
bool bool JSON true or false
any QObject * any JSON value
+ QType QType JSON string matching enum QType values
=== Includes ===
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index c0f1e99..74459ae 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -34,23 +34,12 @@
#include <stddef.h>
#include <assert.h>
+#include "qapi-types.h"
-typedef enum {
- QTYPE_NONE, /* sentinel value, no QObject has this type code */
- QTYPE_QNULL,
- QTYPE_QINT,
- QTYPE_QSTRING,
- QTYPE_QDICT,
- QTYPE_QLIST,
- QTYPE_QFLOAT,
- QTYPE_QBOOL,
- QTYPE_MAX,
-} QType;
-
-typedef struct QObject {
+struct QObject {
QType type;
size_t refcnt;
-} QObject;
+};
/* Get the 'base' part of an object */
#define QOBJECT(obj) (&(obj)->base)
@@ -66,7 +55,7 @@ typedef struct QObject {
/* Initialize an object to default values */
static inline void qobject_init(QObject *obj, QType type)
{
- assert(QTYPE_NONE < type && type < QTYPE_MAX);
+ assert(QTYPE_NONE < type && type < QTYPE__MAX);
obj->refcnt = 1;
obj->type = type;
}
@@ -102,7 +91,7 @@ static inline void qobject_decref(QObject *obj)
*/
static inline QType qobject_type(const QObject *obj)
{
- assert(QTYPE_NONE < obj->type && obj->type < QTYPE_MAX);
+ assert(QTYPE_NONE < obj->type && obj->type < QTYPE__MAX);
return obj->type;
}
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 3eedcf4..78fe6e8 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -80,6 +80,7 @@ typedef struct QEMUSGList QEMUSGList;
typedef struct QEMUSizedBuffer QEMUSizedBuffer;
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUTimerListGroup QEMUTimerListGroup;
+typedef struct QObject QObject;
typedef struct RAMBlock RAMBlock;
typedef struct Range Range;
typedef struct SerialState SerialState;
diff --git a/qobject/qobject.c b/qobject/qobject.c
index 1df315a..a3ef14e 100644
--- a/qobject/qobject.c
+++ b/qobject/qobject.c
@@ -15,7 +15,7 @@
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qstring.h"
-static void (*qdestroy[QTYPE_MAX])(QObject *) = {
+static void (*qdestroy[QTYPE__MAX])(QObject *) = {
[QTYPE_NONE] = NULL, /* No such object exists */
[QTYPE_QNULL] = NULL, /* qnull_ is indestructible */
[QTYPE_QINT] = qint_destroy_obj,
@@ -29,6 +29,6 @@ static void (*qdestroy[QTYPE_MAX])(QObject *) = {
void qobject_destroy(QObject *obj)
{
assert(!obj->refcnt);
- assert(QTYPE_QNULL < obj->type && obj->type < QTYPE_MAX);
+ assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
qdestroy[obj->type](obj);
}
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 2f2f7df..2071846 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -112,7 +112,7 @@ extern const int %(c_name)s_qtypes[];
def gen_alternate_qtypes(name, variants):
ret = mcgen('''
-const int %(c_name)s_qtypes[QTYPE_MAX] = {
+const int %(c_name)s_qtypes[QTYPE__MAX] = {
''',
c_name=c_name(name))
@@ -233,8 +233,15 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.defn += gen_type_cleanup(name)
def visit_enum_type(self, name, info, values, prefix):
- self._fwdecl += gen_enum(name, values, prefix)
- self._fwdefn += gen_enum_lookup(name, values, prefix)
+ # Special case for our lone builtin enum type
+ # TODO use something cleaner than existence of info
+ if not info:
+ self._btin += gen_enum(name, values, prefix)
+ if do_builtins:
+ self.defn += gen_enum_lookup(name, values, prefix)
+ else:
+ self._fwdecl += gen_enum(name, values, prefix)
+ self._fwdefn += gen_enum_lookup(name, values, prefix)
def visit_array_type(self, name, info, element_type):
if isinstance(element_type, QAPISchemaBuiltinType):
@@ -316,10 +323,11 @@ fdef.write(mcgen('''
''',
prefix=prefix))
+# To avoid circular headers, use only typedefs.h here, not qobject.h
fdecl.write(mcgen('''
#include <stdbool.h>
#include <stdint.h>
-#include "qapi/qmp/qobject.h"
+#include "qemu/typedefs.h"
'''))
schema = QAPISchema(input_file)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 94cd113..7ceda18 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -347,8 +347,15 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
isinstance(entity, QAPISchemaObjectType))
def visit_enum_type(self, name, info, values, prefix):
- self.decl += gen_visit_decl(name, scalar=True)
- self.defn += gen_visit_enum(name)
+ # Special case for our lone builtin enum type
+ # TODO use something cleaner than existence of info
+ if not info:
+ self._btin += gen_visit_decl(name, scalar=True)
+ if do_builtins:
+ self.defn += gen_visit_enum(name)
+ else:
+ self.decl += gen_visit_decl(name, scalar=True)
+ self.defn += gen_visit_enum(name)
def visit_array_type(self, name, info, element_type):
decl = gen_visit_decl(name)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index b336fbd..c9e4ad2 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -34,6 +34,7 @@ builtin_types = {
'uint64': 'QTYPE_QINT',
'size': 'QTYPE_QINT',
'any': None, # any QType possible, actually
+ 'QType': 'QTYPE_QSTRING',
}
# Whitelist of commands allowed to return a non-dictionary
@@ -1244,6 +1245,11 @@ class QAPISchema(object):
self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
[], None)
self._def_entity(self.the_empty_object_type)
+ self._def_entity(QAPISchemaEnumType('QType', None,
+ ['none', 'qnull', 'qint',
+ 'qstring', 'qdict', 'qlist',
+ 'qfloat', 'qbool'],
+ 'QTYPE'))
def _make_implicit_enum_type(self, name, info, values):
name = name + 'Kind' # Use namespace reserved by add_name()
diff --git a/tests/qapi-schema/alternate-empty.out b/tests/qapi-schema/alternate-empty.out
index 0f153b6..02b9876 100644
--- a/tests/qapi-schema/alternate-empty.out
+++ b/tests/qapi-schema/alternate-empty.out
@@ -2,3 +2,5 @@ object :empty
alternate Alt
case i: int
enum AltKind ['i']
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
--git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 9e2c656..97be601 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,2 +1,4 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
enum Status ['good', 'bad', 'ugly']
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 272b161..6522940 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1 +1,3 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index cdfd264..6350d64 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,2 +1,4 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
event oops None
diff --git a/tests/qapi-schema/flat-union-empty.out b/tests/qapi-schema/flat-union-empty.out
index 0e0665a..eade2d5 100644
--- a/tests/qapi-schema/flat-union-empty.out
+++ b/tests/qapi-schema/flat-union-empty.out
@@ -2,6 +2,8 @@ object :empty
object Base
member type: Empty optional=False
enum Empty []
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
object Union
base Base
tag type
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index f4542b1..453e0b2 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,5 +1,7 @@
object :empty
object :obj-fooA-arg
member bar1: str optional=False
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
command fooA :obj-fooA-arg -> None
gen=True success_response=True
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index 9e2c656..97be601 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -1,2 +1,4 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
enum Status ['good', 'bad', 'ugly']
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 9e2c656..97be601 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,2 +1,4 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
enum Status ['good', 'bad', 'ugly']
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 9e2c656..97be601 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,2 +1,4 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
enum Status ['good', 'bad', 'ugly']
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 226d300..ce37ff5 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,4 +1,6 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
command eins None -> None
gen=True success_response=True
command zwei None -> None
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 0724a9f..b87cfba 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -101,6 +101,8 @@ object NestedEnumsOne
member enum4: EnumOne optional=True
enum QEnumTwo ['value1', 'value2']
prefix QENUM_TWO
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
object TestStruct
member integer: int optional=False
member boolean: bool optional=False
diff --git a/tests/qapi-schema/union-clash-data.out b/tests/qapi-schema/union-clash-data.out
index cea8551..f5752f4 100644
--- a/tests/qapi-schema/union-clash-data.out
+++ b/tests/qapi-schema/union-clash-data.out
@@ -1,6 +1,8 @@
object :empty
object :obj-int-wrapper
member data: int optional=False
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
object TestUnion
member type: TestUnionKind optional=False
case data: :obj-int-wrapper
diff --git a/tests/qapi-schema/union-empty.out b/tests/qapi-schema/union-empty.out
index 9c89fd1..bdf17e5 100644
--- a/tests/qapi-schema/union-empty.out
+++ b/tests/qapi-schema/union-empty.out
@@ -1,4 +1,6 @@
object :empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+ prefix QTYPE
object Union
member type: UnionKind optional=False
enum UnionKind []
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 30/40] qapi: Simplify visiting of alternate types
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (28 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 29/40] qapi: Convert QType into QAPI built-in enum type Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 31/40] qapi-types: Drop unnedeed ._fwdefn Markus Armbruster
` (10 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Previously, working with alternates required two lookup arrays
and some indirection: for type Foo, we created Foo_qtypes[]
which maps each qtype to a value of the generated FooKind enum,
then look up that value in FooKind_lookup[] like we do for other
union types.
This has a couple of subtle bugs. First, the generator was
creating a call with a parameter '(int *) &(*obj)->type' where
type is an enum type; this is unsafe if the compiler chooses
to store the enum type in a different size than int, where
assigning through the wrong size pointer can corrupt data or
cause a SIGBUS.
Related bug, not not fixed in this patch: qapi-visit.py's
gen_visit_enum() generates a cast of its enum * argument to
int *. Marked FIXME.
Second, since the values of the FooKind enum start at zero, all
entries of the Foo_qtypes[] array that were not explicitly
initialized will map to the same branch of the union as the
first member of the alternate, rather than triggering a desired
failure in visit_get_next_type(). Fortunately, the bug seldom
bites; the very next thing the input visitor does is try to
parse the incoming JSON with the wrong parser, which normally
fails; the output visitor is not used with a C struct in that
state, and the dealloc visitor has nothing to clean up (so
there is no leak).
However, the second bug IS observable in one case: parsing an
integer causes unusual behavior in an alternate that contains
at least a 'number' member but no 'int' member, because the
'number' parser accepts QTYPE_QINT in addition to the expected
QTYPE_QFLOAT (that is, since 'int' is not a member, the type
QTYPE_QINT accidentally maps to FooKind 0; if this enum value
is the 'number' branch the integer parses successfully, but if
the 'number' branch is not first, some other branch tries to
parse the integer and rejects it). A later patch will worry
about fixing alternates to always parse all inputs that a
non-alternate 'number' would accept, for now this is still
marked FIXME in the updated test-qmp-input-visitor.c, to
merely point out that new undesired behavior of 'ans' matches
the existing undesired behavior of 'asn'.
This patch fixes the default-initialization bug by deleting the
indirection, and modifying get_next_type() to directly assign a
QTypeCode parameter. This in turn fixes the type-casting bug,
as we are no longer casting a pointer to enum to a questionable
size. There is no longer a need to generate an implicit FooKind
enum associated with the alternate type (since the QMP wire
format never uses the stringized counterparts of the C union
member names). Since the updated visit_get_next_type() does not
know which qtypes are expected, the generated visitor is
modified to generate an error statement if an unexpected type is
encountered.
Callers now have to know the QTYPE_* mapping when looking at the
discriminator; but so far, only the testsuite was even using the
C struct of an alternate types. I considered the possibility of
keeping the internal enum FooKind, but initialized differently
than most generated arrays, as in:
typedef enum FooKind {
FOO_KIND_A = QTYPE_QDICT,
FOO_KIND_B = QTYPE_QINT,
} FooKind;
to create nicer aliases for knowing when to use foo->a or foo->b
when inspecting foo->type; but it turned out to add too much
complexity, especially without a client.
There is a user-visible side effect to this change, but I
consider it to be an improvement. Previously,
the invalid QMP command:
{"execute":"blockdev-add", "arguments":{"options":
{"driver":"raw", "id":"a", "file":true}}}
failed with:
{"error": {"class": "GenericError",
"desc": "Invalid parameter type for 'file', expected: QDict"}}
(visit_get_next_type() succeeded, and the error comes from the
visit_type_BlockdevOptions() expecting {}; there is no mention of
the fact that a string would also work). Now it fails with:
{"error": {"class": "GenericError",
"desc": "Invalid parameter type for 'file', expected: BlockdevRef"}}
(the error when the next type doesn't match any expected types for
the overall alternate).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-5-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
docs/qapi-code-gen.txt | 3 ---
include/qapi/visitor-impl.h | 3 ++-
include/qapi/visitor.h | 8 +++++++-
qapi/qapi-visit-core.c | 4 ++--
qapi/qmp-input-visitor.c | 4 ++--
scripts/qapi-types.py | 34 ----------------------------------
scripts/qapi-visit.py | 15 ++++++++++-----
scripts/qapi.py | 18 +++++++++++++-----
tests/qapi-schema/alternate-empty.out | 1 -
tests/qapi-schema/qapi-schema-test.out | 8 --------
tests/test-qmp-input-visitor.c | 31 ++++++++++++++++---------------
tests/test-qmp-output-visitor.c | 4 ++--
12 files changed, 54 insertions(+), 79 deletions(-)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 79bf072..128f074 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -384,9 +384,6 @@ where each branch of the union names a QAPI type. For example:
'data': { 'definition': 'BlockdevOptions',
'reference': 'str' } }
-Just like for a simple union, an implicit C enum 'NameKind' is created
-to enumerate the branches for the alternate 'Name'.
-
Unlike a union, the discriminator string is never passed on the wire
for the Client JSON Protocol. Instead, the value's JSON type serves
as an implicit discriminator, which in turn means that an alternate
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 8c0ba57..7cd1313 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -32,7 +32,8 @@ struct Visitor
void (*type_enum)(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp);
- void (*get_next_type)(Visitor *v, int *kind, const int *qobjects,
+ /* May be NULL; only needed for input visitors. */
+ void (*get_next_type)(Visitor *v, QType *type,
const char *name, Error **errp);
void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index a2ad66c..6d25ad2 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -38,7 +38,13 @@ GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
void visit_end_list(Visitor *v, Error **errp);
void visit_optional(Visitor *v, bool *present, const char *name,
Error **errp);
-void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
+
+/**
+ * Determine the qtype of the item @name in the current object visit.
+ * For input visitors, set *@type to the correct qtype of a qapi
+ * alternate type; for other visitors, leave *@type unchanged.
+ */
+void visit_get_next_type(Visitor *v, QType *type,
const char *name, Error **errp);
void visit_type_enum(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 59ed506..850ca03 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -81,11 +81,11 @@ void visit_optional(Visitor *v, bool *present, const char *name,
}
}
-void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
+void visit_get_next_type(Visitor *v, QType *type,
const char *name, Error **errp)
{
if (v->get_next_type) {
- v->get_next_type(v, obj, qtypes, name, errp);
+ v->get_next_type(v, type, name, errp);
}
}
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index eb6e110..d398de7 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -208,7 +208,7 @@ static void qmp_input_end_list(Visitor *v, Error **errp)
qmp_input_pop(qiv, errp);
}
-static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects,
+static void qmp_input_get_next_type(Visitor *v, QType *type,
const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
@@ -218,7 +218,7 @@ static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects,
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
return;
}
- *kind = qobjects[qobject_type(qobj)];
+ *type = qobject_type(qobj);
}
static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 2071846..84ec858 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -101,38 +101,6 @@ static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
c_name=c_name(name), base=base.c_name())
-def gen_alternate_qtypes_decl(name):
- return mcgen('''
-
-extern const int %(c_name)s_qtypes[];
-''',
- c_name=c_name(name))
-
-
-def gen_alternate_qtypes(name, variants):
- ret = mcgen('''
-
-const int %(c_name)s_qtypes[QTYPE__MAX] = {
-''',
- c_name=c_name(name))
-
- for var in variants.variants:
- qtype = var.type.alternate_qtype()
- assert qtype
-
- ret += mcgen('''
- [%(qtype)s] = %(enum_const)s,
-''',
- qtype=qtype,
- enum_const=c_enum_const(variants.tag_member.type.name,
- var.name))
-
- ret += mcgen('''
-};
-''')
- return ret
-
-
def gen_variants(variants):
# FIXME: What purpose does data serve, besides preventing a union that
# has a branch named 'data'? We use it in qapi-visit.py to decide
@@ -264,9 +232,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
def visit_alternate_type(self, name, info, variants):
self._fwdecl += gen_fwd_object_or_array(name)
- self._fwdefn += gen_alternate_qtypes(name, variants)
self.decl += gen_object(name, None, [variants.tag_member], variants)
- self.decl += gen_alternate_qtypes_decl(name)
self._gen_type_cleanup(name)
# If you link code generated from multiple schemata, you want only one
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 7ceda18..4797d6e 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -172,6 +172,7 @@ out:
def gen_visit_enum(name):
+ # FIXME cast from enum *obj to int * invalidly assumes enum is int
return mcgen('''
void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp)
@@ -193,7 +194,7 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
if (err) {
goto out;
}
- visit_get_next_type(v, (int*) &(*obj)->type, %(c_name)s_qtypes, name, &err);
+ visit_get_next_type(v, &(*obj)->type, name, &err);
if (err) {
goto out_obj;
}
@@ -201,20 +202,22 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
''',
c_name=c_name(name))
+ # FIXME: When 'number' but not 'int' is present in the alternate, we
+ # should allow QTYPE_INT to promote to QTYPE_FLOAT.
for var in variants.variants:
ret += mcgen('''
case %(case)s:
visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err);
break;
''',
- case=c_enum_const(variants.tag_member.type.name,
- var.name),
+ case=var.type.alternate_qtype(),
c_type=var.type.c_name(),
c_name=c_name(var.name))
ret += mcgen('''
default:
- abort();
+ error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+ "%(name)s");
}
out_obj:
error_propagate(errp, err);
@@ -223,7 +226,8 @@ out_obj:
out:
error_propagate(errp, err);
}
-''')
+''',
+ name=name)
return ret
@@ -437,6 +441,7 @@ fdef.write(mcgen('''
fdecl.write(mcgen('''
#include "qapi/visitor.h"
+#include "qapi/qmp/qerror.h"
#include "%(prefix)sqapi-types.h"
''',
diff --git a/scripts/qapi.py b/scripts/qapi.py
index c9e4ad2..2b46dd0 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -635,8 +635,8 @@ def check_alternate(expr, expr_info):
for (key, value) in members.items():
check_name(expr_info, "Member of alternate '%s'" % name, key)
- # Check for conflicts in the generated enum
- c_key = camel_to_upper(key)
+ # Check for conflicts in the branch names
+ c_key = c_name(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Alternate '%s' member '%s' clashes with '%s'"
@@ -1092,8 +1092,11 @@ class QAPISchemaObjectTypeVariants(object):
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
for v in self.variants:
v.check(schema)
- assert v.name in self.tag_member.type.values
- if isinstance(v.type, QAPISchemaObjectType):
+ # Union names must match enum values; alternate names are
+ # checked separately. Use 'seen' to tell the two apart.
+ if seen:
+ assert v.name in self.tag_member.type.values
+ assert isinstance(v.type, QAPISchemaObjectType)
v.type.check(schema)
def check_clash(self, schema, info, seen):
@@ -1135,6 +1138,11 @@ class QAPISchemaAlternateType(QAPISchemaType):
# Not calling self.variants.check_clash(), because there's nothing
# to clash with
self.variants.check(schema, {})
+ # Alternate branch names have no relation to the tag enum values;
+ # so we have to check for potential name collisions ourselves.
+ seen = {}
+ for v in self.variants.variants:
+ v.check_clash(self.info, seen)
def json_type(self):
return 'value'
@@ -1342,7 +1350,7 @@ class QAPISchema(object):
data = expr['data']
variants = [self._make_variant(key, value)
for (key, value) in data.iteritems()]
- tag_member = self._make_implicit_tag(name, info, variants)
+ tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
self._def_entity(
QAPISchemaAlternateType(name, info,
QAPISchemaObjectTypeVariants(None,
diff --git a/tests/qapi-schema/alternate-empty.out b/tests/qapi-schema/alternate-empty.out
index 02b9876..f78f174 100644
--- a/tests/qapi-schema/alternate-empty.out
+++ b/tests/qapi-schema/alternate-empty.out
@@ -1,6 +1,5 @@
object :empty
alternate Alt
case i: int
-enum AltKind ['i']
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index b87cfba..2c546b7 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -56,27 +56,21 @@ object :obj-user_def_cmd2-arg
alternate AltIntNum
case i: int
case n: number
-enum AltIntNumKind ['i', 'n']
alternate AltNumInt
case n: number
case i: int
-enum AltNumIntKind ['n', 'i']
alternate AltNumStr
case n: number
case s: str
-enum AltNumStrKind ['n', 's']
alternate AltStrBool
case s: str
case b: bool
-enum AltStrBoolKind ['s', 'b']
alternate AltStrInt
case s: str
case i: int
-enum AltStrIntKind ['s', 'i']
alternate AltStrNum
case s: str
case n: number
-enum AltStrNumKind ['s', 'n']
event EVENT_A None
event EVENT_B None
event EVENT_C :obj-EVENT_C-arg
@@ -114,7 +108,6 @@ alternate UserDefAlternate
case uda: UserDefA
case s: str
case i: int
-enum UserDefAlternateKind ['uda', 's', 'i']
object UserDefB
member intb: int optional=False
member a-b: bool optional=True
@@ -180,7 +173,6 @@ event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
alternate __org.qemu_x-Alt
case __org.qemu_x-branch: str
case b: __org.qemu_x-Base
-enum __org.qemu_x-AltKind ['__org.qemu_x-branch', 'b']
object __org.qemu_x-Base
member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
enum __org.qemu_x-Enum ['__org.qemu_x-value']
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index d48ebdd..43b9e18 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -312,13 +312,13 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
v = visitor_input_test_init(data, "42");
visit_type_UserDefAlternate(v, &tmp, NULL, &error_abort);
- g_assert_cmpint(tmp->type, ==, USER_DEF_ALTERNATE_KIND_I);
+ g_assert_cmpint(tmp->type, ==, QTYPE_QINT);
g_assert_cmpint(tmp->u.i, ==, 42);
qapi_free_UserDefAlternate(tmp);
v = visitor_input_test_init(data, "'string'");
visit_type_UserDefAlternate(v, &tmp, NULL, &error_abort);
- g_assert_cmpint(tmp->type, ==, USER_DEF_ALTERNATE_KIND_S);
+ g_assert_cmpint(tmp->type, ==, QTYPE_QSTRING);
g_assert_cmpstr(tmp->u.s, ==, "string");
qapi_free_UserDefAlternate(tmp);
@@ -347,36 +347,37 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data,
error_free_or_abort(&err);
qapi_free_AltStrBool(asb);
- /* FIXME: Order of alternate should not affect semantics; asn should
- * parse the same as ans */
+ /* FIXME: integer should parse as number */
v = visitor_input_test_init(data, "42");
visit_type_AltStrNum(v, &asn, NULL, &err);
- /* FIXME g_assert_cmpint(asn->type, == ALT_STR_NUM_KIND_N); */
+ /* FIXME g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT); */
/* FIXME g_assert_cmpfloat(asn->u.n, ==, 42); */
error_free_or_abort(&err);
qapi_free_AltStrNum(asn);
+ /* FIXME: integer should parse as number */
v = visitor_input_test_init(data, "42");
- visit_type_AltNumStr(v, &ans, NULL, &error_abort);
- g_assert_cmpint(ans->type, ==, ALT_NUM_STR_KIND_N);
- g_assert_cmpfloat(ans->u.n, ==, 42);
+ visit_type_AltNumStr(v, &ans, NULL, &err);
+ /* FIXME g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT); */
+ /* FIXME g_assert_cmpfloat(ans->u.n, ==, 42); */
+ error_free_or_abort(&err);
qapi_free_AltNumStr(ans);
v = visitor_input_test_init(data, "42");
visit_type_AltStrInt(v, &asi, NULL, &error_abort);
- g_assert_cmpint(asi->type, ==, ALT_STR_INT_KIND_I);
+ g_assert_cmpint(asi->type, ==, QTYPE_QINT);
g_assert_cmpint(asi->u.i, ==, 42);
qapi_free_AltStrInt(asi);
v = visitor_input_test_init(data, "42");
visit_type_AltIntNum(v, &ain, NULL, &error_abort);
- g_assert_cmpint(ain->type, ==, ALT_INT_NUM_KIND_I);
+ g_assert_cmpint(ain->type, ==, QTYPE_QINT);
g_assert_cmpint(ain->u.i, ==, 42);
qapi_free_AltIntNum(ain);
v = visitor_input_test_init(data, "42");
visit_type_AltNumInt(v, &ani, NULL, &error_abort);
- g_assert_cmpint(ani->type, ==, ALT_NUM_INT_KIND_I);
+ g_assert_cmpint(ani->type, ==, QTYPE_QINT);
g_assert_cmpint(ani->u.i, ==, 42);
qapi_free_AltNumInt(ani);
@@ -389,13 +390,13 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data,
v = visitor_input_test_init(data, "42.5");
visit_type_AltStrNum(v, &asn, NULL, &error_abort);
- g_assert_cmpint(asn->type, ==, ALT_STR_NUM_KIND_N);
+ g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT);
g_assert_cmpfloat(asn->u.n, ==, 42.5);
qapi_free_AltStrNum(asn);
v = visitor_input_test_init(data, "42.5");
visit_type_AltNumStr(v, &ans, NULL, &error_abort);
- g_assert_cmpint(ans->type, ==, ALT_NUM_STR_KIND_N);
+ g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT);
g_assert_cmpfloat(ans->u.n, ==, 42.5);
qapi_free_AltNumStr(ans);
@@ -406,13 +407,13 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data,
v = visitor_input_test_init(data, "42.5");
visit_type_AltIntNum(v, &ain, NULL, &error_abort);
- g_assert_cmpint(ain->type, ==, ALT_INT_NUM_KIND_N);
+ g_assert_cmpint(ain->type, ==, QTYPE_QFLOAT);
g_assert_cmpfloat(ain->u.n, ==, 42.5);
qapi_free_AltIntNum(ain);
v = visitor_input_test_init(data, "42.5");
visit_type_AltNumInt(v, &ani, NULL, &error_abort);
- g_assert_cmpint(ani->type, ==, ALT_NUM_INT_KIND_N);
+ g_assert_cmpint(ani->type, ==, QTYPE_QFLOAT);
g_assert_cmpfloat(ani->u.n, ==, 42.5);
qapi_free_AltNumInt(ani);
}
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 4196e66..3078442 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -428,7 +428,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
UserDefAlternate *tmp;
tmp = g_new0(UserDefAlternate, 1);
- tmp->type = USER_DEF_ALTERNATE_KIND_I;
+ tmp->type = QTYPE_QINT;
tmp->u.i = 42;
visit_type_UserDefAlternate(data->ov, &tmp, NULL, &error_abort);
@@ -441,7 +441,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
qobject_decref(arg);
tmp = g_new0(UserDefAlternate, 1);
- tmp->type = USER_DEF_ALTERNATE_KIND_S;
+ tmp->type = QTYPE_QSTRING;
tmp->u.s = g_strdup("hello");
visit_type_UserDefAlternate(data->ov, &tmp, NULL, &error_abort);
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 31/40] qapi-types: Drop unnedeed ._fwdefn
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (29 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 30/40] qapi: Simplify visiting of alternate types Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 32/40] qapi: Inline _make_implicit_tag() Markus Armbruster
` (9 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Previously, the generated code in qapi-types.c initialized all
enum lookup tables first, prior to any other definitions. But
there are no topological sorting requirements that mandate this
layout, so we can drop the QAPISchemaGenTypeVisitor._fwdefn
field and just generate all definitions in visitation order.
The generated code shows some churn due to reordering, but it
is still fairly straightforward to follow (all the deletions
occur in one hunk, and all the deleted lines are re-inserted
in the same order later in the same files, just spread across
multiple insertion points).
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-6-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi-types.py | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 84ec858..0d86269 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -168,21 +168,17 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.decl = None
self.defn = None
self._fwdecl = None
- self._fwdefn = None
self._btin = None
def visit_begin(self, schema):
self.decl = ''
self.defn = ''
self._fwdecl = ''
- self._fwdefn = ''
self._btin = guardstart('QAPI_TYPES_BUILTIN')
def visit_end(self):
self.decl = self._fwdecl + self.decl
self._fwdecl = None
- self.defn = self._fwdefn + self.defn
- self._fwdefn = None
# To avoid header dependency hell, we always generate
# declarations for built-in types in our header files and
# simply guard them. See also do_builtins (command line
@@ -209,7 +205,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.defn += gen_enum_lookup(name, values, prefix)
else:
self._fwdecl += gen_enum(name, values, prefix)
- self._fwdefn += gen_enum_lookup(name, values, prefix)
+ self.defn += gen_enum_lookup(name, values, prefix)
def visit_array_type(self, name, info, element_type):
if isinstance(element_type, QAPISchemaBuiltinType):
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 32/40] qapi: Inline _make_implicit_tag()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (30 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 31/40] qapi-types: Drop unnedeed ._fwdefn Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 33/40] qapi: Fix alternates that accept 'number' but not 'int' Markus Armbruster
` (8 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Now that alternates no longer use an implicit tag, we can
inline _make_implicit_tag() into its one caller,
_def_union_type().
No change to generated code.
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-7-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 2b46dd0..7e6c396 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1319,11 +1319,6 @@ class QAPISchema(object):
typ, info, 'wrapper', [self._make_member('data', typ, info)])
return QAPISchemaObjectTypeVariant(case, typ)
- def _make_implicit_tag(self, type_name, info, variants):
- typ = self._make_implicit_enum_type(type_name, info,
- [v.name for v in variants])
- return QAPISchemaObjectTypeMember('type', typ, False)
-
def _def_union_type(self, expr, info):
name = expr['union']
data = expr['data']
@@ -1337,7 +1332,9 @@ class QAPISchema(object):
else:
variants = [self._make_simple_variant(key, value, info)
for (key, value) in data.iteritems()]
- tag_member = self._make_implicit_tag(name, info, variants)
+ typ = self._make_implicit_enum_type(name, info,
+ [v.name for v in variants])
+ tag_member = QAPISchemaObjectTypeMember('type', typ, False)
members = [tag_member]
self._def_entity(
QAPISchemaObjectType(name, info, base, members,
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 33/40] qapi: Fix alternates that accept 'number' but not 'int'
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (31 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 32/40] qapi: Inline _make_implicit_tag() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 34/40] qapi: Simplify visits of optional fields Markus Armbruster
` (7 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
The QMP input visitor allows integral values to be assigned by
promotion to a QTYPE_QFLOAT. However, when parsing an alternate,
we did not take this into account, such that an alternate that
accepts 'number' and some other type, but not 'int', would reject
integral values.
With this patch, we now have the following desirable table:
alternate has case selected for
'int' 'number' QTYPE_QINT QTYPE_QFLOAT
no no error error
no yes 'number' 'number'
yes no 'int' error
yes yes 'int' 'number'
While it is unlikely that we will ever use 'number' in an
alternate other than in the testsuite, it never hurts to be
more precise in what we allow.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-8-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/visitor-impl.h | 2 +-
include/qapi/visitor.h | 3 ++-
qapi/qapi-visit-core.c | 4 ++--
qapi/qmp-input-visitor.c | 5 ++++-
scripts/qapi-visit.py | 11 +++++++----
tests/test-qmp-input-visitor.c | 16 ++++++----------
6 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 7cd1313..7419684 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -33,7 +33,7 @@ struct Visitor
void (*type_enum)(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp);
/* May be NULL; only needed for input visitors. */
- void (*get_next_type)(Visitor *v, QType *type,
+ void (*get_next_type)(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp);
void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 6d25ad2..1414de1 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -43,8 +43,9 @@ void visit_optional(Visitor *v, bool *present, const char *name,
* Determine the qtype of the item @name in the current object visit.
* For input visitors, set *@type to the correct qtype of a qapi
* alternate type; for other visitors, leave *@type unchanged.
+ * If @promote_int, treat integers as QTYPE_FLOAT.
*/
-void visit_get_next_type(Visitor *v, QType *type,
+void visit_get_next_type(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp);
void visit_type_enum(Visitor *v, int *obj, const char * const strings[],
const char *kind, const char *name, Error **errp);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 850ca03..cee76bc 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -81,11 +81,11 @@ void visit_optional(Visitor *v, bool *present, const char *name,
}
}
-void visit_get_next_type(Visitor *v, QType *type,
+void visit_get_next_type(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp)
{
if (v->get_next_type) {
- v->get_next_type(v, type, name, errp);
+ v->get_next_type(v, type, promote_int, name, errp);
}
}
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index d398de7..26b7414 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -208,7 +208,7 @@ static void qmp_input_end_list(Visitor *v, Error **errp)
qmp_input_pop(qiv, errp);
}
-static void qmp_input_get_next_type(Visitor *v, QType *type,
+static void qmp_input_get_next_type(Visitor *v, QType *type, bool promote_int,
const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
@@ -219,6 +219,9 @@ static void qmp_input_get_next_type(Visitor *v, QType *type,
return;
}
*type = qobject_type(qobj);
+ if (promote_int && *type == QTYPE_QINT) {
+ *type = QTYPE_QFLOAT;
+ }
}
static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 4797d6e..b93690b 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -184,6 +184,11 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error
def gen_visit_alternate(name, variants):
+ promote_int = 'true'
+ for var in variants.variants:
+ if var.type.alternate_qtype() == 'QTYPE_QINT':
+ promote_int = 'false'
+
ret = mcgen('''
void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
@@ -194,16 +199,14 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
if (err) {
goto out;
}
- visit_get_next_type(v, &(*obj)->type, name, &err);
+ visit_get_next_type(v, &(*obj)->type, %(promote_int)s, name, &err);
if (err) {
goto out_obj;
}
switch ((*obj)->type) {
''',
- c_name=c_name(name))
+ c_name=c_name(name), promote_int=promote_int)
- # FIXME: When 'number' but not 'int' is present in the alternate, we
- # should allow QTYPE_INT to promote to QTYPE_FLOAT.
for var in variants.variants:
ret += mcgen('''
case %(case)s:
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 43b9e18..b4a5bee 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -347,20 +347,16 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data,
error_free_or_abort(&err);
qapi_free_AltStrBool(asb);
- /* FIXME: integer should parse as number */
v = visitor_input_test_init(data, "42");
- visit_type_AltStrNum(v, &asn, NULL, &err);
- /* FIXME g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT); */
- /* FIXME g_assert_cmpfloat(asn->u.n, ==, 42); */
- error_free_or_abort(&err);
+ visit_type_AltStrNum(v, &asn, NULL, &error_abort);
+ g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT);
+ g_assert_cmpfloat(asn->u.n, ==, 42);
qapi_free_AltStrNum(asn);
- /* FIXME: integer should parse as number */
v = visitor_input_test_init(data, "42");
- visit_type_AltNumStr(v, &ans, NULL, &err);
- /* FIXME g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT); */
- /* FIXME g_assert_cmpfloat(ans->u.n, ==, 42); */
- error_free_or_abort(&err);
+ visit_type_AltNumStr(v, &ans, NULL, &error_abort);
+ g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT);
+ g_assert_cmpfloat(ans->u.n, ==, 42);
qapi_free_AltNumStr(ans);
v = visitor_input_test_init(data, "42");
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 34/40] qapi: Simplify visits of optional fields
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (32 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 33/40] qapi: Fix alternates that accept 'number' but not 'int' Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 35/40] qapi: Shorter " Markus Armbruster
` (6 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
None of the visitor callbacks would set an error when testing
if an optional field was present; make this part of the interface
contract by eliminating the errp argument.
The resulting generated code has a nice diff:
|- visit_optional(v, &has_fdset_id, "fdset-id", &err);
|- if (err) {
|- goto out;
|- }
|+ visit_optional(v, &has_fdset_id, "fdset-id");
| if (has_fdset_id) {
| visit_type_int(v, &fdset_id, "fdset-id", &err);
| if (err) {
| goto out;
| }
| }
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-9-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/visitor-impl.h | 5 ++---
include/qapi/visitor.h | 10 ++++++++--
qapi/opts-visitor.c | 2 +-
qapi/qapi-visit-core.c | 5 ++---
qapi/qmp-input-visitor.c | 3 +--
qapi/string-input-visitor.c | 3 +--
scripts/qapi.py | 8 ++------
7 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 7419684..44a21b7 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -44,9 +44,8 @@ struct Visitor
void (*type_any)(Visitor *v, QObject **obj, const char *name,
Error **errp);
- /* May be NULL */
- void (*optional)(Visitor *v, bool *present, const char *name,
- Error **errp);
+ /* May be NULL; most useful for input visitors. */
+ void (*optional)(Visitor *v, bool *present, const char *name);
void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp);
void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp);
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 1414de1..9be60d4 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -36,8 +36,14 @@ void visit_end_implicit_struct(Visitor *v, Error **errp);
void visit_start_list(Visitor *v, const char *name, Error **errp);
GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
void visit_end_list(Visitor *v, Error **errp);
-void visit_optional(Visitor *v, bool *present, const char *name,
- Error **errp);
+
+/**
+ * Check if an optional member @name of an object needs visiting.
+ * For input visitors, set *@present according to whether the
+ * corresponding visit_type_*() needs calling; for other visitors,
+ * leave *@present unchanged.
+ */
+void visit_optional(Visitor *v, bool *present, const char *name);
/**
* Determine the qtype of the item @name in the current object visit.
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index cd10392..ef5fb8b 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -488,7 +488,7 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
static void
-opts_optional(Visitor *v, bool *present, const char *name, Error **errp)
+opts_optional(Visitor *v, bool *present, const char *name)
{
OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index cee76bc..e07d6f9 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -73,11 +73,10 @@ void visit_end_union(Visitor *v, bool data_present, Error **errp)
}
}
-void visit_optional(Visitor *v, bool *present, const char *name,
- Error **errp)
+void visit_optional(Visitor *v, bool *present, const char *name)
{
if (v->optional) {
- v->optional(v, present, name, errp);
+ v->optional(v, present, name);
}
}
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 26b7414..932b5f3 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -303,8 +303,7 @@ static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name,
*obj = qobj;
}
-static void qmp_input_optional(Visitor *v, bool *present, const char *name,
- Error **errp)
+static void qmp_input_optional(Visitor *v, bool *present, const char *name)
{
QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true);
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index bbd6a54..dee780a 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -299,8 +299,7 @@ static void parse_type_number(Visitor *v, double *obj, const char *name,
*obj = val;
}
-static void parse_optional(Visitor *v, bool *present, const char *name,
- Error **errp)
+static void parse_optional(Visitor *v, bool *present, const char *name)
{
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 7e6c396..8bf41db 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1656,15 +1656,11 @@ def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
for memb in members:
if memb.optional:
ret += mcgen('''
- visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
+ visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s");
+ if (%(prefix)shas_%(c_name)s) {
''',
prefix=prefix, c_name=c_name(memb.name),
name=memb.name, errp=errparg)
- ret += gen_err_check(skiperr=skiperr)
- ret += mcgen('''
- if (%(prefix)shas_%(c_name)s) {
-''',
- prefix=prefix, c_name=c_name(memb.name))
push_indent()
# Ugly: sometimes we need to cast away const
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 35/40] qapi: Shorter visits of optional fields
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (33 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 34/40] qapi: Simplify visits of optional fields Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 36/40] qapi: Prepare new QAPISchemaMember base class Markus Armbruster
` (5 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
For less code, reflect the determined boolean value of an optional
visit back to the caller instead of making the caller read the
boolean after the fact.
The resulting generated code has the following diff:
|- visit_optional(v, &has_fdset_id, "fdset-id");
|- if (has_fdset_id) {
|+ if (visit_optional(v, &has_fdset_id, "fdset-id")) {
| visit_type_int(v, &fdset_id, "fdset-id", &err);
| if (err) {
| goto out;
| }
| }
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-10-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
include/qapi/visitor.h | 4 ++--
qapi/qapi-visit-core.c | 3 ++-
scripts/qapi.py | 3 +--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 9be60d4..a14a16d 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -41,9 +41,9 @@ void visit_end_list(Visitor *v, Error **errp);
* Check if an optional member @name of an object needs visiting.
* For input visitors, set *@present according to whether the
* corresponding visit_type_*() needs calling; for other visitors,
- * leave *@present unchanged.
+ * leave *@present unchanged. Return *@present for convenience.
*/
-void visit_optional(Visitor *v, bool *present, const char *name);
+bool visit_optional(Visitor *v, bool *present, const char *name);
/**
* Determine the qtype of the item @name in the current object visit.
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index e07d6f9..6d63e40 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -73,11 +73,12 @@ void visit_end_union(Visitor *v, bool data_present, Error **errp)
}
}
-void visit_optional(Visitor *v, bool *present, const char *name)
+bool visit_optional(Visitor *v, bool *present, const char *name)
{
if (v->optional) {
v->optional(v, present, name);
}
+ return *present;
}
void visit_get_next_type(Visitor *v, QType *type, bool promote_int,
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8bf41db..58ecdf2 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1656,8 +1656,7 @@ def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
for memb in members:
if memb.optional:
ret += mcgen('''
- visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s");
- if (%(prefix)shas_%(c_name)s) {
+ if (visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s")) {
''',
prefix=prefix, c_name=c_name(memb.name),
name=memb.name, errp=errparg)
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 36/40] qapi: Prepare new QAPISchemaMember base class
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (34 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 35/40] qapi: Shorter " Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 37/40] qapi: Track enum values by QAPISchemaMember, not string Markus Armbruster
` (4 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
We want to share some clash detection code between enum values
and object type members. To assist with that, split off part
of QAPISchemaObjectTypeMember into a new base class
QAPISchemaMember that tracks name, owner, and common clash
detection code; while the former keeps the additional fields
for type and optional flag.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-11-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 58ecdf2..168463a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1018,28 +1018,18 @@ class QAPISchemaObjectType(QAPISchemaType):
self.members, self.variants)
-class QAPISchemaObjectTypeMember(object):
+class QAPISchemaMember(object):
role = 'member'
- def __init__(self, name, typ, optional):
+ def __init__(self, name):
assert isinstance(name, str)
- assert isinstance(typ, str)
- assert isinstance(optional, bool)
self.name = name
- self._type_name = typ
- self.type = None
- self.optional = optional
self.owner = None
def set_owner(self, name):
assert not self.owner
self.owner = name
- def check(self, schema):
- assert self.owner
- self.type = schema.lookup_type(self._type_name)
- assert self.type
-
def check_clash(self, info, seen):
cname = c_name(self.name)
if cname in seen:
@@ -1066,6 +1056,21 @@ class QAPISchemaObjectTypeMember(object):
return "'%s' %s" % (self.name, self._pretty_owner())
+class QAPISchemaObjectTypeMember(QAPISchemaMember):
+ def __init__(self, name, typ, optional):
+ QAPISchemaMember.__init__(self, name)
+ assert isinstance(typ, str)
+ assert isinstance(optional, bool)
+ self._type_name = typ
+ self.type = None
+ self.optional = optional
+
+ def check(self, schema):
+ assert self.owner
+ self.type = schema.lookup_type(self._type_name)
+ assert self.type
+
+
class QAPISchemaObjectTypeVariants(object):
def __init__(self, tag_name, tag_member, variants):
# Flat unions pass tag_name but not tag_member.
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 37/40] qapi: Track enum values by QAPISchemaMember, not string
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (35 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 36/40] qapi: Prepare new QAPISchemaMember base class Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 38/40] qapi: Enforce (or whitelist) case conventions on qapi members Markus Armbruster
` (3 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
Rather than using just an array of strings, make enum.values be
an array of the new QAPISchemaMember type, and add a helper
member_names() method to get back at the original list of names.
Likewise, creating an enum requires wrapping strings, via a new
QAPISchema._make_enum_members() method. The benefit of wrapping
enum members in a QAPISchemaMember Python object is that we now
share the existing code for C name clash detection (although the
code is not yet active until a later commit removes the earlier
ad hoc parser checks).
In a related change, the QAPISchemaMember._pretty_owner() method
needs to learn about one more implicit type name: the generated
enum associated with a simple union.
In the interest of keeping the changes of this patch local to one
file, the visitor interface still passes just a list of names
rather than the full list of QAPISchemaMember instances. We may
want to revisit this in the future, if the consistency with
visit_object_type() is worth it.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-12-git-send-email-eblake@redhat.com>
[Eric's simplifying followup squashed in]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 168463a..07e8303 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -901,13 +901,16 @@ class QAPISchemaEnumType(QAPISchemaType):
def __init__(self, name, info, values, prefix):
QAPISchemaType.__init__(self, name, info)
for v in values:
- assert isinstance(v, str)
+ assert isinstance(v, QAPISchemaMember)
+ v.set_owner(name)
assert prefix is None or isinstance(prefix, str)
self.values = values
self.prefix = prefix
def check(self, schema):
- assert len(set(self.values)) == len(self.values)
+ seen = {}
+ for v in self.values:
+ v.check_clash(self.info, seen)
def is_implicit(self):
# See QAPISchema._make_implicit_enum_type()
@@ -916,8 +919,11 @@ class QAPISchemaEnumType(QAPISchemaType):
def c_type(self, is_param=False):
return c_name(self.name)
+ def member_names(self):
+ return [v.name for v in self.values]
+
def c_null(self):
- return c_enum_const(self.name, (self.values + ['_MAX'])[0],
+ return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
self.prefix)
def json_type(self):
@@ -925,7 +931,7 @@ class QAPISchemaEnumType(QAPISchemaType):
def visit(self, visitor):
visitor.visit_enum_type(self.name, self.info,
- self.values, self.prefix)
+ self.member_names(), self.prefix)
class QAPISchemaArrayType(QAPISchemaType):
@@ -1050,6 +1056,9 @@ class QAPISchemaMember(object):
assert owner.endswith('-wrapper')
# Unreachable and not implemented
assert False
+ if owner.endswith('Kind'):
+ # See QAPISchema._make_implicit_enum_type()
+ return '(branch of %s)' % owner[:-4]
return '(%s of %s)' % (self.role, owner)
def describe(self):
@@ -1100,7 +1109,7 @@ class QAPISchemaObjectTypeVariants(object):
# Union names must match enum values; alternate names are
# checked separately. Use 'seen' to tell the two apart.
if seen:
- assert v.name in self.tag_member.type.values
+ assert v.name in self.tag_member.type.member_names()
assert isinstance(v.type, QAPISchemaObjectType)
v.type.check(schema)
@@ -1258,15 +1267,20 @@ class QAPISchema(object):
self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
[], None)
self._def_entity(self.the_empty_object_type)
- self._def_entity(QAPISchemaEnumType('QType', None,
- ['none', 'qnull', 'qint',
- 'qstring', 'qdict', 'qlist',
- 'qfloat', 'qbool'],
+ qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
+ 'qstring', 'qdict', 'qlist',
+ 'qfloat', 'qbool'])
+ self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
'QTYPE'))
+ def _make_enum_members(self, values):
+ return [QAPISchemaMember(v) for v in values]
+
def _make_implicit_enum_type(self, name, info, values):
+ # See also QAPISchemaObjectTypeMember._pretty_owner()
name = name + 'Kind' # Use namespace reserved by add_name()
- self._def_entity(QAPISchemaEnumType(name, info, values, None))
+ self._def_entity(QAPISchemaEnumType(
+ name, info, self._make_enum_members(values), None))
return name
def _make_array_type(self, element_type, info):
@@ -1289,7 +1303,8 @@ class QAPISchema(object):
name = expr['enum']
data = expr['data']
prefix = expr.get('prefix')
- self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
+ self._def_entity(QAPISchemaEnumType(
+ name, info, self._make_enum_members(data), prefix))
def _make_member(self, name, typ, info):
optional = False
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 38/40] qapi: Enforce (or whitelist) case conventions on qapi members
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (36 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 37/40] qapi: Track enum values by QAPISchemaMember, not string Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 39/40] qapi: Move duplicate collision checks to schema check() Markus Armbruster
` (2 subsequent siblings)
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
We document that members of enums and objects should be
'lower-case', although we were not enforcing it. We have to
whitelist a few pre-existing entities that violate the norms.
Add three new tests to expose the new error message, each of
which first uses the whitelisted name 'UuidInfo' to prove the
whitelist works, then triggers the failure (this is the same
pattern used in the existing returns-whitelist.json test).
Note that by adding this check, we have effectively forbidden
an entity with a case-insensitive clash of member names, for
any entity that is not on the whitelist (although there is
still the possibility to clash via '-' vs. '_').
Not done here: a future patch should also add naming convention
support and whitelist exceptions for command, event, and type
names.
The additions to QAPISchemaMember.check_clash() check whether
info['name'] is in the whitelist (the top-most entity name at
the point 'info' tracks), rather than self.owner (the type,
possibly implicit, that directly owns the member), because it
is easier to maintain the whitelist by the names actually in
the user's .json file, rather than worrying about the names
of implicit types.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-14-git-send-email-eblake@redhat.com>
[Simplified a bit as per discussion with Eric]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 17 +++++++++++++++++
tests/Makefile | 3 +++
tests/qapi-schema/args-member-case.err | 1 +
tests/qapi-schema/args-member-case.exit | 1 +
tests/qapi-schema/args-member-case.json | 2 ++
tests/qapi-schema/args-member-case.out | 0
tests/qapi-schema/enum-member-case.err | 1 +
tests/qapi-schema/enum-member-case.exit | 1 +
tests/qapi-schema/enum-member-case.json | 3 +++
tests/qapi-schema/enum-member-case.out | 0
tests/qapi-schema/union-branch-case.err | 1 +
tests/qapi-schema/union-branch-case.exit | 1 +
tests/qapi-schema/union-branch-case.json | 2 ++
tests/qapi-schema/union-branch-case.out | 0
14 files changed, 33 insertions(+)
create mode 100644 tests/qapi-schema/args-member-case.err
create mode 100644 tests/qapi-schema/args-member-case.exit
create mode 100644 tests/qapi-schema/args-member-case.json
create mode 100644 tests/qapi-schema/args-member-case.out
create mode 100644 tests/qapi-schema/enum-member-case.err
create mode 100644 tests/qapi-schema/enum-member-case.exit
create mode 100644 tests/qapi-schema/enum-member-case.json
create mode 100644 tests/qapi-schema/enum-member-case.out
create mode 100644 tests/qapi-schema/union-branch-case.err
create mode 100644 tests/qapi-schema/union-branch-case.exit
create mode 100644 tests/qapi-schema/union-branch-case.json
create mode 100644 tests/qapi-schema/union-branch-case.out
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 07e8303..74a561a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -59,6 +59,20 @@ returns_whitelist = [
'guest-sync-delimited',
]
+# Whitelist of entities allowed to violate case conventions
+case_whitelist = [
+ # From QMP:
+ 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
+ 'CpuInfoBase', # CPU, visible through query-cpu
+ 'CpuInfoMIPS', # PC, visible through query-cpu
+ 'CpuInfoTricore', # PC, visible through query-cpu
+ 'InputAxis', # TODO: drop when x-input-send-event is fixed
+ 'InputButton', # TODO: drop when x-input-send-event is fixed
+ 'QapiErrorClass', # all members, visible through errors
+ 'UuidInfo', # UUID, visible through query-uuid
+ 'X86CPURegister32', # all members, visible indirectly through qom-get
+]
+
enum_types = []
struct_types = []
union_types = []
@@ -1038,6 +1052,9 @@ class QAPISchemaMember(object):
def check_clash(self, info, seen):
cname = c_name(self.name)
+ if cname.lower() != cname and self.owner not in case_whitelist:
+ raise QAPIExprError(info,
+ "%s should not use uppercase" % self.describe())
if cname in seen:
raise QAPIExprError(info,
"%s collides with %s"
diff --git a/tests/Makefile b/tests/Makefile
index 0f4914c..6b8b112 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -246,6 +246,7 @@ qapi-schema += args-array-unknown.json
qapi-schema += args-int.json
qapi-schema += args-invalid.json
qapi-schema += args-member-array-bad.json
+qapi-schema += args-member-case.json
qapi-schema += args-member-unknown.json
qapi-schema += args-name-clash.json
qapi-schema += args-union.json
@@ -267,6 +268,7 @@ qapi-schema += enum-bad-prefix.json
qapi-schema += enum-clash-member.json
qapi-schema += enum-dict-member.json
qapi-schema += enum-int-member.json
+qapi-schema += enum-member-case.json
qapi-schema += enum-missing-data.json
qapi-schema += enum-wrong-data.json
qapi-schema += escape-outside-string.json
@@ -341,6 +343,7 @@ qapi-schema += unclosed-string.json
qapi-schema += unicode-str.json
qapi-schema += union-bad-branch.json
qapi-schema += union-base-no-discriminator.json
+qapi-schema += union-branch-case.json
qapi-schema += union-clash-branches.json
qapi-schema += union-clash-data.json
qapi-schema += union-empty.json
diff --git a/tests/qapi-schema/args-member-case.err b/tests/qapi-schema/args-member-case.err
new file mode 100644
index 0000000..19c4426
--- /dev/null
+++ b/tests/qapi-schema/args-member-case.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase
diff --git a/tests/qapi-schema/args-member-case.exit b/tests/qapi-schema/args-member-case.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/args-member-case.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/args-member-case.json b/tests/qapi-schema/args-member-case.json
new file mode 100644
index 0000000..93439be
--- /dev/null
+++ b/tests/qapi-schema/args-member-case.json
@@ -0,0 +1,2 @@
+# Member names should be 'lower-case' unless the struct/command is whitelisted
+{ 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } }
diff --git a/tests/qapi-schema/args-member-case.out b/tests/qapi-schema/args-member-case.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/enum-member-case.err b/tests/qapi-schema/enum-member-case.err
new file mode 100644
index 0000000..b652e9a
--- /dev/null
+++ b/tests/qapi-schema/enum-member-case.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-member-case.json:3: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase
diff --git a/tests/qapi-schema/enum-member-case.exit b/tests/qapi-schema/enum-member-case.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/enum-member-case.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-member-case.json b/tests/qapi-schema/enum-member-case.json
new file mode 100644
index 0000000..2096b35
--- /dev/null
+++ b/tests/qapi-schema/enum-member-case.json
@@ -0,0 +1,3 @@
+# Member names should be 'lower-case' unless the enum is whitelisted
+{ 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted
+{ 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] }
diff --git a/tests/qapi-schema/enum-member-case.out b/tests/qapi-schema/enum-member-case.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/union-branch-case.err b/tests/qapi-schema/union-branch-case.err
new file mode 100644
index 0000000..1152190
--- /dev/null
+++ b/tests/qapi-schema/union-branch-case.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-branch-case.json:2: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase
diff --git a/tests/qapi-schema/union-branch-case.exit b/tests/qapi-schema/union-branch-case.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/union-branch-case.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-branch-case.json b/tests/qapi-schema/union-branch-case.json
new file mode 100644
index 0000000..e6565dc
--- /dev/null
+++ b/tests/qapi-schema/union-branch-case.json
@@ -0,0 +1,2 @@
+# Branch names should be 'lower-case' unless the union is whitelisted
+{ 'union': 'NoWayThisWillGetWhitelisted', 'data': { 'Branch': 'int' } }
diff --git a/tests/qapi-schema/union-branch-case.out b/tests/qapi-schema/union-branch-case.out
new file mode 100644
index 0000000..e69de29
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 39/40] qapi: Move duplicate collision checks to schema check()
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (37 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 38/40] qapi: Enforce (or whitelist) case conventions on qapi members Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 40/40] qapi: Detect base class loops Markus Armbruster
2015-12-17 12:39 ` [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Peter Maydell
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
With the recent commit 'qapi: Detect collisions in C member
names', we have two different locations for detecting clashes -
one at parse time, and another at QAPISchema*.check() time.
Remove all of the ad hoc parser checks, and delete associated
code (for example, the global check_member_clash() method is
no longer needed).
Testing this showed that the test union-bad-branch wasn't adding
much: union-clash-branches also exposes the error message when
branches collide, and we've recently fixed things to avoid an
implicit collision with max. Likewise, the error for
enum-clash-member changes to report our new detection of
upper case in a value name, unless we modify the test to use
all lower case.
The wording of several error messages has changed, but the
change is generally an improvement rather than a regression.
No change to generated code.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-15-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 51 +--------------------------
tests/Makefile | 1 -
tests/qapi-schema/alternate-clash.err | 2 +-
tests/qapi-schema/enum-clash-member.err | 2 +-
tests/qapi-schema/enum-clash-member.json | 2 +-
tests/qapi-schema/flat-union-clash-member.err | 2 +-
tests/qapi-schema/struct-base-clash-deep.err | 2 +-
tests/qapi-schema/struct-base-clash.err | 2 +-
tests/qapi-schema/union-bad-branch.err | 1 -
tests/qapi-schema/union-bad-branch.exit | 1 -
tests/qapi-schema/union-bad-branch.json | 8 -----
tests/qapi-schema/union-bad-branch.out | 0
tests/qapi-schema/union-clash-branches.err | 2 +-
tests/qapi-schema/union-clash-branches.json | 2 +-
14 files changed, 9 insertions(+), 69 deletions(-)
delete mode 100644 tests/qapi-schema/union-bad-branch.err
delete mode 100644 tests/qapi-schema/union-bad-branch.exit
delete mode 100644 tests/qapi-schema/union-bad-branch.json
delete mode 100644 tests/qapi-schema/union-bad-branch.out
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 74a561a..8edfd79 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -519,21 +519,6 @@ def check_type(expr_info, source, value, allow_array=False,
'enum'])
-def check_member_clash(expr_info, base_name, data, source=""):
- base = find_struct(base_name)
- assert base
- base_members = base['data']
- for key in data.keys():
- if key.startswith('*'):
- key = key[1:]
- if key in base_members or "*" + key in base_members:
- raise QAPIExprError(expr_info,
- "Member name '%s'%s clashes with base '%s'"
- % (key, source, base_name))
- if base.get('base'):
- check_member_clash(expr_info, base['base'], data, source)
-
-
def check_command(expr, expr_info):
name = expr['command']
@@ -563,7 +548,6 @@ def check_union(expr, expr_info):
base = expr.get('base')
discriminator = expr.get('discriminator')
members = expr['data']
- values = {}
# Two types of unions, determined by discriminator.
@@ -610,15 +594,9 @@ def check_union(expr, expr_info):
for (key, value) in members.items():
check_name(expr_info, "Member of union '%s'" % name, key)
- # Each value must name a known type; furthermore, in flat unions,
- # branches must be a struct with no overlapping member names
+ # Each value must name a known type
check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
value, allow_array=not base, allow_metas=allow_metas)
- if base:
- branch_struct = find_struct(value)
- assert branch_struct
- check_member_clash(expr_info, base, branch_struct['data'],
- " of branch '%s'" % key)
# If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type.
@@ -629,34 +607,16 @@ def check_union(expr, expr_info):
"enum '%s'" %
(key, enum_define["enum_name"]))
- # Otherwise, check for conflicts in the generated enum
- else:
- c_key = camel_to_upper(key)
- if c_key in values:
- raise QAPIExprError(expr_info,
- "Union '%s' member '%s' clashes with '%s'"
- % (name, key, values[c_key]))
- values[c_key] = key
-
def check_alternate(expr, expr_info):
name = expr['alternate']
members = expr['data']
- values = {}
types_seen = {}
# Check every branch
for (key, value) in members.items():
check_name(expr_info, "Member of alternate '%s'" % name, key)
- # Check for conflicts in the branch names
- c_key = c_name(key)
- if c_key in values:
- raise QAPIExprError(expr_info,
- "Alternate '%s' member '%s' clashes with '%s'"
- % (name, key, values[c_key]))
- values[c_key] = key
-
# Ensure alternates have no type conflicts.
check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
value,
@@ -675,7 +635,6 @@ def check_enum(expr, expr_info):
name = expr['enum']
members = expr.get('data')
prefix = expr.get('prefix')
- values = {}
if not isinstance(members, list):
raise QAPIExprError(expr_info,
@@ -686,12 +645,6 @@ def check_enum(expr, expr_info):
for member in members:
check_name(expr_info, "Member of enum '%s'" % name, member,
enum_member=True)
- key = camel_to_upper(member)
- if key in values:
- raise QAPIExprError(expr_info,
- "Enum '%s' member '%s' clashes with '%s'"
- % (name, member, values[key]))
- values[key] = member
def check_struct(expr, expr_info):
@@ -702,8 +655,6 @@ def check_struct(expr, expr_info):
allow_dict=True, allow_optional=True)
check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
allow_metas=['struct'])
- if expr.get('base'):
- check_member_clash(expr_info, expr['base'], expr['data'])
def check_keys(expr_elem, meta, required, optional=[]):
diff --git a/tests/Makefile b/tests/Makefile
index 6b8b112..69cef77 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -341,7 +341,6 @@ qapi-schema += unclosed-list.json
qapi-schema += unclosed-object.json
qapi-schema += unclosed-string.json
qapi-schema += unicode-str.json
-qapi-schema += union-bad-branch.json
qapi-schema += union-base-no-discriminator.json
qapi-schema += union-branch-case.json
qapi-schema += union-clash-branches.json
diff --git a/tests/qapi-schema/alternate-clash.err b/tests/qapi-schema/alternate-clash.err
index a475ab6..604d849 100644
--- a/tests/qapi-schema/alternate-clash.err
+++ b/tests/qapi-schema/alternate-clash.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-clash.json:7: Alternate 'Alt1' member 'a_b' clashes with 'a-b'
+tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1)
diff --git a/tests/qapi-schema/enum-clash-member.err b/tests/qapi-schema/enum-clash-member.err
index 48bd136..5403c78 100644
--- a/tests/qapi-schema/enum-clash-member.err
+++ b/tests/qapi-schema/enum-clash-member.err
@@ -1 +1 @@
-tests/qapi-schema/enum-clash-member.json:2: Enum 'MyEnum' member 'ONE' clashes with 'one'
+tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum)
diff --git a/tests/qapi-schema/enum-clash-member.json b/tests/qapi-schema/enum-clash-member.json
index b7dc02a..b6928b8 100644
--- a/tests/qapi-schema/enum-clash-member.json
+++ b/tests/qapi-schema/enum-clash-member.json
@@ -1,2 +1,2 @@
# we reject enums where members will clash when mapped to C enum
-{ 'enum': 'MyEnum', 'data': [ 'one', 'ONE' ] }
+{ 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] }
diff --git a/tests/qapi-schema/flat-union-clash-member.err b/tests/qapi-schema/flat-union-clash-member.err
index 2f0397a..2adf697 100644
--- a/tests/qapi-schema/flat-union-clash-member.err
+++ b/tests/qapi-schema/flat-union-clash-member.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-clash-member.json:11: Member name 'name' of branch 'value1' clashes with base 'Base'
+tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base)
diff --git a/tests/qapi-schema/struct-base-clash-deep.err b/tests/qapi-schema/struct-base-clash-deep.err
index f7a25a3..e2d7943 100644
--- a/tests/qapi-schema/struct-base-clash-deep.err
+++ b/tests/qapi-schema/struct-base-clash-deep.err
@@ -1 +1 @@
-tests/qapi-schema/struct-base-clash-deep.json:10: Member name 'name' clashes with base 'Base'
+tests/qapi-schema/struct-base-clash-deep.json:10: 'name' (member of Sub) collides with 'name' (member of Base)
diff --git a/tests/qapi-schema/struct-base-clash.err b/tests/qapi-schema/struct-base-clash.err
index 3a9f66b..c52f33d 100644
--- a/tests/qapi-schema/struct-base-clash.err
+++ b/tests/qapi-schema/struct-base-clash.err
@@ -1 +1 @@
-tests/qapi-schema/struct-base-clash.json:5: Member name 'name' clashes with base 'Base'
+tests/qapi-schema/struct-base-clash.json:5: 'name' (member of Sub) collides with 'name' (member of Base)
diff --git a/tests/qapi-schema/union-bad-branch.err b/tests/qapi-schema/union-bad-branch.err
deleted file mode 100644
index 8822735..0000000
--- a/tests/qapi-schema/union-bad-branch.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/union-bad-branch.json:6: Union 'MyUnion' member 'ONE' clashes with 'one'
diff --git a/tests/qapi-schema/union-bad-branch.exit b/tests/qapi-schema/union-bad-branch.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/union-bad-branch.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/union-bad-branch.json b/tests/qapi-schema/union-bad-branch.json
deleted file mode 100644
index 913aa38..0000000
--- a/tests/qapi-schema/union-bad-branch.json
+++ /dev/null
@@ -1,8 +0,0 @@
-# we reject normal unions where branches would collide in C
-{ 'struct': 'One',
- 'data': { 'string': 'str' } }
-{ 'struct': 'Two',
- 'data': { 'number': 'int' } }
-{ 'union': 'MyUnion',
- 'data': { 'one': 'One',
- 'ONE': 'Two' } }
diff --git a/tests/qapi-schema/union-bad-branch.out b/tests/qapi-schema/union-bad-branch.out
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/union-clash-branches.err b/tests/qapi-schema/union-clash-branches.err
index 005c48d..e5b2113 100644
--- a/tests/qapi-schema/union-clash-branches.err
+++ b/tests/qapi-schema/union-clash-branches.err
@@ -1 +1 @@
-tests/qapi-schema/union-clash-branches.json:4: Union 'TestUnion' member 'a_b' clashes with 'a-b'
+tests/qapi-schema/union-clash-branches.json:4: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion)
diff --git a/tests/qapi-schema/union-clash-branches.json b/tests/qapi-schema/union-clash-branches.json
index 31d135f..3bece8c 100644
--- a/tests/qapi-schema/union-clash-branches.json
+++ b/tests/qapi-schema/union-clash-branches.json
@@ -1,5 +1,5 @@
# Union branch name collision
# Reject a union that would result in a collision in generated C names (this
-# would try to generate two enum values 'TEST_UNION_KIND_A_B').
+# would try to generate two members 'a_b').
{ 'union': 'TestUnion',
'data': { 'a-b': 'int', 'a_b': 'str' } }
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [Qemu-devel] [PULL 40/40] qapi: Detect base class loops
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (38 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 39/40] qapi: Move duplicate collision checks to schema check() Markus Armbruster
@ 2015-12-17 8:33 ` Markus Armbruster
2015-12-17 12:39 ` [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Peter Maydell
40 siblings, 0 replies; 42+ messages in thread
From: Markus Armbruster @ 2015-12-17 8:33 UTC (permalink / raw)
To: qemu-devel
From: Eric Blake <eblake@redhat.com>
It should be fairly obvious that qapi base classes need to
form an acyclic graph, since QMP cannot specify the same
key more than once, while base classes are included as flat
members alongside other members added by the child. But the
old check_member_clash() parser function was not prepared to
check for this, and entered an infinite recursion (at least
until Python gives up, complaining about nesting too deep).
Now that check_member_clash() has been recently removed,
attempts at self-inheritance trigger an assertion failure
introduced by commit ac88219a. The obvious fix is to turn
the assertion into a conditional.
This patch includes both the tests (base-cycle-direct and
base-cycle-indirect) and the fix, since the .err file output
for the unfixed case is not useful (particularly when it was
warning about unbounded recursion, as that limit may be
platform-specific).
We don't need to worry about cycles in flat unions (neither
the base type nor the type of a variant can be a union) nor
in alternates (alternate branches cannot themselves be an
alternate). But if we later allow a union type as a variant,
we will still be okay, as QAPISchemaObjectTypeVariants.check()
triggers the same QAPISchemaObjectType.check() that will
detect any loops.
Likewise, we need not worry about the case of diamond
inheritance where the same class is used for a flat union base
class and one of its variants; either both uses will introduce
a collision in trying to insert the same member name twice, or
the shared type is empty and changes nothing.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-16-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
scripts/qapi.py | 4 +++-
tests/Makefile | 2 ++
tests/qapi-schema/base-cycle-direct.err | 1 +
tests/qapi-schema/base-cycle-direct.exit | 1 +
tests/qapi-schema/base-cycle-direct.json | 2 ++
tests/qapi-schema/base-cycle-direct.out | 0
tests/qapi-schema/base-cycle-indirect.err | 1 +
tests/qapi-schema/base-cycle-indirect.exit | 1 +
tests/qapi-schema/base-cycle-indirect.json | 3 +++
tests/qapi-schema/base-cycle-indirect.out | 0
10 files changed, 14 insertions(+), 1 deletion(-)
create mode 100644 tests/qapi-schema/base-cycle-direct.err
create mode 100644 tests/qapi-schema/base-cycle-direct.exit
create mode 100644 tests/qapi-schema/base-cycle-direct.json
create mode 100644 tests/qapi-schema/base-cycle-direct.out
create mode 100644 tests/qapi-schema/base-cycle-indirect.err
create mode 100644 tests/qapi-schema/base-cycle-indirect.exit
create mode 100644 tests/qapi-schema/base-cycle-indirect.json
create mode 100644 tests/qapi-schema/base-cycle-indirect.out
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8edfd79..7dec611 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -940,7 +940,9 @@ class QAPISchemaObjectType(QAPISchemaType):
self.members = None
def check(self, schema):
- assert self.members is not False # not running in cycles
+ if self.members is False: # check for cycles
+ raise QAPIExprError(self.info,
+ "Object %s contains itself" % self.name)
if self.members:
return
self.members = False # mark as being checked
diff --git a/tests/Makefile b/tests/Makefile
index 69cef77..053c1ae 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -257,6 +257,8 @@ qapi-schema += bad-ident.json
qapi-schema += bad-type-bool.json
qapi-schema += bad-type-dict.json
qapi-schema += bad-type-int.json
+qapi-schema += base-cycle-direct.json
+qapi-schema += base-cycle-indirect.json
qapi-schema += command-int.json
qapi-schema += comments.json
qapi-schema += double-data.json
diff --git a/tests/qapi-schema/base-cycle-direct.err b/tests/qapi-schema/base-cycle-direct.err
new file mode 100644
index 0000000..9c68f65
--- /dev/null
+++ b/tests/qapi-schema/base-cycle-direct.err
@@ -0,0 +1 @@
+tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself
diff --git a/tests/qapi-schema/base-cycle-direct.exit b/tests/qapi-schema/base-cycle-direct.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/base-cycle-direct.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/base-cycle-direct.json b/tests/qapi-schema/base-cycle-direct.json
new file mode 100644
index 0000000..4fc66d0
--- /dev/null
+++ b/tests/qapi-schema/base-cycle-direct.json
@@ -0,0 +1,2 @@
+# we reject a loop in base classes
+{ 'struct': 'Loopy', 'base': 'Loopy', 'data': {} }
diff --git a/tests/qapi-schema/base-cycle-direct.out b/tests/qapi-schema/base-cycle-direct.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/base-cycle-indirect.err b/tests/qapi-schema/base-cycle-indirect.err
new file mode 100644
index 0000000..fc92fe4
--- /dev/null
+++ b/tests/qapi-schema/base-cycle-indirect.err
@@ -0,0 +1 @@
+tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself
diff --git a/tests/qapi-schema/base-cycle-indirect.exit b/tests/qapi-schema/base-cycle-indirect.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/base-cycle-indirect.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/base-cycle-indirect.json b/tests/qapi-schema/base-cycle-indirect.json
new file mode 100644
index 0000000..2866772
--- /dev/null
+++ b/tests/qapi-schema/base-cycle-indirect.json
@@ -0,0 +1,3 @@
+# we reject a loop in base classes
+{ 'struct': 'Base1', 'base': 'Base2', 'data': {} }
+{ 'struct': 'Base2', 'base': 'Base1', 'data': {} }
diff --git a/tests/qapi-schema/base-cycle-indirect.out b/tests/qapi-schema/base-cycle-indirect.out
new file mode 100644
index 0000000..e69de29
--
2.4.3
^ permalink raw reply related [flat|nested] 42+ messages in thread
* Re: [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
` (39 preceding siblings ...)
2015-12-17 8:33 ` [Qemu-devel] [PULL 40/40] qapi: Detect base class loops Markus Armbruster
@ 2015-12-17 12:39 ` Peter Maydell
40 siblings, 0 replies; 42+ messages in thread
From: Peter Maydell @ 2015-12-17 12:39 UTC (permalink / raw)
To: Markus Armbruster; +Cc: QEMU Developers
On 17 December 2015 at 08:33, Markus Armbruster <armbru@redhat.com> wrote:
> The following changes since commit a8c40fa2d667e585382080db36ac44e216b37a1c:
>
> Update version for v2.5.0 release (2015-12-16 16:10:14 +0000)
>
> are available in the git repository at:
>
> git://repo.or.cz/qemu/armbru.git tags/pull-qapi-2015-12-17
>
> for you to fetch changes up to bac5429ccb4f41d421ec641b11f1852c8420fdb7:
>
> qapi: Detect base class loops (2015-12-17 08:21:29 +0100)
>
> ----------------------------------------------------------------
> QAPI patches for 2015-12-17
>
> ----------------------------------------------------------------
Applied, thanks.
-- PMM
^ permalink raw reply [flat|nested] 42+ messages in thread
end of thread, other threads:[~2015-12-17 12:40 UTC | newest]
Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-17 8:33 [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 01/40] qapi: Track simple union tag in object.local_members Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 02/40] qapi-types: Consolidate gen_struct() and gen_union() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 03/40] qapi-types: Simplify gen_struct_field[s] Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 04/40] qapi: Drop obsolete tag value collision assertions Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 05/40] qapi: Simplify QAPISchemaObjectTypeMember.check() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 06/40] qapi: Clean up after previous commit Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 07/40] qapi: Fix up commit 7618b91's clash sanity checking change Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 08/40] qapi: Eliminate QAPISchemaObjectType.check() variable members Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 09/40] qapi: Factor out QAPISchemaObjectTypeMember.check_clash() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 10/40] qapi: Simplify QAPISchemaObjectTypeVariants.check() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 11/40] qapi: Check for QAPI collisions involving variant members Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 12/40] qapi: Factor out QAPISchemaObjectType.check_clash() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 13/40] qapi: Hoist tag collision check to Variants.check() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 14/40] qapi: Remove outdated tests related to QMP/branch collisions Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 15/40] qapi: Track owner of each object member Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 16/40] qapi: Detect collisions in C member names Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 17/40] qapi: Fix c_name() munging Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 18/40] qapi: Remove dead visitor code Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 19/40] blkdebug: Merge hand-rolled and qapi BlkdebugEvent enum Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 20/40] blkdebug: Avoid '.' in enum values Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 21/40] qapi: Tighten the regex on valid names Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 22/40] qapi: Don't let implicit enum MAX member collide Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 23/40] qapi: Remove obsolete tests for MAX collision Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 24/40] cpu: Convert CpuInfo into flat union Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 25/40] qapi: Add alias for ErrorClass Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 26/40] qapi: Change munging of CamelCase enum values Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 27/40] qobject: Simplify QObject Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 28/40] qobject: Rename qtype_code to QType Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 29/40] qapi: Convert QType into QAPI built-in enum type Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 30/40] qapi: Simplify visiting of alternate types Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 31/40] qapi-types: Drop unnedeed ._fwdefn Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 32/40] qapi: Inline _make_implicit_tag() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 33/40] qapi: Fix alternates that accept 'number' but not 'int' Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 34/40] qapi: Simplify visits of optional fields Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 35/40] qapi: Shorter " Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 36/40] qapi: Prepare new QAPISchemaMember base class Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 37/40] qapi: Track enum values by QAPISchemaMember, not string Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 38/40] qapi: Enforce (or whitelist) case conventions on qapi members Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 39/40] qapi: Move duplicate collision checks to schema check() Markus Armbruster
2015-12-17 8:33 ` [Qemu-devel] [PULL 40/40] qapi: Detect base class loops Markus Armbruster
2015-12-17 12:39 ` [Qemu-devel] [PULL 00/40] QAPI patches for 2015-12-17 Peter Maydell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).