All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B')
@ 2015-10-23  5:09 Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct Eric Blake
                   ` (25 more replies)
  0 siblings, 26 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Eduardo Habkost

No pending prerequisites (applies to current master)

Also available as a tag at this location:
git fetch git://repo.or.cz/qemu/ericb.git qapi-cleanupv10b

and I plan to eventually forcefully update my branch with the rest
of the v5 series, at:
http://repo.or.cz/qemu/ericb.git/shortlog/refs/heads/qapi

v10 notes:
Rebase to master, reduce churn in the testsuite (particularly for
things that disappear once the named union conversion is complete),
and rearrange various hunks either forward or backward.  17 patches
turned into 25, because I split things.  Also, several patches got
retitled, which messes up git backport-diff reporting, but some
survived unscathed:

001/25:[down] 'tests/qapi-schema: Test for reserved names, empty struct'
002/25:[down] 'qapi: More idiomatic string operations'
003/25:[down] 'qapi: More robust conditions for when labels are needed'
004/25:[down] 'qapi: Reserve '*List' type names for list types'
005/25:[down] 'qapi: Reserve 'q_*' and 'has_*' member names'
006/25:[down] 'vnc: Hoist allocation of VncBasicInfo to callers'
007/25:[down] 'qapi-visit: Split off visit_type_FOO_fields forward decl'
008/25:[down] 'qapi-types: Refactor base fields output'
009/25:[down] 'qapi: Prefer typesafe upcasts to qapi base classes'
010/25:[0079] [FC] 'qapi: Unbox base members'
011/25:[0005] [FC] 'qapi-visit: Remove redundant functions for flat union base'
012/25:[0032] [FC] 'qapi: Start converting to new qapi union layout'
013/25:[down] 'qapi-visit: Convert to new qapi union layout'
014/25:[0010] [FC] 'tests: Convert to new qapi union layout'
015/25:[----] [--] 'block: Convert to new qapi union layout'
016/25:[down] 'sockets: Convert to new qapi union layout'
017/25:[----] [--] 'net: Convert to new qapi union layout'
018/25:[----] [--] 'char: Convert to new qapi union layout'
019/25:[----] [--] 'input: Convert to new qapi union layout'
020/25:[----] [--] 'memory: Convert to new qapi union layout'
021/25:[----] [--] 'tpm: Convert to new qapi union layout'
022/25:[0008] [FC] 'qapi: Finish converting to new qapi union layout'
023/25:[down] 'qapi: Reserve 'u' member name'
024/25:[down] 'qapi: Remove outdated tests related to QMP/branch collisions'
025/25:[----] [-C] 'qapi: Simplify gen_struct_field()'

v9 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg03730.html
Calling this subset B', because it is mostly new content, but
based heavily on review comments on subset B.  Also, I need to
rebase pending subset C on top of this.  A couple patches
from v5 have been hoisted earlier into the series; while v8
11/18 (Simplify gen_struct_field()) makes an appearance at the
end, and v8 10/18 (Move union tag quirks into subclass) is all
but eliminated.  Since the concepts of these patches has been
on the list for a while, it should be safe to take even during
soft freeze, even if the actual versions of these patches have
lots of new content.

The general goal of this batch of patches is to rework the C
layout of qapi unions so that we get rid of the type/kind
mismatch and isolate tag values from colliding with QMP names.
The tail end of v8 (detecting collisions in check()) will have
to wait a bit longer, but it should be a lot easier to reason
about now that there are fewer collisions possible.

Not worth a backport diff, since most of it is new or previously
unreviewed.

v8 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02879.html
Address review comments, including fixing a bug with tracking
branch name collisions. Include a few more simple test cleanups
(4-6), and add another patch (11) that will make converting from
kind=>type easier in a later subset.  More details in per-patch
changelogs.

v7 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg01387.html
Address comments, including a couple of new commits that made
later patches a bit cleaner.  Backport diff gets a bit confused
by a couple of patch titles changing.

v6 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg00562.html
This is patches 11-16 of my v5 series; it has grown a bit with
splitting some patches and adding some others.  I suspect that
12/12 on this series will be discarded, but am including it because
it was split from v5 content.

Not much review comments other than on the original 11/46, but there
is enough churn due to rebasing that it's now easier to review this
version than plowing through v5.

Subset C (and more?) will come later.

In v5:
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg05410.html
I _did_ rearrange patches to try and group related features:

1-2: Groundwork cleanups
3-5: Add more test cases
6-16: Front-end cleanups
17-18: Introspection output cleanups
19-20: 'alternate' type cleanups
21-29: qapi visitor cleanups
30-45: qapi-ify netdev_add
46: add qapi shorthand for flat unions

Lots of fixes based on additional testing, and rebased to
track other changes that happened in the meantime.  The series
is huge; I can split off smaller portions as requested.

In v4:
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg02580.html
add some more clean up patches
rebase to Markus' recent work
pull in part of Zoltán's work to make netdev_add a flat union,
further enhancing it to be introspectible

I might be able to rearrange some of these patches, or separate
it into smaller independent series, if requested; but I'm
posting now to get review started.

In v3:
https://lists.gnu.org/archive/html/qemu-devel/2015-08/msg02059.html
redo cleanup of dealloc of partial struct
add patches to make all visit_type_*() avoid leaks on failure
add patches to allow boxed command arguments and events

In v2:
https://lists.gnu.org/archive/html/qemu-devel/2015-08/msg00900.html
rebase to Markus' v3 series
rework how comments are emitted for fields inherited from base
additional patches added for deleting colliding 'void *data'
documentation updates to match code changes

v1 was here:
https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg05266.html
https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg05325.html

Eric Blake (25):
  tests/qapi-schema: Test for reserved names, empty struct
  qapi: More idiomatic string operations
  qapi: More robust conditions for when labels are needed
  qapi: Reserve '*List' type names for list types
  qapi: Reserve 'q_*' and 'has_*' member names
  vnc: Hoist allocation of VncBasicInfo to callers
  qapi-visit: Split off visit_type_FOO_fields forward decl
  qapi-types: Refactor base fields output
  qapi: Prefer typesafe upcasts to qapi base classes
  qapi: Unbox base members
  qapi-visit: Remove redundant functions for flat union base
  qapi: Start converting to new qapi union layout
  qapi-visit: Convert to new qapi union layout
  tests: Convert to new qapi union layout
  block: Convert to new qapi union layout
  sockets: Convert to new qapi union layout
  net: Convert to new qapi union layout
  char: Convert to new qapi union layout
  input: Convert to new qapi union layout
  memory: Convert to new qapi union layout
  tpm: Convert to new qapi union layout
  qapi: Finish converting to new qapi union layout
  qapi: Reserve 'u' member name
  qapi: Remove outdated tests related to QMP/branch collisions
  qapi: Simplify gen_struct_field()

 block/nbd.c                                        |  18 +--
 block/qcow2.c                                      |  10 +-
 block/vmdk.c                                       |   6 +-
 blockdev.c                                         |  47 +++---
 docs/qapi-code-gen.txt                             |  14 +-
 hmp.c                                              |  26 ++--
 hw/char/escc.c                                     |  12 +-
 hw/input/hid.c                                     |  32 ++---
 hw/input/ps2.c                                     |  24 ++--
 hw/input/virtio-input-hid.c                        |  27 ++--
 hw/mem/pc-dimm.c                                   |   6 +-
 net/dump.c                                         |   4 +-
 net/hub.c                                          |   4 +-
 net/l2tpv3.c                                       |   4 +-
 net/net.c                                          |  24 ++--
 net/slirp.c                                        |   4 +-
 net/socket.c                                       |   4 +-
 net/tap-win32.c                                    |   4 +-
 net/tap.c                                          |   8 +-
 net/vde.c                                          |   4 +-
 net/vhost-user.c                                   |   4 +-
 numa.c                                             |   8 +-
 qemu-char.c                                        | 160 ++++++++++-----------
 qemu-nbd.c                                         |  16 +--
 scripts/qapi-commands.py                           |   2 +-
 scripts/qapi-types.py                              |  65 +++++----
 scripts/qapi-visit.py                              |  94 ++++++------
 scripts/qapi.py                                    |  29 ++--
 spice-qemu-char.c                                  |  12 +-
 tests/Makefile                                     |   9 +-
 tests/qapi-schema/args-has-clash.err               |   1 +
 .../{union-clash-type.exit => args-has-clash.exit} |   0
 tests/qapi-schema/args-has-clash.json              |   6 +
 .../{union-clash-type.out => args-has-clash.out}   |   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.json       |  14 --
 tests/qapi-schema/qapi-schema-test.json            |   4 +
 tests/qapi-schema/qapi-schema-test.out             |   3 +
 tests/qapi-schema/reserved-command.err             |   1 +
 ...union-clash-type.exit => reserved-command.exit} |   0
 tests/qapi-schema/reserved-command.json            |   6 +
 ...ct-base-clash-base.err => reserved-command.out} |   0
 tests/qapi-schema/reserved-member.err              |   1 +
 tests/qapi-schema/reserved-member.exit             |   1 +
 tests/qapi-schema/reserved-member.json             |   5 +
 ...at-union-clash-type.out => reserved-member.out} |   0
 tests/qapi-schema/struct-base-clash-base.exit      |   1 -
 tests/qapi-schema/struct-base-clash-base.json      |   9 --
 tests/qapi-schema/struct-base-clash-base.out       |   5 -
 tests/qapi-schema/struct-member-u.err              |   1 +
 tests/qapi-schema/struct-member-u.exit             |   1 +
 tests/qapi-schema/struct-member-u.json             |   7 +
 ...-union-clash-branch.err => struct-member-u.out} |   0
 tests/qapi-schema/struct-name-list.err             |   1 +
 tests/qapi-schema/struct-name-list.exit            |   1 +
 tests/qapi-schema/struct-name-list.json            |   5 +
 tests/qapi-schema/struct-name-list.out             |   0
 tests/qapi-schema/union-clash-type.err             |   1 -
 tests/qapi-schema/union-clash-type.json            |   9 --
 tests/test-qmp-commands.c                          |  19 +--
 tests/test-qmp-event.c                             |   8 +-
 tests/test-qmp-input-visitor.c                     |  82 +++++------
 tests/test-qmp-output-visitor.c                    |  55 ++++---
 tests/test-visitor-serialization.c                 |  14 +-
 tpm.c                                              |   4 +-
 ui/console.c                                       |  20 +--
 ui/input-keymap.c                                  |  20 +--
 ui/input-legacy.c                                  |  21 +--
 ui/input.c                                         |  84 +++++------
 ui/spice-core.c                                    |  23 +--
 ui/vnc.c                                           | 114 ++++++++-------
 util/qemu-sockets.c                                |  62 ++++----
 75 files changed, 654 insertions(+), 670 deletions(-)
 create mode 100644 tests/qapi-schema/args-has-clash.err
 rename tests/qapi-schema/{union-clash-type.exit => args-has-clash.exit} (100%)
 create mode 100644 tests/qapi-schema/args-has-clash.json
 rename tests/qapi-schema/{union-clash-type.out => args-has-clash.out} (100%)
 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-command.err
 rename tests/qapi-schema/{flat-union-clash-type.exit => reserved-command.exit} (100%)
 create mode 100644 tests/qapi-schema/reserved-command.json
 rename tests/qapi-schema/{struct-base-clash-base.err => reserved-command.out} (100%)
 create mode 100644 tests/qapi-schema/reserved-member.err
 create mode 100644 tests/qapi-schema/reserved-member.exit
 create mode 100644 tests/qapi-schema/reserved-member.json
 rename tests/qapi-schema/{flat-union-clash-type.out => reserved-member.out} (100%)
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.exit
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.json
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.out
 create mode 100644 tests/qapi-schema/struct-member-u.err
 create mode 100644 tests/qapi-schema/struct-member-u.exit
 create mode 100644 tests/qapi-schema/struct-member-u.json
 rename tests/qapi-schema/{flat-union-clash-branch.err => struct-member-u.out} (100%)
 create mode 100644 tests/qapi-schema/struct-name-list.err
 create mode 100644 tests/qapi-schema/struct-name-list.exit
 create mode 100644 tests/qapi-schema/struct-name-list.json
 create mode 100644 tests/qapi-schema/struct-name-list.out
 delete mode 100644 tests/qapi-schema/union-clash-type.err
 delete mode 100644 tests/qapi-schema/union-clash-type.json

-- 
2.4.3

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 12:33   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 02/25] qapi: More idiomatic string operations Eric Blake
                   ` (24 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We are failing to detect a collision between a QMP member and
the implicit 'has_*' flag for another optional QMP member. The
easiest fix would be for a future patch to reserve the entire
"has[-_]" namespace for member names (the collision is also
possible for branch names within flat unions, but only as long
as branch names can collide with QMP names; since future
patches are about to remove that, it is not worth testing here).

A similar collision exists between a QMP member where c_name()
munges what might otherwise be a reserved name to start with
'q_', and another member explicitly starts with "q[-_]".  Again,
the easiest task for a future patch will be reserving the entire
namespace, but here for commands as well as members.

Our current representation of qapi arrays is done by appending
'List' to the element name; but we are not preventing the
creation of a non-array type with the same name.

Finally, our testsuite does not have any compilation coverage
of struct inheritance with empty qapi structs.

Add tests to cover these issues.

On the other hand, there is currently no technical reason to
forbid type name patterns from member names, or member name
patterns from types, since the two are not in the same namespace
in C and won't collide (but it's not worth adding positive tests
of these corner cases, especially while there is other churn
pending in patches that rearrange which collisions actually
happen).

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: retitle, split off 'u' collisions and positive tests for
later, add 'q_' collisions and empty struct inheritance, improve
commit message, rename args-name-has to args-has-clash
v9: new patch
---
 tests/Makefile                          | 4 ++++
 tests/qapi-schema/args-has-clash.err    | 0
 tests/qapi-schema/args-has-clash.exit   | 1 +
 tests/qapi-schema/args-has-clash.json   | 6 ++++++
 tests/qapi-schema/args-has-clash.out    | 6 ++++++
 tests/qapi-schema/qapi-schema-test.json | 4 ++++
 tests/qapi-schema/qapi-schema-test.out  | 3 +++
 tests/qapi-schema/reserved-command.err  | 0
 tests/qapi-schema/reserved-command.exit | 1 +
 tests/qapi-schema/reserved-command.json | 7 +++++++
 tests/qapi-schema/reserved-command.out  | 5 +++++
 tests/qapi-schema/reserved-member.err   | 0
 tests/qapi-schema/reserved-member.exit  | 1 +
 tests/qapi-schema/reserved-member.json  | 6 ++++++
 tests/qapi-schema/reserved-member.out   | 4 ++++
 tests/qapi-schema/struct-name-list.err  | 0
 tests/qapi-schema/struct-name-list.exit | 1 +
 tests/qapi-schema/struct-name-list.json | 5 +++++
 tests/qapi-schema/struct-name-list.out  | 3 +++
 19 files changed, 57 insertions(+)
 create mode 100644 tests/qapi-schema/args-has-clash.err
 create mode 100644 tests/qapi-schema/args-has-clash.exit
 create mode 100644 tests/qapi-schema/args-has-clash.json
 create mode 100644 tests/qapi-schema/args-has-clash.out
 create mode 100644 tests/qapi-schema/reserved-command.err
 create mode 100644 tests/qapi-schema/reserved-command.exit
 create mode 100644 tests/qapi-schema/reserved-command.json
 create mode 100644 tests/qapi-schema/reserved-command.out
 create mode 100644 tests/qapi-schema/reserved-member.err
 create mode 100644 tests/qapi-schema/reserved-member.exit
 create mode 100644 tests/qapi-schema/reserved-member.json
 create mode 100644 tests/qapi-schema/reserved-member.out
 create mode 100644 tests/qapi-schema/struct-name-list.err
 create mode 100644 tests/qapi-schema/struct-name-list.exit
 create mode 100644 tests/qapi-schema/struct-name-list.json
 create mode 100644 tests/qapi-schema/struct-name-list.out

diff --git a/tests/Makefile b/tests/Makefile
index 0531b30..cc6b24f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -237,6 +237,7 @@ qapi-schema += args-alternate.json
 qapi-schema += args-any.json
 qapi-schema += args-array-empty.json
 qapi-schema += args-array-unknown.json
+qapi-schema += args-has-clash.json
 qapi-schema += args-int.json
 qapi-schema += args-invalid.json
 qapi-schema += args-member-array-bad.json
@@ -314,6 +315,8 @@ qapi-schema += redefined-builtin.json
 qapi-schema += redefined-command.json
 qapi-schema += redefined-event.json
 qapi-schema += redefined-type.json
+qapi-schema += reserved-command.json
+qapi-schema += reserved-member.json
 qapi-schema += returns-alternate.json
 qapi-schema += returns-array-bad.json
 qapi-schema += returns-dict.json
@@ -324,6 +327,7 @@ qapi-schema += struct-base-clash-deep.json
 qapi-schema += struct-base-clash.json
 qapi-schema += struct-data-invalid.json
 qapi-schema += struct-member-invalid.json
+qapi-schema += struct-name-list.json
 qapi-schema += trailing-comma-list.json
 qapi-schema += trailing-comma-object.json
 qapi-schema += type-bypass-bad-gen.json
diff --git a/tests/qapi-schema/args-has-clash.err b/tests/qapi-schema/args-has-clash.err
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/args-has-clash.exit b/tests/qapi-schema/args-has-clash.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/args-has-clash.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/args-has-clash.json b/tests/qapi-schema/args-has-clash.json
new file mode 100644
index 0000000..a2197de
--- /dev/null
+++ b/tests/qapi-schema/args-has-clash.json
@@ -0,0 +1,6 @@
+# C member name collision
+# FIXME - This parses, but fails to compile, because the C struct is given
+# two 'has_a' members, one from the flag for optional 'a', and the other
+# from member 'has-a'.  Either reject this at parse time, or munge the C
+# names to avoid the collision.
+{ 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
diff --git a/tests/qapi-schema/args-has-clash.out b/tests/qapi-schema/args-has-clash.out
new file mode 100644
index 0000000..5a18b6b
--- /dev/null
+++ b/tests/qapi-schema/args-has-clash.out
@@ -0,0 +1,6 @@
+object :empty
+object :obj-oops-arg
+    member a: str optional=True
+    member has-a: str optional=False
+command oops :obj-oops-arg -> None
+   gen=True success_response=True
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 4e2d7c2..48e104b 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -11,6 +11,10 @@
 # An empty enum, although unusual, is currently acceptable
 { 'enum': 'MyEnum', 'data': [ ] }

+# Likewise for an empty struct, including an empty base
+{ 'struct': 'Empty1', 'data': { } }
+{ 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
+
 # for testing override of default naming heuristic
 { 'enum': 'QEnumTwo',
   'prefix': 'QENUM_TWO',
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index a6c80e0..a7e9aab 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -81,6 +81,9 @@ event EVENT_A None
 event EVENT_B None
 event EVENT_C :obj-EVENT_C-arg
 event EVENT_D :obj-EVENT_D-arg
+object Empty1
+object Empty2
+    base Empty1
 enum EnumOne ['value1', 'value2', 'value3']
 object EventStructOne
     member struct1: UserDefOne optional=False
diff --git a/tests/qapi-schema/reserved-command.err b/tests/qapi-schema/reserved-command.err
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/reserved-command.exit b/tests/qapi-schema/reserved-command.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/reserved-command.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/reserved-command.json b/tests/qapi-schema/reserved-command.json
new file mode 100644
index 0000000..be9944c
--- /dev/null
+++ b/tests/qapi-schema/reserved-command.json
@@ -0,0 +1,7 @@
+# C entity name collision
+# FIXME - This parses, but fails to compile, because it attempts to declare
+# two 'qmp_q_unix' functions (one for 'q-unix', the other because c_name()
+# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
+# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
+{ 'command': 'unix' }
+{ 'command': 'q-unix' }
diff --git a/tests/qapi-schema/reserved-command.out b/tests/qapi-schema/reserved-command.out
new file mode 100644
index 0000000..b31b38f
--- /dev/null
+++ b/tests/qapi-schema/reserved-command.out
@@ -0,0 +1,5 @@
+object :empty
+command q-unix None -> None
+   gen=True success_response=True
+command unix None -> None
+   gen=True success_response=True
diff --git a/tests/qapi-schema/reserved-member.err b/tests/qapi-schema/reserved-member.err
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/reserved-member.exit b/tests/qapi-schema/reserved-member.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/reserved-member.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/reserved-member.json b/tests/qapi-schema/reserved-member.json
new file mode 100644
index 0000000..1602ed3
--- /dev/null
+++ b/tests/qapi-schema/reserved-member.json
@@ -0,0 +1,6 @@
+# C member name collision
+# FIXME - This parses, but fails to compile, because it attempts to declare
+# two 'q_unix' members (one for 'q-unix', the other because c_name()
+# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
+# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
+{ 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }
diff --git a/tests/qapi-schema/reserved-member.out b/tests/qapi-schema/reserved-member.out
new file mode 100644
index 0000000..0d8685a
--- /dev/null
+++ b/tests/qapi-schema/reserved-member.out
@@ -0,0 +1,4 @@
+object :empty
+object Foo
+    member unix: int optional=False
+    member q-unix: bool optional=False
diff --git a/tests/qapi-schema/struct-name-list.err b/tests/qapi-schema/struct-name-list.err
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/struct-name-list.exit b/tests/qapi-schema/struct-name-list.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/struct-name-list.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/struct-name-list.json b/tests/qapi-schema/struct-name-list.json
new file mode 100644
index 0000000..8ad38e6
--- /dev/null
+++ b/tests/qapi-schema/struct-name-list.json
@@ -0,0 +1,5 @@
+# Potential C name collision
+# FIXME - This parses and compiles on its own, but prevents the user from
+# creating a type named 'Foo' and using ['Foo'] for an array.  We should
+# reject the use of any non-array type names ending in 'List'.
+{ 'struct': 'FooList', 'data': { 's': 'str' } }
diff --git a/tests/qapi-schema/struct-name-list.out b/tests/qapi-schema/struct-name-list.out
new file mode 100644
index 0000000..0406bfe
--- /dev/null
+++ b/tests/qapi-schema/struct-name-list.out
@@ -0,0 +1,3 @@
+object :empty
+object FooList
+    member s: str optional=False
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 02/25] qapi: More idiomatic string operations
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 03/25] qapi: More robust conditions for when labels are needed Eric Blake
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Rather than slicing the end of a string, we can use python's
endswith().  And rather than creating a set of characters,
we can search for a character within a string.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch
---
 scripts/qapi.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 9d53255..3af4c2c 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -172,7 +172,7 @@ class QAPISchemaParser(object):

             if self.tok == '#':
                 self.cursor = self.src.find('\n', self.cursor)
-            elif self.tok in ['{', '}', ':', ',', '[', ']']:
+            elif self.tok in "{}:,[]":
                 return
             elif self.tok == "'":
                 string = ''
@@ -390,7 +390,7 @@ def add_name(name, info, meta, implicit=False):
         raise QAPIExprError(info,
                             "%s '%s' is already defined"
                             % (all_names[name], name))
-    if not implicit and name[-4:] == 'Kind':
+    if not implicit and name.endswith('Kind'):
         raise QAPIExprError(info,
                             "%s '%s' should not end in 'Kind'"
                             % (meta, name))
@@ -910,7 +910,7 @@ class QAPISchemaEnumType(QAPISchemaType):

     def is_implicit(self):
         # See QAPISchema._make_implicit_enum_type()
-        return self.name[-4:] == 'Kind'
+        return self.name.endswith('Kind')

     def c_type(self, is_param=False):
         return c_name(self.name)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 03/25] qapi: More robust conditions for when labels are needed
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 02/25] qapi: More idiomatic string operations Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 12:44   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 04/25] qapi: Reserve '*List' type names for list types Eric Blake
                   ` (22 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We were using regular expressions to see if ret included
any earlier text that emitted a 'goto out;' line, to decide
whether we needed to output an 'out:' label.  But this is
fragile, if the ret text can possibly combine more than one
generated function body, where the first function used a
goto but the second does not.  Change the code to just check
for the known conditions which cause an error check to be
needed.  Besides, it's slightly more efficient to use plain
checks than regular expression searching.

No change to generated code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch, split in part from 6/17
---
 scripts/qapi-commands.py | 2 +-
 scripts/qapi-visit.py    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 43a893b..d6a4bf4 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -175,7 +175,7 @@ def gen_marshal(name, arg_type, ret_type):
     ret += gen_marshal_input_visit(arg_type)
     ret += gen_call(name, arg_type, ret_type)

-    if re.search('^ *goto out;', ret, re.MULTILINE):
+    if (arg_type and arg_type.members) or ret_type:
         ret += mcgen('''

 out:
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index d0759d7..e878018 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -87,7 +87,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **e

     ret += gen_visit_fields(members, prefix='(*obj)->')

-    if re.search('^ *goto out;', ret, re.MULTILINE):
+    if base or members:
         ret += mcgen('''

 out:
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 04/25] qapi: Reserve '*List' type names for list types
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (2 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 03/25] qapi: More robust conditions for when labels are needed Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 12:53   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names Eric Blake
                   ` (21 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Type names ending in 'List' can clash with qapi list types in
generated C.  We don't currently use such names. It is easier to
outlaw them now than to worry about how to resolve such a clash
in the future. For precedence, see commit 4dc2e69, which did the
same for names ending in 'Kind' versus implicit enum types for
qapi unions.

Note that this only forbids explicit creation of new (non-array)
types or commands ending in 'List'; the parser already rejects
attempts to use ['intList'] as the type for an object member
(although 'intList' happens to be the C spelling for the qapi
type ['int'], that does not make it a recognized name in qapi).
Whether we later turn on support for multi-dimensional arrays
(via [['int']], not ['intList']) is a design decision best left
for another day.

Update the testsuite to match.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: improve commit message, including a retitle (qapi list types
may be JSON arrays, but they are C linked lists, not C arrays)
v9: new patch
---
 docs/qapi-code-gen.txt                  |  3 ++-
 scripts/qapi.py                         | 10 ++++------
 tests/qapi-schema/struct-name-list.err  |  1 +
 tests/qapi-schema/struct-name-list.exit |  2 +-
 tests/qapi-schema/struct-name-list.json |  6 +++---
 tests/qapi-schema/struct-name-list.out  |  3 ---
 6 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 2afab20..c4264a8 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -106,7 +106,8 @@ Types, commands, and events share a common namespace.  Therefore,
 generally speaking, type definitions should always use CamelCase for
 user-defined type names, while built-in types are lowercase. Type
 definitions should not end in 'Kind', as this namespace is used for
-creating implicit C enums for visiting union types.  Command names,
+creating implicit C enums for visiting union types, or in 'List', as
+this namespace is used for creating array types.  Command names,
 and field names within a type, should be all lower case with words
 separated by a hyphen.  However, some existing older commands and
 complex types use underscore; when extending such expressions,
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 3af4c2c..d53b5c4 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -390,10 +390,10 @@ def add_name(name, info, meta, implicit=False):
         raise QAPIExprError(info,
                             "%s '%s' is already defined"
                             % (all_names[name], name))
-    if not implicit and name.endswith('Kind'):
+    if not implicit and (name.endswith('Kind') or name.endswith('List')):
         raise QAPIExprError(info,
-                            "%s '%s' should not end in 'Kind'"
-                            % (meta, name))
+                            "%s '%s' should not end in '%s'"
+                            % (meta, name, name[-4:]))
     all_names[name] = meta


@@ -1196,9 +1196,7 @@ class QAPISchema(object):
         return name

     def _make_array_type(self, element_type, info):
-        # TODO fooList namespace is not reserved; user can create collisions,
-        # or abuse our type system with ['fooList'] for 2D array
-        name = element_type + 'List'
+        name = element_type + 'List'   # Use namespace reserved by add_name()
         if not self.lookup_type(name):
             self._def_entity(QAPISchemaArrayType(name, info, element_type))
         return name
diff --git a/tests/qapi-schema/struct-name-list.err b/tests/qapi-schema/struct-name-list.err
index e69de29..ee5b09b 100644
--- a/tests/qapi-schema/struct-name-list.err
+++ b/tests/qapi-schema/struct-name-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-name-list.json:5: struct 'FooList' should not end in 'List'
diff --git a/tests/qapi-schema/struct-name-list.exit b/tests/qapi-schema/struct-name-list.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/struct-name-list.exit
+++ b/tests/qapi-schema/struct-name-list.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/struct-name-list.json b/tests/qapi-schema/struct-name-list.json
index 8ad38e6..98d53bf 100644
--- a/tests/qapi-schema/struct-name-list.json
+++ b/tests/qapi-schema/struct-name-list.json
@@ -1,5 +1,5 @@
 # Potential C name collision
-# FIXME - This parses and compiles on its own, but prevents the user from
-# creating a type named 'Foo' and using ['Foo'] for an array.  We should
-# reject the use of any non-array type names ending in 'List'.
+# We reserve names ending in 'List' for use by array types.
+# TODO - we could choose array names to avoid collision with user types,
+# in order to let this compile
 { 'struct': 'FooList', 'data': { 's': 'str' } }
diff --git a/tests/qapi-schema/struct-name-list.out b/tests/qapi-schema/struct-name-list.out
index 0406bfe..e69de29 100644
--- a/tests/qapi-schema/struct-name-list.out
+++ b/tests/qapi-schema/struct-name-list.out
@@ -1,3 +0,0 @@
-object :empty
-object FooList
-    member s: str optional=False
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (3 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 04/25] qapi: Reserve '*List' type names for list types Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 13:05   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 06/25] vnc: Hoist allocation of VncBasicInfo to callers Eric Blake
                   ` (20 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

c_name() produces names starting with 'q_' when protecting
a QMP member name that would fail to directly compile, but
in doing so can cause clashes with any QMP name already
beginning with 'q-' or 'q_'.  Likewise, we create a C name
'has_' for any optional member, that can clash with any QMP
name beginning with 'has-' or 'has_'.

Technically, rather than blindly reserving the namespace,
we could try to complain about user names only when an actual
collision occurs, or even teach c_name() how to munge names
to avoid collisions.  But it is not trivial, especially when
collisions can occur across multiple types (such as via
inheritance or flat unions).  Besides, no existing .json
files are trying to use these names.  So it's easier to just
outright forbid the potential for collision.  We can always
relax things in the future if a real need arises for QMP to
express member names that have been forbidden here.

'has_' only has to be reserved for struct/union member names,
while 'q_' is reserved everywhere (matching the fact that
we only have optional members, but use c_name() everywhere).

Update and add tests to cover the new error messages.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: retitle, improve comments, defer 'u' changes for later, use
c_name(name).startswith('has_') rather than open coding
v9: new patch
---
 docs/qapi-code-gen.txt                  | 11 +++++++----
 scripts/qapi.py                         |  8 +++++++-
 tests/qapi-schema/args-has-clash.err    |  1 +
 tests/qapi-schema/args-has-clash.exit   |  2 +-
 tests/qapi-schema/args-has-clash.json   |  8 ++++----
 tests/qapi-schema/args-has-clash.out    |  6 ------
 tests/qapi-schema/reserved-command.err  |  1 +
 tests/qapi-schema/reserved-command.exit |  2 +-
 tests/qapi-schema/reserved-command.json |  7 +++----
 tests/qapi-schema/reserved-command.out  |  5 -----
 tests/qapi-schema/reserved-member.err   |  1 +
 tests/qapi-schema/reserved-member.exit  |  2 +-
 tests/qapi-schema/reserved-member.json  |  7 +++----
 tests/qapi-schema/reserved-member.out   |  4 ----
 14 files changed, 30 insertions(+), 35 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index c4264a8..4d8c2fc 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -112,7 +112,9 @@ and field names within a type, should be all lower case with words
 separated by a hyphen.  However, some existing older commands and
 complex types use underscore; when extending such expressions,
 consistency is preferred over blindly avoiding underscore.  Event
-names should be ALL_CAPS with words separated by underscore.
+names should be ALL_CAPS with words separated by underscore.  Field
+names cannot start with 'has-' or 'has_', as this is reserved for
+tracking optional fields.

 Any name (command, event, type, field, or enum value) beginning with
 "x-" is marked experimental, and may be withdrawn or changed
@@ -123,9 +125,10 @@ 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.
-It is okay to reuse names that match C keywords; the generator will
-rename a field named "default" in the QAPI to "q_default" in the
-generated C code.
+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 d53b5c4..04bcbf7 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -376,7 +376,9 @@ def check_name(expr_info, source, name, allow_optional=False,
     # code always prefixes it with the enum name
     if enum_member:
         membername = '_' + membername
-    if not valid_name.match(membername):
+    # Reserve the entire 'q_' namespace for c_name()
+    if not valid_name.match(membername) or \
+       membername.replace('-', '_').startswith('q_'):
         raise QAPIExprError(expr_info,
                             "%s uses invalid name '%s'" % (source, name))

@@ -488,6 +490,10 @@ def check_type(expr_info, source, value, allow_array=False,
     for (key, arg) in value.items():
         check_name(expr_info, "Member of %s" % source, key,
                    allow_optional=allow_optional)
+        if c_name(key).startswith('has_'):
+            raise QAPIExprError(expr_info,
+                                "Member of %s uses reserved name '%s'"
+                                % (source, key))
         # Todo: allow dictionaries to represent default values of
         # an optional argument.
         check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
diff --git a/tests/qapi-schema/args-has-clash.err b/tests/qapi-schema/args-has-clash.err
index e69de29..595fe93 100644
--- a/tests/qapi-schema/args-has-clash.err
+++ b/tests/qapi-schema/args-has-clash.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-has-clash.json:6: Member of 'data' for command 'oops' uses reserved name 'has-a'
diff --git a/tests/qapi-schema/args-has-clash.exit b/tests/qapi-schema/args-has-clash.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/args-has-clash.exit
+++ b/tests/qapi-schema/args-has-clash.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/args-has-clash.json b/tests/qapi-schema/args-has-clash.json
index a2197de..38453e7 100644
--- a/tests/qapi-schema/args-has-clash.json
+++ b/tests/qapi-schema/args-has-clash.json
@@ -1,6 +1,6 @@
 # C member name collision
-# FIXME - This parses, but fails to compile, because the C struct is given
-# two 'has_a' members, one from the flag for optional 'a', and the other
-# from member 'has-a'.  Either reject this at parse time, or munge the C
-# names to avoid the collision.
+# This would attempt to create two 'has_a' members of the C struct, one
+# from the flag for optional 'a', and the other from member 'has-a'; so
+# instead we reject any member with a name that would collide with 'has_'.
+# TODO we could munge the optional flag name to avoid the collision.
 { 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
diff --git a/tests/qapi-schema/args-has-clash.out b/tests/qapi-schema/args-has-clash.out
index 5a18b6b..e69de29 100644
--- a/tests/qapi-schema/args-has-clash.out
+++ b/tests/qapi-schema/args-has-clash.out
@@ -1,6 +0,0 @@
-object :empty
-object :obj-oops-arg
-    member a: str optional=True
-    member has-a: str optional=False
-command oops :obj-oops-arg -> None
-   gen=True success_response=True
diff --git a/tests/qapi-schema/reserved-command.err b/tests/qapi-schema/reserved-command.err
index e69de29..a70856b 100644
--- a/tests/qapi-schema/reserved-command.err
+++ b/tests/qapi-schema/reserved-command.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-command.json:6: 'command' uses invalid name 'q-unix'
diff --git a/tests/qapi-schema/reserved-command.exit b/tests/qapi-schema/reserved-command.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/reserved-command.exit
+++ b/tests/qapi-schema/reserved-command.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/reserved-command.json b/tests/qapi-schema/reserved-command.json
index be9944c..d662a96 100644
--- a/tests/qapi-schema/reserved-command.json
+++ b/tests/qapi-schema/reserved-command.json
@@ -1,7 +1,6 @@
 # C entity name collision
-# FIXME - This parses, but fails to compile, because it attempts to declare
-# two 'qmp_q_unix' functions (one for 'q-unix', the other because c_name()
-# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
-# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
+# This would attempt to declare two 'qmp_q_unix' functions (one for 'q-unix',
+# the other because c_name() munges 'unix' to 'q_unix' to avoid reserved word
+# collisions). Therefore, we reserve 'q_' names for qapi.
 { 'command': 'unix' }
 { 'command': 'q-unix' }
diff --git a/tests/qapi-schema/reserved-command.out b/tests/qapi-schema/reserved-command.out
index b31b38f..e69de29 100644
--- a/tests/qapi-schema/reserved-command.out
+++ b/tests/qapi-schema/reserved-command.out
@@ -1,5 +0,0 @@
-object :empty
-command q-unix None -> None
-   gen=True success_response=True
-command unix None -> None
-   gen=True success_response=True
diff --git a/tests/qapi-schema/reserved-member.err b/tests/qapi-schema/reserved-member.err
index e69de29..8752c5b 100644
--- a/tests/qapi-schema/reserved-member.err
+++ b/tests/qapi-schema/reserved-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member.json:5: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
diff --git a/tests/qapi-schema/reserved-member.exit b/tests/qapi-schema/reserved-member.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/reserved-member.exit
+++ b/tests/qapi-schema/reserved-member.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/reserved-member.json b/tests/qapi-schema/reserved-member.json
index 1602ed3..a8dac22 100644
--- a/tests/qapi-schema/reserved-member.json
+++ b/tests/qapi-schema/reserved-member.json
@@ -1,6 +1,5 @@
 # C member name collision
-# FIXME - This parses, but fails to compile, because it attempts to declare
-# two 'q_unix' members (one for 'q-unix', the other because c_name()
-# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
-# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
+# This would attempt to declare two 'q_unix' members (one for 'q-unix',
+# the other because c_name() munges 'unix' to 'q_unix' to avoid reserved word
+# collisions). Therefore, we reserve 'q_' names for qapi.
 { 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }
diff --git a/tests/qapi-schema/reserved-member.out b/tests/qapi-schema/reserved-member.out
index 0d8685a..e69de29 100644
--- a/tests/qapi-schema/reserved-member.out
+++ b/tests/qapi-schema/reserved-member.out
@@ -1,4 +0,0 @@
-object :empty
-object Foo
-    member unix: int optional=False
-    member q-unix: bool optional=False
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 06/25] vnc: Hoist allocation of VncBasicInfo to callers
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (4 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl Eric Blake
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Gerd Hoffmann

A future qapi patch will rework generated structs with a base
class to be unboxed.  In preparation for that, change the code
that allocates then populates an info struct to instead merely
populate the fields of an info field passed in as a parameter
(renaming vnc_basic_info_get* to vnc_init_basic_info*). Add
rudimentary Error handling at the lowest levels for cases
where the old code returned NULL; but rather than plumb Error
all the way through the stack, the callers drop the error and
return NULL as before.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: improve commit message (including a retitle), rename
functions, tweak error message, don't change semantics of
vnc_server_info_get()
v9: (no v6-8): hoist from v5 33/46
---
 ui/vnc.c | 57 ++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 34 insertions(+), 23 deletions(-)

diff --git a/ui/vnc.c b/ui/vnc.c
index faff054..502a10a 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -156,10 +156,11 @@ char *vnc_socket_remote_addr(const char *format, int fd) {
     return addr_to_string(format, &sa, salen);
 }

-static VncBasicInfo *vnc_basic_info_get(struct sockaddr_storage *sa,
-                                        socklen_t salen)
+static void vnc_init_basic_info(struct sockaddr_storage *sa,
+                                socklen_t salen,
+                                VncBasicInfo *info,
+                                Error **errp)
 {
-    VncBasicInfo *info;
     char host[NI_MAXHOST];
     char serv[NI_MAXSERV];
     int err;
@@ -168,42 +169,44 @@ static VncBasicInfo *vnc_basic_info_get(struct sockaddr_storage *sa,
                            host, sizeof(host),
                            serv, sizeof(serv),
                            NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
-        VNC_DEBUG("Cannot resolve address %d: %s\n",
-                  err, gai_strerror(err));
-        return NULL;
+        error_setg(errp, "Cannot resolve address: %s",
+                   gai_strerror(err));
+        return;
     }

-    info = g_malloc0(sizeof(VncBasicInfo));
     info->host = g_strdup(host);
     info->service = g_strdup(serv);
     info->family = inet_netfamily(sa->ss_family);
-    return info;
 }

-static VncBasicInfo *vnc_basic_info_get_from_server_addr(int fd)
+static void vnc_init_basic_info_from_server_addr(int fd, VncBasicInfo *info,
+                                                 Error **errp)
 {
     struct sockaddr_storage sa;
     socklen_t salen;

     salen = sizeof(sa);
     if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
-        return NULL;
+        error_setg_errno(errp, errno, "getsockname failed");
+        return;
     }

-    return vnc_basic_info_get(&sa, salen);
+    vnc_init_basic_info(&sa, salen, info, errp);
 }

-static VncBasicInfo *vnc_basic_info_get_from_remote_addr(int fd)
+static void vnc_init_basic_info_from_remote_addr(int fd, VncBasicInfo *info,
+                                                 Error **errp)
 {
     struct sockaddr_storage sa;
     socklen_t salen;

     salen = sizeof(sa);
     if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
-        return NULL;
+        error_setg_errno(errp, errno, "getpeername failed");
+        return;
     }

-    return vnc_basic_info_get(&sa, salen);
+    vnc_init_basic_info(&sa, salen, info, errp);
 }

 static const char *vnc_auth_name(VncDisplay *vd) {
@@ -256,15 +259,18 @@ static const char *vnc_auth_name(VncDisplay *vd) {
 static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
 {
     VncServerInfo *info;
-    VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vd->lsock);
-    if (!bi) {
-        return NULL;
-    }
+    Error *err = NULL;

     info = g_malloc(sizeof(*info));
-    info->base = bi;
+    info->base = g_malloc(sizeof(*info->base));
+    vnc_init_basic_info_from_server_addr(vd->lsock, info->base, &err);
     info->has_auth = true;
     info->auth = g_strdup(vnc_auth_name(vd));
+    if (err) {
+        qapi_free_VncServerInfo(info);
+        info = NULL;
+        error_free(err);
+    }
     return info;
 }

@@ -291,11 +297,16 @@ static void vnc_client_cache_auth(VncState *client)

 static void vnc_client_cache_addr(VncState *client)
 {
-    VncBasicInfo *bi = vnc_basic_info_get_from_remote_addr(client->csock);
+    Error *err = NULL;

-    if (bi) {
-        client->info = g_malloc0(sizeof(*client->info));
-        client->info->base = bi;
+    client->info = g_malloc0(sizeof(*client->info));
+    client->info->base = g_malloc0(sizeof(*client->info->base));
+    vnc_init_basic_info_from_remote_addr(client->csock, client->info->base,
+                                         &err);
+    if (err) {
+        qapi_free_VncClientInfo(client->info);
+        client->info = NULL;
+        error_free(err);
     }
 }

-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (5 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 06/25] vnc: Hoist allocation of VncBasicInfo to callers Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 13:46   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output Eric Blake
                   ` (18 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We generate a static visit_type_FOO_fields() for every type
FOO.  However, sometimes we need a forward declaration. Split
the code to generate the forward declaration out of
gen_visit_implicit_struct() into a new gen_visit_fields_decl(),
and also prepare for a forward declaration to be emitted
during gen_visit_struct(), so that a future patch can switch
from using visit_type_FOO_implicit() to the simpler
visit_type_FOO_fields() as part of unboxing the base class
of a struct.

No change to generated code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch, split from 5/17
---
 scripts/qapi-visit.py | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index e878018..7204ed0 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -15,7 +15,12 @@
 from qapi import *
 import re

+# visit_type_FOO_implicit() is emitted as needed; track if it has already
+# been output. No forward declaration is needed.
 implicit_structs_seen = set()
+
+# visit_type_FOO_fields() is always emitted; track if a forward declaration
+# or implementation has already been output.
 struct_fields_seen = set()


@@ -29,19 +34,24 @@ void visit_type_%(c_name)s(Visitor *v, %(c_type)sobj, const char *name, Error **
                  c_name=c_name(name), c_type=c_type)


+def gen_visit_fields_decl(typ):
+    ret = ''
+    if typ.name not in struct_fields_seen:
+        ret += mcgen('''
+
+static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
+''',
+                     c_type=typ.c_name())
+        struct_fields_seen.add(typ.name)
+    return ret
+
+
 def gen_visit_implicit_struct(typ):
     if typ in implicit_structs_seen:
         return ''
     implicit_structs_seen.add(typ)

-    ret = ''
-    if typ.name not in struct_fields_seen:
-        # Need a forward declaration
-        ret += mcgen('''
-
-static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
-''',
-                     c_type=typ.c_name())
+    ret = gen_visit_fields_decl(typ)

     ret += mcgen('''

@@ -62,13 +72,12 @@ static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error *


 def gen_visit_struct_fields(name, base, members):
-    struct_fields_seen.add(name)
-
     ret = ''

     if base:
         ret += gen_visit_implicit_struct(base)

+    struct_fields_seen.add(name)
     ret += mcgen('''

 static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
@@ -100,7 +109,11 @@ out:


 def gen_visit_struct(name, base, members):
-    ret = gen_visit_struct_fields(name, base, members)
+    ret = ''
+    if base:
+        ret += gen_visit_fields_decl(base)
+
+    ret += gen_visit_struct_fields(name, base, members)

     # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
     # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (6 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 15:06   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes Eric Blake
                   ` (17 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Move code from gen_union() into gen_struct_fields() in order for
a later patch to share code when enumerating inherited fields
for struct types.

No change to generated code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch, split off of 5/17
---
 scripts/qapi-types.py | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4fe618e..a97cc10 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -51,9 +51,19 @@ def gen_struct_field(name, typ, optional):
     return ret


-def gen_struct_fields(members):
+def gen_struct_fields(members, base=None):
     ret = ''

+    if base:
+        ret += mcgen('''
+    /* Members inherited from %(c_name)s: */
+''',
+                     c_name=base.c_name())
+        ret += gen_struct_fields(base.members)
+        ret += mcgen('''
+    /* Own members: */
+''')
+
     for memb in members:
         ret += gen_struct_field(memb.name, memb.type, memb.optional)
     return ret
@@ -126,14 +136,7 @@ struct %(c_name)s {
 ''',
                 c_name=c_name(name))
     if base:
-        ret += mcgen('''
-    /* Members inherited from %(c_name)s: */
-''',
-                     c_name=c_name(base.name))
-        ret += gen_struct_fields(base.members)
-        ret += mcgen('''
-    /* Own members: */
-''')
+        ret += gen_struct_fields([], base)
     else:
         ret += mcgen('''
     %(c_type)s kind;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (7 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 15:30   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members Eric Blake
                   ` (16 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, armbru, Michael Roth

A previous patch (commit 1e6c1616) made it possible to
directly cast from a qapi type to its base type. A future
patch will do likewise for structs.  However, it requires
the client code to use a C cast, which turns off compiler
type-safety checks if the client gets it wrong.  So this
patch adds inline type-safe wrappers named qapi_FOO_base()
for any type FOO that has a base, which can be used to
upcast a qapi type to its base, then uses the new generated
functions in places where we were already casting.

Some of the ugliness of this patch will disappear once
structs are laid out in the same manner as unions; mark
it with TODO for now.

Note that C makes const-correct upcasts annoying because
it lacks overloads; these functions cast away const so that
they can accept user pointers whether const or not, and the
result in turn can be assigned to normal or const pointers.
Alternatively, this could have been done with macros, but
those tend to not have quite as much type safety.

This patch just adds upcasts.  None of our code needed to
downcast from a base qapi class to a child.  Also, in the
case of grandchildren (such as BlockdevOptionsQcow2), the
caller will need to call two functions to get to the inner
base (although it wouldn't be too hard to generate a
qapi_FOO_base_base() if desired).  If a user changes qapi
to alter the base class hierarchy, such as going from
'A -> C' to 'A -> B -> C', it will change the type of
'qapi_C_base()', and the compiler will point out the places
that are affected by the new base.

One alternative was proposed, but was deemed too ugly to use
in practice: the generators could output redundant
information using anonymous types:
| struct Child {
|     union {
|         struct {
|             Type1 parent_member1;
|             Type2 parent_member2;
|         };
|         Parent base;
|     };
| };
With that ugly proposal, for a given qapi type, obj->member
and obj->base.member would refer to the same storage; allowing
convenience in working with members without needing 'base.'
allowing typesafe upcast without needing a C cast by accessing
'&obj->base', and allowing downcasts from the parent back to
the child possible through container_of(obj, Child, base).

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch
---
 scripts/qapi-types.py | 20 ++++++++++++++++++++
 ui/spice-core.c       | 14 ++++++++++----
 ui/vnc.c              |  9 ++++++---
 3 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index a97cc10..ed4a11c 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -97,6 +97,23 @@ struct %(c_name)s {
     return ret


+def gen_upcast(name, base, struct):
+    # C makes const-correctness ugly.  We have to cast away const to let
+    # this function work for both const and non-const obj.
+    # TODO Ugly difference between struct and flat union bases
+    member = ''
+    if struct:
+        member = '->base'
+    return mcgen('''
+
+static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
+{
+    return (%(base)s *)obj%(member)s;
+}
+''',
+                 c_name=c_name(name), base=base.c_name(), member=member)
+
+
 def gen_alternate_qtypes_decl(name):
     return mcgen('''

@@ -268,6 +285,9 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             self.decl += gen_union(name, base, variants)
         else:
             self.decl += gen_struct(name, base, members)
+        if base:
+            # TODO Drop last param once structs have sane layout
+            self.decl += gen_upcast(name, base, not variants)
         self._gen_type_cleanup(name)

     def visit_alternate_type(self, name, info, variants):
diff --git a/ui/spice-core.c b/ui/spice-core.c
index bf4fd07..d43cfbe 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -218,9 +218,11 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
     }

     if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
-        add_addr_info(client->base, (struct sockaddr *)&info->paddr_ext,
+        add_addr_info(qapi_SpiceChannel_base(client),
+                      (struct sockaddr *)&info->paddr_ext,
                       info->plen_ext);
-        add_addr_info(server->base, (struct sockaddr *)&info->laddr_ext,
+        add_addr_info(qapi_SpiceServerInfo_base(server),
+                      (struct sockaddr *)&info->laddr_ext,
                       info->llen_ext);
     } else {
         error_report("spice: %s, extended address is expected",
@@ -229,7 +231,9 @@ static void channel_event(int event, SpiceChannelEventInfo *info)

     switch (event) {
     case SPICE_CHANNEL_EVENT_CONNECTED:
-        qapi_event_send_spice_connected(server->base, client->base, &error_abort);
+        qapi_event_send_spice_connected(qapi_SpiceServerInfo_base(server),
+                                        qapi_SpiceChannel_base(client),
+                                        &error_abort);
         break;
     case SPICE_CHANNEL_EVENT_INITIALIZED:
         if (auth) {
@@ -242,7 +246,9 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
         break;
     case SPICE_CHANNEL_EVENT_DISCONNECTED:
         channel_list_del(info);
-        qapi_event_send_spice_disconnected(server->base, client->base, &error_abort);
+        qapi_event_send_spice_disconnected(qapi_SpiceServerInfo_base(server),
+                                           qapi_SpiceChannel_base(client),
+                                           &error_abort);
         break;
     default:
         break;
diff --git a/ui/vnc.c b/ui/vnc.c
index 502a10a..9473b32 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -263,7 +263,8 @@ static VncServerInfo *vnc_server_info_get(VncDisplay *vd)

     info = g_malloc(sizeof(*info));
     info->base = g_malloc(sizeof(*info->base));
-    vnc_init_basic_info_from_server_addr(vd->lsock, info->base, &err);
+    vnc_init_basic_info_from_server_addr(vd->lsock,
+                                         qapi_VncServerInfo_base(info), &err);
     info->has_auth = true;
     info->auth = g_strdup(vnc_auth_name(vd));
     if (err) {
@@ -301,7 +302,8 @@ static void vnc_client_cache_addr(VncState *client)

     client->info = g_malloc0(sizeof(*client->info));
     client->info->base = g_malloc0(sizeof(*client->info->base));
-    vnc_init_basic_info_from_remote_addr(client->csock, client->info->base,
+    vnc_init_basic_info_from_remote_addr(client->csock,
+                                         qapi_VncClientInfo_base(client->info),
                                          &err);
     if (err) {
         qapi_free_VncClientInfo(client->info);
@@ -326,7 +328,8 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event)

     switch (event) {
     case QAPI_EVENT_VNC_CONNECTED:
-        qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
+        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
+                                      &error_abort);
         break;
     case QAPI_EVENT_VNC_INITIALIZED:
         qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (8 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 19:14   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 11/25] qapi-visit: Remove redundant functions for flat union base Eric Blake
                   ` (15 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael Roth, Gerd Hoffmann, armbru, Luiz Capitulino

Rather than storing a base class as a pointer to a box, just
store the fields of that base class in the same order, so that
a child struct can be directly cast to its parent.  This gives
less malloc overhead, less pointer dereferencing, and even less
generated code.  Compare to the earlier commit 1e6c1616a "qapi:
Generate a nicer struct for flat unions" (although that patch
had fewer places to change, as less of qemu was directly using
qapi structs for flat unions).  It also drops a hack that was
needed for type-safe casting to the base class of a struct.

Changes to the generated code look like this in qapi-types.h:

| struct SpiceChannel {
|-    SpiceBasicInfo *base;
|+    /* Members inherited from SpiceBasicInfo: */
|+    char *host;
|+    char *port;
|+    NetworkAddressFamily family;
|+    /* Own members: */
|     int64_t connection_id;

as well as:

| static inline SpiceBasicInfo *qapi_SpiceChannel_base(const SpiceChannel *obj)
| {
|-    return (SpiceBasicInfo *)obj->base;
|+    return (SpiceBasicInfo *)obj;
| }

and this in qapi-visit.c:

| static void visit_type_SpiceChannel_fields(Visitor *v, SpiceChannel **obj, Error **errp)
| {
|     Error *err = NULL;
|
|-    visit_type_implicit_SpiceBasicInfo(v, &(*obj)->base, &err);
|+    visit_type_SpiceBasiInfo_fields(v, (SpiceBasicInfo **)obj, &err);
|     if (err) {

plus the wholesale elimination of some now-unused
visit_type_implicit_FOO() functions.

Without boxing, the corner case of one empty struct having
another empty struct as its base type now requires inserting a
dummy member (previously, the pointer to the base would have
sufficed).

And now that we no longer consume a 'base' member in the generated
C struct, we can delete the former negative struct-base-clash-base
test.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: split off some of the cleanups into earlier patches, improve
commit message, don't emit visit_type_FOO_fields out of order,
save positive tests in qapi-schema-tests for later
v9: (no v6-8): hoist from v5 34/46, rebase to master
---
 hmp.c                                         |  6 +++---
 scripts/qapi-types.py                         | 20 ++++++--------------
 scripts/qapi-visit.py                         | 13 ++++---------
 tests/Makefile                                |  1 -
 tests/qapi-schema/struct-base-clash-base.err  |  0
 tests/qapi-schema/struct-base-clash-base.exit |  1 -
 tests/qapi-schema/struct-base-clash-base.json |  9 ---------
 tests/qapi-schema/struct-base-clash-base.out  |  5 -----
 tests/test-qmp-commands.c                     | 15 +++++----------
 tests/test-qmp-event.c                        |  8 ++------
 tests/test-qmp-input-visitor.c                |  4 ++--
 tests/test-qmp-output-visitor.c               | 13 +++++--------
 tests/test-visitor-serialization.c            | 14 ++++++--------
 ui/spice-core.c                               |  9 +++------
 ui/vnc.c                                      | 12 ++++--------
 15 files changed, 40 insertions(+), 90 deletions(-)
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.err
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.exit
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.json
 delete mode 100644 tests/qapi-schema/struct-base-clash-base.out

diff --git a/hmp.c b/hmp.c
index 5048eee..88fd804 100644
--- a/hmp.c
+++ b/hmp.c
@@ -569,8 +569,8 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
         for (client = info->clients; client; client = client->next) {
             monitor_printf(mon, "Client:\n");
             monitor_printf(mon, "     address: %s:%s\n",
-                           client->value->base->host,
-                           client->value->base->service);
+                           client->value->host,
+                           client->value->service);
             monitor_printf(mon, "  x509_dname: %s\n",
                            client->value->x509_dname ?
                            client->value->x509_dname : "none");
@@ -638,7 +638,7 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict)
         for (chan = info->channels; chan; chan = chan->next) {
             monitor_printf(mon, "Channel:\n");
             monitor_printf(mon, "     address: %s:%s%s\n",
-                           chan->value->base->host, chan->value->base->port,
+                           chan->value->host, chan->value->port,
                            chan->value->tls ? " [tls]" : "");
             monitor_printf(mon, "     session: %" PRId64 "\n",
                            chan->value->connection_id);
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index ed4a11c..9c51d8f 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -76,16 +76,13 @@ struct %(c_name)s {
 ''',
                 c_name=c_name(name))

-    if base:
-        ret += gen_struct_field('base', base, False)
-
-    ret += gen_struct_fields(members)
+    ret += gen_struct_fields(members, base)

     # 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 not members:
+    if not (base and base.members) and not members:
         ret += mcgen('''
     char qapi_dummy_field_for_empty_struct;
 ''')
@@ -97,21 +94,17 @@ struct %(c_name)s {
     return ret


-def gen_upcast(name, base, struct):
+def gen_upcast(name, base):
     # C makes const-correctness ugly.  We have to cast away const to let
     # this function work for both const and non-const obj.
-    # TODO Ugly difference between struct and flat union bases
-    member = ''
-    if struct:
-        member = '->base'
     return mcgen('''

 static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
 {
-    return (%(base)s *)obj%(member)s;
+    return (%(base)s *)obj;
 }
 ''',
-                 c_name=c_name(name), base=base.c_name(), member=member)
+                 c_name=c_name(name), base=base.c_name())


 def gen_alternate_qtypes_decl(name):
@@ -286,8 +279,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
         else:
             self.decl += gen_struct(name, base, members)
         if base:
-            # TODO Drop last param once structs have sane layout
-            self.decl += gen_upcast(name, base, not variants)
+            self.decl += gen_upcast(name, base)
         self._gen_type_cleanup(name)

     def visit_alternate_type(self, name, info, variants):
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 7204ed0..e30062b 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -72,26 +72,21 @@ static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error *


 def gen_visit_struct_fields(name, base, members):
-    ret = ''
-
-    if base:
-        ret += gen_visit_implicit_struct(base)
-
     struct_fields_seen.add(name)
-    ret += mcgen('''
+    ret = mcgen('''

 static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
 {
     Error *err = NULL;

 ''',
-                 c_name=c_name(name))
+                c_name=c_name(name))

     if base:
         ret += mcgen('''
-    visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
+    visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err);
 ''',
-                     c_type=base.c_name(), c_name=c_name('base'))
+                     c_type=base.c_name())
         ret += gen_err_check()

     ret += gen_visit_fields(members, prefix='(*obj)->')
diff --git a/tests/Makefile b/tests/Makefile
index cc6b24f..9194264 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -322,7 +322,6 @@ qapi-schema += returns-array-bad.json
 qapi-schema += returns-dict.json
 qapi-schema += returns-unknown.json
 qapi-schema += returns-whitelist.json
-qapi-schema += struct-base-clash-base.json
 qapi-schema += struct-base-clash-deep.json
 qapi-schema += struct-base-clash.json
 qapi-schema += struct-data-invalid.json
diff --git a/tests/qapi-schema/struct-base-clash-base.err b/tests/qapi-schema/struct-base-clash-base.err
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/struct-base-clash-base.exit b/tests/qapi-schema/struct-base-clash-base.exit
deleted file mode 100644
index 573541a..0000000
--- a/tests/qapi-schema/struct-base-clash-base.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/struct-base-clash-base.json b/tests/qapi-schema/struct-base-clash-base.json
deleted file mode 100644
index 0c84025..0000000
--- a/tests/qapi-schema/struct-base-clash-base.json
+++ /dev/null
@@ -1,9 +0,0 @@
-# Struct member 'base'
-# FIXME: this parses, but then fails to compile due to a duplicate 'base'
-# (one explicit in QMP, the other used to box the base class members).
-# We should either reject the collision at parse time, or change the
-# generated struct to allow this to compile.
-{ 'struct': 'Base', 'data': {} }
-{ 'struct': 'Sub',
-  'base': 'Base',
-  'data': { 'base': 'str' } }
diff --git a/tests/qapi-schema/struct-base-clash-base.out b/tests/qapi-schema/struct-base-clash-base.out
deleted file mode 100644
index e69a416..0000000
--- a/tests/qapi-schema/struct-base-clash-base.out
+++ /dev/null
@@ -1,5 +0,0 @@
-object :empty
-object Base
-object Sub
-    base Base
-    member base: str optional=False
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index bc59835..ea700d8 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -25,11 +25,9 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a,
     UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne));

     ud1c->string = strdup(ud1a->string);
-    ud1c->base = g_new0(UserDefZero, 1);
-    ud1c->base->integer = ud1a->base->integer;
+    ud1c->integer = ud1a->integer;
     ud1d->string = strdup(has_udb1 ? ud1b->string : "blah0");
-    ud1d->base = g_new0(UserDefZero, 1);
-    ud1d->base->integer = has_udb1 ? ud1b->base->integer : 0;
+    ud1d->integer = has_udb1 ? ud1b->integer : 0;

     ret = g_new0(UserDefTwo, 1);
     ret->string0 = strdup("blah1");
@@ -176,20 +174,17 @@ static void test_dealloc_types(void)
     UserDefOneList *ud1list;

     ud1test = g_malloc0(sizeof(UserDefOne));
-    ud1test->base = g_new0(UserDefZero, 1);
-    ud1test->base->integer = 42;
+    ud1test->integer = 42;
     ud1test->string = g_strdup("hi there 42");

     qapi_free_UserDefOne(ud1test);

     ud1a = g_malloc0(sizeof(UserDefOne));
-    ud1a->base = g_new0(UserDefZero, 1);
-    ud1a->base->integer = 43;
+    ud1a->integer = 43;
     ud1a->string = g_strdup("hi there 43");

     ud1b = g_malloc0(sizeof(UserDefOne));
-    ud1b->base = g_new0(UserDefZero, 1);
-    ud1b->base->integer = 44;
+    ud1b->integer = 44;
     ud1b->string = g_strdup("hi there 44");

     ud1list = g_malloc0(sizeof(UserDefOneList));
diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index 28f146d..035c65c 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -179,9 +179,7 @@ static void test_event_c(TestEventData *data,
     QDict *d, *d_data, *d_b;

     UserDefOne b;
-    UserDefZero z;
-    z.integer = 2;
-    b.base = &z;
+    b.integer = 2;
     b.string = g_strdup("test1");
     b.has_enum1 = false;

@@ -209,11 +207,9 @@ static void test_event_d(TestEventData *data,
 {
     UserDefOne struct1;
     EventStructOne a;
-    UserDefZero z;
     QDict *d, *d_data, *d_a, *d_struct1;

-    z.integer = 2;
-    struct1.base = &z;
+    struct1.integer = 2;
     struct1.string = g_strdup("test1");
     struct1.has_enum1 = true;
     struct1.enum1 = ENUM_ONE_VALUE1;
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 8941963..514cfd0 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -262,7 +262,7 @@ static void test_visitor_in_struct_nested(TestInputVisitorData *data,

     check_and_free_str(udp->string0, "string0");
     check_and_free_str(udp->dict1->string1, "string1");
-    g_assert_cmpint(udp->dict1->dict2->userdef->base->integer, ==, 42);
+    g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42);
     check_and_free_str(udp->dict1->dict2->userdef->string, "string");
     check_and_free_str(udp->dict1->dict2->string, "string2");
     g_assert(udp->dict1->has_dict3 == false);
@@ -292,7 +292,7 @@ static void test_visitor_in_list(TestInputVisitorData *data,

         snprintf(string, sizeof(string), "string%d", i);
         g_assert_cmpstr(item->value->string, ==, string);
-        g_assert_cmpint(item->value->base->integer, ==, 42 + i);
+        g_assert_cmpint(item->value->integer, ==, 42 + i);
     }

     qapi_free_UserDefOneList(head);
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index c84002e..cfb06bb 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -250,16 +250,14 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
     ud2->dict1->dict2 = g_malloc0(sizeof(*ud2->dict1->dict2));
     ud2->dict1->dict2->userdef = g_new0(UserDefOne, 1);
     ud2->dict1->dict2->userdef->string = g_strdup(string);
-    ud2->dict1->dict2->userdef->base = g_new0(UserDefZero, 1);
-    ud2->dict1->dict2->userdef->base->integer = value;
+    ud2->dict1->dict2->userdef->integer = value;
     ud2->dict1->dict2->string = g_strdup(strings[2]);

     ud2->dict1->dict3 = g_malloc0(sizeof(*ud2->dict1->dict3));
     ud2->dict1->has_dict3 = true;
     ud2->dict1->dict3->userdef = g_new0(UserDefOne, 1);
     ud2->dict1->dict3->userdef->string = g_strdup(string);
-    ud2->dict1->dict3->userdef->base = g_new0(UserDefZero, 1);
-    ud2->dict1->dict3->userdef->base->integer = value;
+    ud2->dict1->dict3->userdef->integer = value;
     ud2->dict1->dict3->string = g_strdup(strings[3]);

     visit_type_UserDefTwo(data->ov, &ud2, "unused", &err);
@@ -301,8 +299,8 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
                                            const void *unused)
 {
     EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
-    UserDefZero b;
-    UserDefOne u = { .base = &b }, *pu = &u;
+    UserDefOne u = {0};
+    UserDefOne *pu = &u;
     Error *err;
     int i;

@@ -416,8 +414,7 @@ static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
         p->value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1);
         p->value->dict1->dict2->userdef = g_new0(UserDefOne, 1);
         p->value->dict1->dict2->userdef->string = g_strdup(string);
-        p->value->dict1->dict2->userdef->base = g_new0(UserDefZero, 1);
-        p->value->dict1->dict2->userdef->base->integer = 42;
+        p->value->dict1->dict2->userdef->integer = 42;
         p->value->dict1->dict2->string = g_strdup(string);
         p->value->dict1->has_dict3 = false;

diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index fa86cae..634563b 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -258,15 +258,13 @@ static UserDefTwo *nested_struct_create(void)
     udnp->dict1->string1 = strdup("test_string1");
     udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
     udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
-    udnp->dict1->dict2->userdef->base = g_new0(UserDefZero, 1);
-    udnp->dict1->dict2->userdef->base->integer = 42;
+    udnp->dict1->dict2->userdef->integer = 42;
     udnp->dict1->dict2->userdef->string = strdup("test_string");
     udnp->dict1->dict2->string = strdup("test_string2");
     udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
     udnp->dict1->has_dict3 = true;
     udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
-    udnp->dict1->dict3->userdef->base = g_new0(UserDefZero, 1);
-    udnp->dict1->dict3->userdef->base->integer = 43;
+    udnp->dict1->dict3->userdef->integer = 43;
     udnp->dict1->dict3->userdef->string = strdup("test_string");
     udnp->dict1->dict3->string = strdup("test_string3");
     return udnp;
@@ -278,15 +276,15 @@ static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
     g_assert(udnp2);
     g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
     g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
-    g_assert_cmpint(udnp1->dict1->dict2->userdef->base->integer, ==,
-                    udnp2->dict1->dict2->userdef->base->integer);
+    g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
+                    udnp2->dict1->dict2->userdef->integer);
     g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
                     udnp2->dict1->dict2->userdef->string);
     g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
                     udnp2->dict1->dict2->string);
     g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
-    g_assert_cmpint(udnp1->dict1->dict3->userdef->base->integer, ==,
-                    udnp2->dict1->dict3->userdef->base->integer);
+    g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
+                    udnp2->dict1->dict3->userdef->integer);
     g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
                     udnp2->dict1->dict3->userdef->string);
     g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
diff --git a/ui/spice-core.c b/ui/spice-core.c
index d43cfbe..6a62d71 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -200,8 +200,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
 {
     SpiceServerInfo *server = g_malloc0(sizeof(*server));
     SpiceChannel *client = g_malloc0(sizeof(*client));
-    server->base = g_malloc0(sizeof(*server->base));
-    client->base = g_malloc0(sizeof(*client->base));

     /*
      * Spice server might have called us from spice worker thread
@@ -384,16 +382,15 @@ static SpiceChannelList *qmp_query_spice_channels(void)

         chan = g_malloc0(sizeof(*chan));
         chan->value = g_malloc0(sizeof(*chan->value));
-        chan->value->base = g_malloc0(sizeof(*chan->value->base));

         paddr = (struct sockaddr *)&item->info->paddr_ext;
         plen = item->info->plen_ext;
         getnameinfo(paddr, plen,
                     host, sizeof(host), port, sizeof(port),
                     NI_NUMERICHOST | NI_NUMERICSERV);
-        chan->value->base->host = g_strdup(host);
-        chan->value->base->port = g_strdup(port);
-        chan->value->base->family = inet_netfamily(paddr->sa_family);
+        chan->value->host = g_strdup(host);
+        chan->value->port = g_strdup(port);
+        chan->value->family = inet_netfamily(paddr->sa_family);

         chan->value->connection_id = item->info->connection_id;
         chan->value->channel_type = item->info->type;
diff --git a/ui/vnc.c b/ui/vnc.c
index 9473b32..cec2cee 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -262,7 +262,6 @@ static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
     Error *err = NULL;

     info = g_malloc(sizeof(*info));
-    info->base = g_malloc(sizeof(*info->base));
     vnc_init_basic_info_from_server_addr(vd->lsock,
                                          qapi_VncServerInfo_base(info), &err);
     info->has_auth = true;
@@ -301,7 +300,6 @@ static void vnc_client_cache_addr(VncState *client)
     Error *err = NULL;

     client->info = g_malloc0(sizeof(*client->info));
-    client->info->base = g_malloc0(sizeof(*client->info->base));
     vnc_init_basic_info_from_remote_addr(client->csock,
                                          qapi_VncClientInfo_base(client->info),
                                          &err);
@@ -319,7 +317,6 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event)
     if (!vs->info) {
         return;
     }
-    g_assert(vs->info->base);

     si = vnc_server_info_get(vs->vd);
     if (!si) {
@@ -364,11 +361,10 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client)
     }

     info = g_malloc0(sizeof(*info));
-    info->base = g_malloc0(sizeof(*info->base));
-    info->base->host = g_strdup(host);
-    info->base->service = g_strdup(serv);
-    info->base->family = inet_netfamily(sa.ss_family);
-    info->base->websocket = client->websocket;
+    info->host = g_strdup(host);
+    info->service = g_strdup(serv);
+    info->family = inet_netfamily(sa.ss_family);
+    info->websocket = client->websocket;

     if (client->tls) {
         info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 11/25] qapi-visit: Remove redundant functions for flat union base
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (9 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 19:35   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 12/25] qapi: Start converting to new qapi union layout Eric Blake
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

The code for visiting the base class of a child struct created
visit_type_Base_fields() which covers all fields of Base; while
the code for visiting the base class of a flat union created
visit_type_Union_fields() covering all fields of the base
except the discriminator.  But since the base class includes
the discriminator of a flat union, we can just visit the entire
base, without needing a separate visit of the discriminator.
Not only is consistently visiting all fields easier to
understand, it lets us share code.

The generated code in qapi-visit.c loses several now-unused
visit_type_UNION_fields(), along with changes like:

|@@ -1654,11 +1557,7 @@ void visit_type_BlockdevOptions(Visitor
|     if (!*obj) {
|         goto out_obj;
|     }
|-    visit_type_BlockdevOptions_fields(v, obj, &err);
|-    if (err) {
|-        goto out_obj;
|-    }
|-    visit_type_BlockdevDriver(v, &(*obj)->driver, "driver", &err);
|+    visit_type_BlockdevOptionsBase_fields(v, (BlockdevOptionsBase **)obj, &err);
|     if (err) {
|         goto out_obj;
|     }

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: split out regex to earlier commit, rebase to earlier changes,
improve commit message
v9: (no v6-8): hoist from v5 35/46; rebase to master; fix indentation
botch in gen_visit_union(); polish commit message
---
 scripts/qapi-visit.py | 32 +++++++++++++++-----------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index e30062b..3c23c53 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -226,8 +226,7 @@ def gen_visit_union(name, base, variants):
     ret = ''

     if base:
-        members = [m for m in base.members if m != variants.tag_member]
-        ret += gen_visit_struct_fields(name, None, members)
+        ret += gen_visit_fields_decl(base)

     for var in variants.variants:
         # Ugly special case for simple union TODO get rid of it
@@ -252,31 +251,30 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error

     if base:
         ret += mcgen('''
-    visit_type_%(c_name)s_fields(v, obj, &err);
+    visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err);
 ''',
-                     c_name=c_name(name))
-        ret += gen_err_check(label='out_obj')
-
-    tag_key = variants.tag_member.name
-    if not variants.tag_name:
-        # we pointlessly use a different key for simple unions
-        tag_key = 'type'
-    ret += mcgen('''
+                     c_name=base.c_name())
+    else:
+        ret += mcgen('''
     visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
-    if (err) {
-        goto out_obj;
-    }
+''',
+                     c_type=variants.tag_member.type.c_name(),
+                     # TODO ugly special case for simple union
+                     # Use same tag name in C as on the wire to get rid of
+                     # it, then: c_name=c_name(variants.tag_member.name)
+                     c_name='kind',
+                     name=variants.tag_member.name)
+    ret += gen_err_check(label='out_obj')
+    ret += mcgen('''
     if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
         goto out_obj;
     }
     switch ((*obj)->%(c_name)s) {
 ''',
-                 c_type=variants.tag_member.type.c_name(),
                  # TODO ugly special case for simple union
                  # Use same tag name in C as on the wire to get rid of
                  # it, then: c_name=c_name(variants.tag_member.name)
-                 c_name=c_name(variants.tag_name or 'kind'),
-                 name=tag_key)
+                 c_name=c_name(variants.tag_name or 'kind'))

     for var in variants.variants:
         # TODO ugly special case for simple union
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 12/25] qapi: Start converting to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (10 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 11/25] qapi-visit: Remove redundant functions for flat union base Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert " Eric Blake
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

This patch is the front end for a series that converts to a
saner qapi union layout.  By the end of the series, we will no
longer have the type/kind mismatch, and all tag values will be
under a named union, which requires clients to access
'obj->u.value' instead of 'obj->value'.  But since the
conversion touches a number of files, it is easiest if we
temporarily support BOTH layouts simultaneously.

Given a simple union qapi type:

{ 'union':'Foo', 'data': { 'a':'int', 'b':'bool' } }

make the following changes in generated qapi-types.h:

| struct Foo {
|-    FooKind kind;
|-    union { /* union tag is @kind */
|+    union {
|+        FooKind kind;
|+        FooKind type;
|+    };
|+    union { /* union tag is @type */
|         void *data;
|         int64_t a;
|         bool b;
|+        union { /* union tag is @type */
|+            void *data;
|+            int64_t a;
|+            bool b;
|+        } u;
|     };
| };

Flat unions do not need the anonymous union for the tag member,
as we already fixed that to use the member name instead of 'kind'
back in commit 0f61af3e.

Later, when the conversions are complete, we will remove the
duplication hacks.

Note, however, that we do not rename the generated enum, which
is still 'FooKind'.  A further patch could generate implicit
enums as 'FooType', but while the generator already reserved
the '*Kind' namespace (commit 4dc2e69), there are already QMP
constructs with '*Type' naming, which means changing our
reservation namespace would have lots of churn to C code to
deal with a forced name change.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: rebase to earlier changes, improve commit message, defer
qapi-visit and testsuite 'u' changes to later
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 scripts/qapi-types.py | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 9c51d8f..579532d 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -148,11 +148,23 @@ struct %(c_name)s {
     if base:
         ret += gen_struct_fields([], base)
     else:
+        # TODO As a hack, we emit both 'kind' and 'type'. Ultimately, we
+        # want to use only 'type', but the conversion is large enough to
+        # require staging over several commits.
         ret += mcgen('''
-    %(c_type)s kind;
+    union {
+        %(c_type)s kind;
+        %(c_type)s type;
+    };
 ''',
                      c_type=c_name(variants.tag_member.type.name))

+    # TODO As a hack, we emit the union twice, once as an anonymous union
+    # and once as a named union.  Ultimately, we want to use only the
+    # named union version (as it avoids conflicts between tag values as
+    # branch names competing with non-variant QMP names), but the conversion
+    # is large enough to require staging over several commits.
+    tmp = ''
     # 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
@@ -161,25 +173,25 @@ 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('''
+    tmp += mcgen('''
     union { /* union tag is @%(c_name)s */
         void *data;
 ''',
-                 # TODO ugly special case for simple union
-                 # Use same tag name in C as on the wire to get rid of
-                 # it, then: c_name=c_name(variants.tag_member.name)
-                 c_name=c_name(variants.tag_name or 'kind'))
+                 c_name=c_name(variants.tag_member.name))

     for var in variants.variants:
         # Ugly special case for simple union TODO get rid of it
         typ = var.simple_union_type() or var.type
-        ret += mcgen('''
+        tmp += mcgen('''
         %(c_type)s %(c_name)s;
 ''',
                      c_type=typ.c_type(),
                      c_name=c_name(var.name))

+    ret += tmp
+    ret += '    ' + '\n    '.join(tmp.split('\n'))
     ret += mcgen('''
+    } u;
     };
 };
 ''')
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (11 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 12/25] qapi: Start converting to new qapi union layout Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-26 17:07   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 14/25] tests: " Eric Blake
                   ` (12 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for qapi-visit.py.  Also
make a change in qapi.py to quit using the name 'kind', and
the corresponding change in the testsuite.  However, many more
changes will be made to the testsuite later, including the
entire deletion of union-clash-type.json, after the completion
of the conversion eliminates collisions between union tag
branch names and non-variant names.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch, split from 7/17 an 8/17
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 scripts/qapi-visit.py                  | 24 +++++++++---------------
 scripts/qapi.py                        |  2 +-
 tests/qapi-schema/union-clash-type.err |  2 +-
 3 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 3c23c53..421fcb6 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -187,18 +187,18 @@ 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)->kind, %(c_name)s_qtypes, name, &err);
+    visit_get_next_type(v, (int*) &(*obj)->type, %(c_name)s_qtypes, name, &err);
     if (err) {
         goto out_obj;
     }
-    switch ((*obj)->kind) {
+    switch ((*obj)->type) {
 ''',
                 c_name=c_name(name))

     for var in variants.variants:
         ret += mcgen('''
     case %(case)s:
-        visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, name, &err);
+        visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err);
         break;
 ''',
                      case=c_enum_const(variants.tag_member.type.name,
@@ -259,22 +259,16 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
     visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
 ''',
                      c_type=variants.tag_member.type.c_name(),
-                     # TODO ugly special case for simple union
-                     # Use same tag name in C as on the wire to get rid of
-                     # it, then: c_name=c_name(variants.tag_member.name)
-                     c_name='kind',
+                     c_name=c_name(variants.tag_member.name),
                      name=variants.tag_member.name)
     ret += gen_err_check(label='out_obj')
     ret += mcgen('''
-    if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
+    if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
         goto out_obj;
     }
     switch ((*obj)->%(c_name)s) {
 ''',
-                 # TODO ugly special case for simple union
-                 # Use same tag name in C as on the wire to get rid of
-                 # it, then: c_name=c_name(variants.tag_member.name)
-                 c_name=c_name(variants.tag_name or 'kind'))
+                 c_name=c_name(variants.tag_member.name))

     for var in variants.variants:
         # TODO ugly special case for simple union
@@ -286,13 +280,13 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
                                        var.name))
         if simple_union_type:
             ret += mcgen('''
-        visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "data", &err);
+        visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, "data", &err);
 ''',
                          c_type=simple_union_type.c_name(),
                          c_name=c_name(var.name))
         else:
             ret += mcgen('''
-        visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
+        visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
 ''',
                          c_type=var.type.c_name(),
                          c_name=c_name(var.name))
@@ -308,7 +302,7 @@ out_obj:
     error_propagate(errp, err);
     err = NULL;
     if (*obj) {
-        visit_end_union(v, !!(*obj)->data, &err);
+        visit_end_union(v, !!(*obj)->u.data, &err);
     }
     error_propagate(errp, err);
     err = NULL;
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 04bcbf7..8b9f5f7 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -548,7 +548,7 @@ def check_union(expr, expr_info):
     base = expr.get('base')
     discriminator = expr.get('discriminator')
     members = expr['data']
-    values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
+    values = {'MAX': '(automatic)', 'TYPE': '(automatic tag)'}

     # Two types of unions, determined by discriminator.

diff --git a/tests/qapi-schema/union-clash-type.err b/tests/qapi-schema/union-clash-type.err
index a5dead1..eca7c1d 100644
--- a/tests/qapi-schema/union-clash-type.err
+++ b/tests/qapi-schema/union-clash-type.err
@@ -1 +1 @@
-tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'kind' clashes with '(automatic)'
+tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'type' clashes with '(automatic tag)'
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 14/25] tests: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (12 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 15/25] block: " Eric Blake
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for testsuite code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: split qapi.py change into earlier less-mechanical patch
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 tests/test-qmp-commands.c       |  4 +--
 tests/test-qmp-input-visitor.c  | 78 ++++++++++++++++++++---------------------
 tests/test-qmp-output-visitor.c | 42 +++++++++++-----------
 3 files changed, 62 insertions(+), 62 deletions(-)

diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index ea700d8..f23d8ea 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -62,8 +62,8 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
 {
     __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1);

-    ret->kind = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
-    ret->__org_qemu_x_branch = strdup("blah1");
+    ret->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
+    ret->u.__org_qemu_x_branch = strdup("blah1");

     return ret;
 }
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 514cfd0..617eada 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -359,7 +359,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
     g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
     g_assert_cmpstr(tmp->string, ==, "str");
     g_assert_cmpint(tmp->integer, ==, 41);
-    g_assert_cmpint(tmp->value1->boolean, ==, true);
+    g_assert_cmpint(tmp->u.value1->boolean, ==, true);
     qapi_free_UserDefFlatUnion(tmp);
 }

@@ -372,15 +372,15 @@ 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->kind, ==, USER_DEF_ALTERNATE_KIND_I);
-    g_assert_cmpint(tmp->i, ==, 42);
+    g_assert_cmpint(tmp->type, ==, USER_DEF_ALTERNATE_KIND_I);
+    g_assert_cmpint(tmp->u.i, ==, 42);
     qapi_free_UserDefAlternate(tmp);
     visitor_input_teardown(data, NULL);

     v = visitor_input_test_init(data, "'string'");
     visit_type_UserDefAlternate(v, &tmp, NULL, &error_abort);
-    g_assert_cmpint(tmp->kind, ==, USER_DEF_ALTERNATE_KIND_S);
-    g_assert_cmpstr(tmp->s, ==, "string");
+    g_assert_cmpint(tmp->type, ==, USER_DEF_ALTERNATE_KIND_S);
+    g_assert_cmpstr(tmp->u.s, ==, "string");
     qapi_free_UserDefAlternate(tmp);
     visitor_input_teardown(data, NULL);

@@ -419,8 +419,8 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data,
      * parse the same as ans */
     v = visitor_input_test_init(data, "42");
     visit_type_AltStrNum(v, &asn, NULL, &err);
-    /* FIXME g_assert_cmpint(asn->kind, == ALT_STR_NUM_KIND_N); */
-    /* FIXME g_assert_cmpfloat(asn->n, ==, 42); */
+    /* FIXME g_assert_cmpint(asn->type, == ALT_STR_NUM_KIND_N); */
+    /* FIXME g_assert_cmpfloat(asn->u.n, ==, 42); */
     g_assert(err);
     error_free(err);
     err = NULL;
@@ -429,29 +429,29 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data,

     v = visitor_input_test_init(data, "42");
     visit_type_AltNumStr(v, &ans, NULL, &error_abort);
-    g_assert_cmpint(ans->kind, ==, ALT_NUM_STR_KIND_N);
-    g_assert_cmpfloat(ans->n, ==, 42);
+    g_assert_cmpint(ans->type, ==, ALT_NUM_STR_KIND_N);
+    g_assert_cmpfloat(ans->u.n, ==, 42);
     qapi_free_AltNumStr(ans);
     visitor_input_teardown(data, NULL);

     v = visitor_input_test_init(data, "42");
     visit_type_AltStrInt(v, &asi, NULL, &error_abort);
-    g_assert_cmpint(asi->kind, ==, ALT_STR_INT_KIND_I);
-    g_assert_cmpint(asi->i, ==, 42);
+    g_assert_cmpint(asi->type, ==, ALT_STR_INT_KIND_I);
+    g_assert_cmpint(asi->u.i, ==, 42);
     qapi_free_AltStrInt(asi);
     visitor_input_teardown(data, NULL);

     v = visitor_input_test_init(data, "42");
     visit_type_AltIntNum(v, &ain, NULL, &error_abort);
-    g_assert_cmpint(ain->kind, ==, ALT_INT_NUM_KIND_I);
-    g_assert_cmpint(ain->i, ==, 42);
+    g_assert_cmpint(ain->type, ==, ALT_INT_NUM_KIND_I);
+    g_assert_cmpint(ain->u.i, ==, 42);
     qapi_free_AltIntNum(ain);
     visitor_input_teardown(data, NULL);

     v = visitor_input_test_init(data, "42");
     visit_type_AltNumInt(v, &ani, NULL, &error_abort);
-    g_assert_cmpint(ani->kind, ==, ALT_NUM_INT_KIND_I);
-    g_assert_cmpint(ani->i, ==, 42);
+    g_assert_cmpint(ani->type, ==, ALT_NUM_INT_KIND_I);
+    g_assert_cmpint(ani->u.i, ==, 42);
     qapi_free_AltNumInt(ani);
     visitor_input_teardown(data, NULL);

@@ -467,15 +467,15 @@ 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->kind, ==, ALT_STR_NUM_KIND_N);
-    g_assert_cmpfloat(asn->n, ==, 42.5);
+    g_assert_cmpint(asn->type, ==, ALT_STR_NUM_KIND_N);
+    g_assert_cmpfloat(asn->u.n, ==, 42.5);
     qapi_free_AltStrNum(asn);
     visitor_input_teardown(data, NULL);

     v = visitor_input_test_init(data, "42.5");
     visit_type_AltNumStr(v, &ans, NULL, &error_abort);
-    g_assert_cmpint(ans->kind, ==, ALT_NUM_STR_KIND_N);
-    g_assert_cmpfloat(ans->n, ==, 42.5);
+    g_assert_cmpint(ans->type, ==, ALT_NUM_STR_KIND_N);
+    g_assert_cmpfloat(ans->u.n, ==, 42.5);
     qapi_free_AltNumStr(ans);
     visitor_input_teardown(data, NULL);

@@ -489,15 +489,15 @@ 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->kind, ==, ALT_INT_NUM_KIND_N);
-    g_assert_cmpfloat(ain->n, ==, 42.5);
+    g_assert_cmpint(ain->type, ==, ALT_INT_NUM_KIND_N);
+    g_assert_cmpfloat(ain->u.n, ==, 42.5);
     qapi_free_AltIntNum(ain);
     visitor_input_teardown(data, NULL);

     v = visitor_input_test_init(data, "42.5");
     visit_type_AltNumInt(v, &ani, NULL, &error_abort);
-    g_assert_cmpint(ani->kind, ==, ALT_NUM_INT_KIND_N);
-    g_assert_cmpfloat(ani->n, ==, 42.5);
+    g_assert_cmpint(ani->type, ==, ALT_NUM_INT_KIND_N);
+    g_assert_cmpfloat(ani->u.n, ==, 42.5);
     qapi_free_AltNumInt(ani);
     visitor_input_teardown(data, NULL);
 }
@@ -527,68 +527,68 @@ static void test_native_list_integer_helper(TestInputVisitorData *data,
     visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
     g_assert(err == NULL);
     g_assert(cvalue != NULL);
-    g_assert_cmpint(cvalue->kind, ==, kind);
+    g_assert_cmpint(cvalue->type, ==, kind);

     switch (kind) {
     case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
         intList *elem = NULL;
-        for (i = 0, elem = cvalue->integer; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.integer; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S8: {
         int8List *elem = NULL;
-        for (i = 0, elem = cvalue->s8; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s8; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S16: {
         int16List *elem = NULL;
-        for (i = 0, elem = cvalue->s16; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s16; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S32: {
         int32List *elem = NULL;
-        for (i = 0, elem = cvalue->s32; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s32; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S64: {
         int64List *elem = NULL;
-        for (i = 0, elem = cvalue->s64; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s64; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U8: {
         uint8List *elem = NULL;
-        for (i = 0, elem = cvalue->u8; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u8; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U16: {
         uint16List *elem = NULL;
-        for (i = 0, elem = cvalue->u16; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u16; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U32: {
         uint32List *elem = NULL;
-        for (i = 0, elem = cvalue->u32; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u32; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U64: {
         uint64List *elem = NULL;
-        for (i = 0, elem = cvalue->u64; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u64; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
@@ -690,9 +690,9 @@ static void test_visitor_in_native_list_bool(TestInputVisitorData *data,
     visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
     g_assert(err == NULL);
     g_assert(cvalue != NULL);
-    g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN);
+    g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN);

-    for (i = 0, elem = cvalue->boolean; elem; elem = elem->next, i++) {
+    for (i = 0, elem = cvalue->u.boolean; elem; elem = elem->next, i++) {
         g_assert_cmpint(elem->value, ==, (i % 3 == 0) ? 1 : 0);
     }

@@ -725,9 +725,9 @@ static void test_visitor_in_native_list_string(TestInputVisitorData *data,
     visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
     g_assert(err == NULL);
     g_assert(cvalue != NULL);
-    g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING);
+    g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING);

-    for (i = 0, elem = cvalue->string; elem; elem = elem->next, i++) {
+    for (i = 0, elem = cvalue->u.string; elem; elem = elem->next, i++) {
         gchar str[8];
         sprintf(str, "%d", i);
         g_assert_cmpstr(elem->value, ==, str);
@@ -764,9 +764,9 @@ static void test_visitor_in_native_list_number(TestInputVisitorData *data,
     visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
     g_assert(err == NULL);
     g_assert(cvalue != NULL);
-    g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER);
+    g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER);

-    for (i = 0, elem = cvalue->number; elem; elem = elem->next, i++) {
+    for (i = 0, elem = cvalue->u.number; elem; elem = elem->next, i++) {
         GString *double_expected = g_string_new("");
         GString *double_actual = g_string_new("");

diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index cfb06bb..09d0dd8 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -487,9 +487,9 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
     UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
     tmp->enum1 = ENUM_ONE_VALUE1;
     tmp->string = g_strdup("str");
-    tmp->value1 = g_malloc0(sizeof(UserDefA));
-    /* TODO when generator bug is fixed: tmp->integer = 41; */
-    tmp->value1->boolean = true;
+    tmp->u.value1 = g_malloc0(sizeof(UserDefA));
+    tmp->integer = 41;
+    tmp->u.value1->boolean = true;

     visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err);
     g_assert(err == NULL);
@@ -500,7 +500,7 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,

     g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1");
     g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
-    /* TODO g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); */
+    g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41);
     g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);

     qapi_free_UserDefFlatUnion(tmp);
@@ -514,8 +514,8 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
     Error *err = NULL;

     UserDefAlternate *tmp = g_malloc0(sizeof(UserDefAlternate));
-    tmp->kind = USER_DEF_ALTERNATE_KIND_I;
-    tmp->i = 42;
+    tmp->type = USER_DEF_ALTERNATE_KIND_I;
+    tmp->u.i = 42;

     visit_type_UserDefAlternate(data->ov, &tmp, NULL, &err);
     g_assert(err == NULL);
@@ -540,9 +540,9 @@ static void test_visitor_out_empty(TestOutputVisitorData *data,
 static void init_native_list(UserDefNativeListUnion *cvalue)
 {
     int i;
-    switch (cvalue->kind) {
+    switch (cvalue->type) {
     case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
-        intList **list = &cvalue->integer;
+        intList **list = &cvalue->u.integer;
         for (i = 0; i < 32; i++) {
             *list = g_new0(intList, 1);
             (*list)->value = i;
@@ -552,7 +552,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S8: {
-        int8List **list = &cvalue->s8;
+        int8List **list = &cvalue->u.s8;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int8List, 1);
             (*list)->value = i;
@@ -562,7 +562,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S16: {
-        int16List **list = &cvalue->s16;
+        int16List **list = &cvalue->u.s16;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int16List, 1);
             (*list)->value = i;
@@ -572,7 +572,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S32: {
-        int32List **list = &cvalue->s32;
+        int32List **list = &cvalue->u.s32;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int32List, 1);
             (*list)->value = i;
@@ -582,7 +582,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S64: {
-        int64List **list = &cvalue->s64;
+        int64List **list = &cvalue->u.s64;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int64List, 1);
             (*list)->value = i;
@@ -592,7 +592,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U8: {
-        uint8List **list = &cvalue->u8;
+        uint8List **list = &cvalue->u.u8;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint8List, 1);
             (*list)->value = i;
@@ -602,7 +602,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U16: {
-        uint16List **list = &cvalue->u16;
+        uint16List **list = &cvalue->u.u16;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint16List, 1);
             (*list)->value = i;
@@ -612,7 +612,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U32: {
-        uint32List **list = &cvalue->u32;
+        uint32List **list = &cvalue->u.u32;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint32List, 1);
             (*list)->value = i;
@@ -622,7 +622,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U64: {
-        uint64List **list = &cvalue->u64;
+        uint64List **list = &cvalue->u.u64;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint64List, 1);
             (*list)->value = i;
@@ -632,7 +632,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: {
-        boolList **list = &cvalue->boolean;
+        boolList **list = &cvalue->u.boolean;
         for (i = 0; i < 32; i++) {
             *list = g_new0(boolList, 1);
             (*list)->value = (i % 3 == 0);
@@ -642,7 +642,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: {
-        strList **list = &cvalue->string;
+        strList **list = &cvalue->u.string;
         for (i = 0; i < 32; i++) {
             *list = g_new0(strList, 1);
             (*list)->value = g_strdup_printf("%d", i);
@@ -652,7 +652,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue)
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: {
-        numberList **list = &cvalue->number;
+        numberList **list = &cvalue->u.number;
         for (i = 0; i < 32; i++) {
             *list = g_new0(numberList, 1);
             (*list)->value = (double)i / 3;
@@ -761,14 +761,14 @@ static void test_native_list(TestOutputVisitorData *data,
     Error *err = NULL;
     QObject *obj;

-    cvalue->kind = kind;
+    cvalue->type = kind;
     init_native_list(cvalue);

     visit_type_UserDefNativeListUnion(data->ov, &cvalue, NULL, &err);
     g_assert(err == NULL);

     obj = qmp_output_get_qobject(data->qov);
-    check_native_list(obj, cvalue->kind);
+    check_native_list(obj, cvalue->type);
     qapi_free_UserDefNativeListUnion(cvalue);
     qobject_decref(obj);
 }
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 15/25] block: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (13 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 14/25] tests: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 16/25] sockets: " Eric Blake
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Paolo Bonzini, Fam Zheng, armbru, open list:Block layer core

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for block-related code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 block/nbd.c   | 18 +++++++++---------
 block/qcow2.c | 10 ++++------
 block/vmdk.c  |  6 +++---
 blockdev.c    | 47 ++++++++++++++++++++++++-----------------------
 4 files changed, 40 insertions(+), 41 deletions(-)

diff --git a/block/nbd.c b/block/nbd.c
index c2a87e9..cd6a587 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -206,24 +206,24 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, char **export,
     saddr = g_new0(SocketAddress, 1);

     if (qdict_haskey(options, "path")) {
-        saddr->kind = SOCKET_ADDRESS_KIND_UNIX;
-        saddr->q_unix = g_new0(UnixSocketAddress, 1);
-        saddr->q_unix->path = g_strdup(qdict_get_str(options, "path"));
+        saddr->type = SOCKET_ADDRESS_KIND_UNIX;
+        saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
+        saddr->u.q_unix->path = g_strdup(qdict_get_str(options, "path"));
         qdict_del(options, "path");
     } else {
-        saddr->kind = SOCKET_ADDRESS_KIND_INET;
-        saddr->inet = g_new0(InetSocketAddress, 1);
-        saddr->inet->host = g_strdup(qdict_get_str(options, "host"));
+        saddr->type = SOCKET_ADDRESS_KIND_INET;
+        saddr->u.inet = g_new0(InetSocketAddress, 1);
+        saddr->u.inet->host = g_strdup(qdict_get_str(options, "host"));
         if (!qdict_get_try_str(options, "port")) {
-            saddr->inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
+            saddr->u.inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
         } else {
-            saddr->inet->port = g_strdup(qdict_get_str(options, "port"));
+            saddr->u.inet->port = g_strdup(qdict_get_str(options, "port"));
         }
         qdict_del(options, "host");
         qdict_del(options, "port");
     }

-    s->client.is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX;
+    s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;

     *export = g_strdup(qdict_get_try_str(options, "export"));
     if (*export) {
diff --git a/block/qcow2.c b/block/qcow2.c
index bacc4f2..88f56c8 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2738,18 +2738,16 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
     ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);

     *spec_info = (ImageInfoSpecific){
-        .kind  = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
-        {
-            .qcow2 = g_new(ImageInfoSpecificQCow2, 1),
-        },
+        .type  = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
+        .u.qcow2 = g_new(ImageInfoSpecificQCow2, 1),
     };
     if (s->qcow_version == 2) {
-        *spec_info->qcow2 = (ImageInfoSpecificQCow2){
+        *spec_info->u.qcow2 = (ImageInfoSpecificQCow2){
             .compat             = g_strdup("0.10"),
             .refcount_bits      = s->refcount_bits,
         };
     } else if (s->qcow_version == 3) {
-        *spec_info->qcow2 = (ImageInfoSpecificQCow2){
+        *spec_info->u.qcow2 = (ImageInfoSpecificQCow2){
             .compat             = g_strdup("1.1"),
             .lazy_refcounts     = s->compatible_features &
                                   QCOW2_COMPAT_LAZY_REFCOUNTS,
diff --git a/block/vmdk.c b/block/vmdk.c
index 0effb7d..6f819e4 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -2161,19 +2161,19 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
     ImageInfoList **next;

     *spec_info = (ImageInfoSpecific){
-        .kind = IMAGE_INFO_SPECIFIC_KIND_VMDK,
+        .type = IMAGE_INFO_SPECIFIC_KIND_VMDK,
         {
             .vmdk = g_new0(ImageInfoSpecificVmdk, 1),
         },
     };

-    *spec_info->vmdk = (ImageInfoSpecificVmdk) {
+    *spec_info->u.vmdk = (ImageInfoSpecificVmdk) {
         .create_type = g_strdup(s->create_type),
         .cid = s->cid,
         .parent_cid = s->parent_cid,
     };

-    next = &spec_info->vmdk->extents;
+    next = &spec_info->u.vmdk->extents;
     for (i = 0; i < s->num_extents; i++) {
         *next = g_new0(ImageInfoList, 1);
         (*next)->value = vmdk_get_extent_info(&s->extents[i]);
diff --git a/blockdev.c b/blockdev.c
index 8141b6b..0bcd3f1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1050,13 +1050,14 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
     }
 }

-static void blockdev_do_action(int kind, void *data, Error **errp)
+static void blockdev_do_action(TransactionActionKind type, void *data,
+                               Error **errp)
 {
     TransactionAction action;
     TransactionActionList list;

-    action.kind = kind;
-    action.data = data;
+    action.type = type;
+    action.u.data = data;
     list.value = &action;
     list.next = NULL;
     qmp_transaction(&list, errp);
@@ -1295,9 +1296,9 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
     InternalSnapshotState *state;
     int ret1;

-    g_assert(common->action->kind ==
+    g_assert(common->action->type ==
              TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC);
-    internal = common->action->blockdev_snapshot_internal_sync;
+    internal = common->action->u.blockdev_snapshot_internal_sync;
     state = DO_UPCAST(InternalSnapshotState, common, common);

     /* 1. parse input */
@@ -1437,22 +1438,22 @@ static void external_snapshot_prepare(BlkTransactionState *common,
     TransactionAction *action = common->action;

     /* get parameters */
-    g_assert(action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC);
+    g_assert(action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC);

-    has_device = action->blockdev_snapshot_sync->has_device;
-    device = action->blockdev_snapshot_sync->device;
-    has_node_name = action->blockdev_snapshot_sync->has_node_name;
-    node_name = action->blockdev_snapshot_sync->node_name;
+    has_device = action->u.blockdev_snapshot_sync->has_device;
+    device = action->u.blockdev_snapshot_sync->device;
+    has_node_name = action->u.blockdev_snapshot_sync->has_node_name;
+    node_name = action->u.blockdev_snapshot_sync->node_name;
     has_snapshot_node_name =
-        action->blockdev_snapshot_sync->has_snapshot_node_name;
-    snapshot_node_name = action->blockdev_snapshot_sync->snapshot_node_name;
+        action->u.blockdev_snapshot_sync->has_snapshot_node_name;
+    snapshot_node_name = action->u.blockdev_snapshot_sync->snapshot_node_name;

-    new_image_file = action->blockdev_snapshot_sync->snapshot_file;
-    if (action->blockdev_snapshot_sync->has_format) {
-        format = action->blockdev_snapshot_sync->format;
+    new_image_file = action->u.blockdev_snapshot_sync->snapshot_file;
+    if (action->u.blockdev_snapshot_sync->has_format) {
+        format = action->u.blockdev_snapshot_sync->format;
     }
-    if (action->blockdev_snapshot_sync->has_mode) {
-        mode = action->blockdev_snapshot_sync->mode;
+    if (action->u.blockdev_snapshot_sync->has_mode) {
+        mode = action->u.blockdev_snapshot_sync->mode;
     }

     /* start processing */
@@ -1577,8 +1578,8 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
     DriveBackup *backup;
     Error *local_err = NULL;

-    assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
-    backup = common->action->drive_backup;
+    assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
+    backup = common->action->u.drive_backup;

     blk = blk_by_name(backup->device);
     if (!blk) {
@@ -1645,8 +1646,8 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
     BlockBackend *blk;
     Error *local_err = NULL;

-    assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
-    backup = common->action->blockdev_backup;
+    assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
+    backup = common->action->u.blockdev_backup;

     blk = blk_by_name(backup->device);
     if (!blk) {
@@ -1772,9 +1773,9 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
         dev_info = dev_entry->value;
         dev_entry = dev_entry->next;

-        assert(dev_info->kind < ARRAY_SIZE(actions));
+        assert(dev_info->type < ARRAY_SIZE(actions));

-        ops = &actions[dev_info->kind];
+        ops = &actions[dev_info->type];
         assert(ops->instance_size > 0);

         state = g_malloc0(ops->instance_size);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 16/25] sockets: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (14 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 15/25] block: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 17/25] net: " Eric Blake
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, armbru, Gerd Hoffmann

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for socket-related code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: rebase to latest, retitle from nbd to sockets
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 qemu-nbd.c          | 16 +++++++-------
 ui/vnc.c            | 44 ++++++++++++++++++-------------------
 util/qemu-sockets.c | 62 ++++++++++++++++++++++++++---------------------------
 3 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/qemu-nbd.c b/qemu-nbd.c
index 422a607..3afec76 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -362,17 +362,17 @@ static SocketAddress *nbd_build_socket_address(const char *sockpath,

     saddr = g_new0(SocketAddress, 1);
     if (sockpath) {
-        saddr->kind = SOCKET_ADDRESS_KIND_UNIX;
-        saddr->q_unix = g_new0(UnixSocketAddress, 1);
-        saddr->q_unix->path = g_strdup(sockpath);
+        saddr->type = SOCKET_ADDRESS_KIND_UNIX;
+        saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
+        saddr->u.q_unix->path = g_strdup(sockpath);
     } else {
-        saddr->kind = SOCKET_ADDRESS_KIND_INET;
-        saddr->inet = g_new0(InetSocketAddress, 1);
-        saddr->inet->host = g_strdup(bindto);
+        saddr->type = SOCKET_ADDRESS_KIND_INET;
+        saddr->u.inet = g_new0(InetSocketAddress, 1);
+        saddr->u.inet->host = g_strdup(bindto);
         if (port) {
-            saddr->inet->port = g_strdup(port);
+            saddr->u.inet->port = g_strdup(port);
         } else  {
-            saddr->inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
+            saddr->u.inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
         }
     }

diff --git a/ui/vnc.c b/ui/vnc.c
index cec2cee..7b37e3b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3524,9 +3524,9 @@ void vnc_display_open(const char *id, Error **errp)
         }

         if (strncmp(vnc, "unix:", 5) == 0) {
-            saddr->kind = SOCKET_ADDRESS_KIND_UNIX;
-            saddr->q_unix = g_new0(UnixSocketAddress, 1);
-            saddr->q_unix->path = g_strdup(vnc + 5);
+            saddr->type = SOCKET_ADDRESS_KIND_UNIX;
+            saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
+            saddr->u.q_unix->path = g_strdup(vnc + 5);

             if (vs->ws_enabled) {
                 error_setg(errp, "UNIX sockets not supported with websock");
@@ -3534,12 +3534,12 @@ void vnc_display_open(const char *id, Error **errp)
             }
         } else {
             unsigned long long baseport;
-            saddr->kind = SOCKET_ADDRESS_KIND_INET;
-            saddr->inet = g_new0(InetSocketAddress, 1);
+            saddr->type = SOCKET_ADDRESS_KIND_INET;
+            saddr->u.inet = g_new0(InetSocketAddress, 1);
             if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
-                saddr->inet->host = g_strndup(vnc + 1, hlen - 2);
+                saddr->u.inet->host = g_strndup(vnc + 1, hlen - 2);
             } else {
-                saddr->inet->host = g_strndup(vnc, hlen);
+                saddr->u.inet->host = g_strndup(vnc, hlen);
             }
             if (parse_uint_full(h + 1, &baseport, 10) < 0) {
                 error_setg(errp, "can't convert to a number: %s", h + 1);
@@ -3550,28 +3550,28 @@ void vnc_display_open(const char *id, Error **errp)
                 error_setg(errp, "port %s out of range", h + 1);
                 goto fail;
             }
-            saddr->inet->port = g_strdup_printf(
+            saddr->u.inet->port = g_strdup_printf(
                 "%d", (int)baseport + 5900);

             if (to) {
-                saddr->inet->has_to = true;
-                saddr->inet->to = to;
+                saddr->u.inet->has_to = true;
+                saddr->u.inet->to = to;
             }
-            saddr->inet->ipv4 = saddr->inet->has_ipv4 = has_ipv4;
-            saddr->inet->ipv6 = saddr->inet->has_ipv6 = has_ipv6;
+            saddr->u.inet->ipv4 = saddr->u.inet->has_ipv4 = has_ipv4;
+            saddr->u.inet->ipv6 = saddr->u.inet->has_ipv6 = has_ipv6;

             if (vs->ws_enabled) {
-                wsaddr->kind = SOCKET_ADDRESS_KIND_INET;
-                wsaddr->inet = g_new0(InetSocketAddress, 1);
-                wsaddr->inet->host = g_strdup(saddr->inet->host);
-                wsaddr->inet->port = g_strdup(websocket);
+                wsaddr->type = SOCKET_ADDRESS_KIND_INET;
+                wsaddr->u.inet = g_new0(InetSocketAddress, 1);
+                wsaddr->u.inet->host = g_strdup(saddr->u.inet->host);
+                wsaddr->u.inet->port = g_strdup(websocket);

                 if (to) {
-                    wsaddr->inet->has_to = true;
-                    wsaddr->inet->to = to;
+                    wsaddr->u.inet->has_to = true;
+                    wsaddr->u.inet->to = to;
                 }
-                wsaddr->inet->ipv4 = wsaddr->inet->has_ipv4 = has_ipv4;
-                wsaddr->inet->ipv6 = wsaddr->inet->has_ipv6 = has_ipv6;
+                wsaddr->u.inet->ipv4 = wsaddr->u.inet->has_ipv4 = has_ipv4;
+                wsaddr->u.inet->ipv6 = wsaddr->u.inet->has_ipv6 = has_ipv6;
             }
         }
     } else {
@@ -3770,7 +3770,7 @@ void vnc_display_open(const char *id, Error **errp)
         if (csock < 0) {
             goto fail;
         }
-        vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX;
+        vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
         vnc_connect(vs, csock, false, false);
     } else {
         /* listen for connects */
@@ -3778,7 +3778,7 @@ void vnc_display_open(const char *id, Error **errp)
         if (vs->lsock < 0) {
             goto fail;
         }
-        vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX;
+        vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
         if (vs->ws_enabled) {
             vs->lwebsock = socket_listen(wsaddr, errp);
             if (vs->lwebsock < 0) {
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 9142917..dfe4587 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -918,23 +918,23 @@ SocketAddress *socket_parse(const char *str, Error **errp)
             error_setg(errp, "invalid Unix socket address");
             goto fail;
         } else {
-            addr->kind = SOCKET_ADDRESS_KIND_UNIX;
-            addr->q_unix = g_new(UnixSocketAddress, 1);
-            addr->q_unix->path = g_strdup(str + 5);
+            addr->type = SOCKET_ADDRESS_KIND_UNIX;
+            addr->u.q_unix = g_new(UnixSocketAddress, 1);
+            addr->u.q_unix->path = g_strdup(str + 5);
         }
     } else if (strstart(str, "fd:", NULL)) {
         if (str[3] == '\0') {
             error_setg(errp, "invalid file descriptor address");
             goto fail;
         } else {
-            addr->kind = SOCKET_ADDRESS_KIND_FD;
-            addr->fd = g_new(String, 1);
-            addr->fd->str = g_strdup(str + 3);
+            addr->type = SOCKET_ADDRESS_KIND_FD;
+            addr->u.fd = g_new(String, 1);
+            addr->u.fd->str = g_strdup(str + 3);
         }
     } else {
-        addr->kind = SOCKET_ADDRESS_KIND_INET;
-        addr->inet = inet_parse(str, errp);
-        if (addr->inet == NULL) {
+        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr->u.inet = inet_parse(str, errp);
+        if (addr->u.inet == NULL) {
             goto fail;
         }
     }
@@ -952,19 +952,19 @@ int socket_connect(SocketAddress *addr, Error **errp,
     int fd;

     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
-    switch (addr->kind) {
+    switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        inet_addr_to_opts(opts, addr->inet);
+        inet_addr_to_opts(opts, addr->u.inet);
         fd = inet_connect_opts(opts, errp, callback, opaque);
         break;

     case SOCKET_ADDRESS_KIND_UNIX:
-        qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort);
+        qemu_opt_set(opts, "path", addr->u.q_unix->path, &error_abort);
         fd = unix_connect_opts(opts, errp, callback, opaque);
         break;

     case SOCKET_ADDRESS_KIND_FD:
-        fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
+        fd = monitor_get_fd(cur_mon, addr->u.fd->str, errp);
         if (fd >= 0 && callback) {
             qemu_set_nonblock(fd);
             callback(fd, NULL, opaque);
@@ -984,19 +984,19 @@ int socket_listen(SocketAddress *addr, Error **errp)
     int fd;

     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
-    switch (addr->kind) {
+    switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        inet_addr_to_opts(opts, addr->inet);
+        inet_addr_to_opts(opts, addr->u.inet);
         fd = inet_listen_opts(opts, 0, errp);
         break;

     case SOCKET_ADDRESS_KIND_UNIX:
-        qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort);
+        qemu_opt_set(opts, "path", addr->u.q_unix->path, &error_abort);
         fd = unix_listen_opts(opts, errp);
         break;

     case SOCKET_ADDRESS_KIND_FD:
-        fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
+        fd = monitor_get_fd(cur_mon, addr->u.fd->str, errp);
         break;

     default:
@@ -1012,12 +1012,12 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
     int fd;

     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
-    switch (remote->kind) {
+    switch (remote->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        inet_addr_to_opts(opts, remote->inet);
+        inet_addr_to_opts(opts, remote->u.inet);
         if (local) {
-            qemu_opt_set(opts, "localaddr", local->inet->host, &error_abort);
-            qemu_opt_set(opts, "localport", local->inet->port, &error_abort);
+            qemu_opt_set(opts, "localaddr", local->u.inet->host, &error_abort);
+            qemu_opt_set(opts, "localport", local->u.inet->port, &error_abort);
         }
         fd = inet_dgram_opts(opts, errp);
         break;
@@ -1052,14 +1052,14 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa,
     }

     addr = g_new0(SocketAddress, 1);
-    addr->kind = SOCKET_ADDRESS_KIND_INET;
-    addr->inet = g_new0(InetSocketAddress, 1);
-    addr->inet->host = g_strdup(host);
-    addr->inet->port = g_strdup(serv);
+    addr->type = SOCKET_ADDRESS_KIND_INET;
+    addr->u.inet = g_new0(InetSocketAddress, 1);
+    addr->u.inet->host = g_strdup(host);
+    addr->u.inet->port = g_strdup(serv);
     if (sa->ss_family == AF_INET) {
-        addr->inet->has_ipv4 = addr->inet->ipv4 = true;
+        addr->u.inet->has_ipv4 = addr->u.inet->ipv4 = true;
     } else {
-        addr->inet->has_ipv6 = addr->inet->ipv6 = true;
+        addr->u.inet->has_ipv6 = addr->u.inet->ipv6 = true;
     }

     return addr;
@@ -1076,11 +1076,11 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
     struct sockaddr_un *su = (struct sockaddr_un *)sa;

     addr = g_new0(SocketAddress, 1);
-    addr->kind = SOCKET_ADDRESS_KIND_UNIX;
-    addr->q_unix = g_new0(UnixSocketAddress, 1);
+    addr->type = SOCKET_ADDRESS_KIND_UNIX;
+    addr->u.q_unix = g_new0(UnixSocketAddress, 1);
     if (su->sun_path[0]) {
-        addr->q_unix->path = g_strndup(su->sun_path,
-                                       sizeof(su->sun_path));
+        addr->u.q_unix->path = g_strndup(su->sun_path,
+                                         sizeof(su->sun_path));
     }

     return addr;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 17/25] net: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (15 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 16/25] sockets: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 18/25] char: " Eric Blake
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jason Wang, armbru, Michael S. Tsirkin

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for net-related code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 net/dump.c       |  4 ++--
 net/hub.c        |  4 ++--
 net/l2tpv3.c     |  4 ++--
 net/net.c        | 24 ++++++++++++------------
 net/slirp.c      |  4 ++--
 net/socket.c     |  4 ++--
 net/tap-win32.c  |  4 ++--
 net/tap.c        |  8 ++++----
 net/vde.c        |  4 ++--
 net/vhost-user.c |  4 ++--
 10 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/net/dump.c b/net/dump.c
index 08259af..2812070 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -154,8 +154,8 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
     char def_file[128];
     const NetdevDumpOptions *dump;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
-    dump = opts->dump;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_DUMP);
+    dump = opts->u.dump;

     assert(peer);

diff --git a/net/hub.c b/net/hub.c
index 3047f12..9ae9f01 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -285,9 +285,9 @@ int net_init_hubport(const NetClientOptions *opts, const char *name,
 {
     const NetdevHubPortOptions *hubport;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_HUBPORT);
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT);
     assert(!peer);
-    hubport = opts->hubport;
+    hubport = opts->u.hubport;

     net_hub_add_port(hubport->hubid, name);
     return 0;
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index 4f9bcee..8e68e54 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -545,8 +545,8 @@ int net_init_l2tpv3(const NetClientOptions *opts,
     s->queue_tail = 0;
     s->header_mismatch = false;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_L2TPV3);
-    l2tpv3 = opts->l2tpv3;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3);
+    l2tpv3 = opts->u.l2tpv3;

     if (l2tpv3->has_ipv6 && l2tpv3->ipv6) {
         s->ipv6 = l2tpv3->ipv6;
diff --git a/net/net.c b/net/net.c
index 3c68f3f..d5aeb31 100644
--- a/net/net.c
+++ b/net/net.c
@@ -882,8 +882,8 @@ static int net_init_nic(const NetClientOptions *opts, const char *name,
     NICInfo *nd;
     const NetLegacyNicOptions *nic;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_NIC);
-    nic = opts->nic;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_NIC);
+    nic = opts->u.nic;

     idx = nic_get_free_idx();
     if (idx == -1 || nb_nics >= MAX_NICS) {
@@ -984,9 +984,9 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
         opts = netdev->opts;
         name = netdev->id;

-        if (opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP ||
-            opts->kind == NET_CLIENT_OPTIONS_KIND_NIC ||
-            !net_client_init_fun[opts->kind]) {
+        if (opts->type == NET_CLIENT_OPTIONS_KIND_DUMP ||
+            opts->type == NET_CLIENT_OPTIONS_KIND_NIC ||
+            !net_client_init_fun[opts->type]) {
             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                        "a netdev backend type");
             return -1;
@@ -997,16 +997,16 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
         /* missing optional values have been initialized to "all bits zero" */
         name = net->has_id ? net->id : net->name;

-        if (opts->kind == NET_CLIENT_OPTIONS_KIND_NONE) {
+        if (opts->type == NET_CLIENT_OPTIONS_KIND_NONE) {
             return 0; /* nothing to do */
         }
-        if (opts->kind == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
+        if (opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                        "a net type");
             return -1;
         }

-        if (!net_client_init_fun[opts->kind]) {
+        if (!net_client_init_fun[opts->type]) {
             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                        "a net backend type (maybe it is not compiled "
                        "into this binary)");
@@ -1014,17 +1014,17 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
         }

         /* Do not add to a vlan if it's a nic with a netdev= parameter. */
-        if (opts->kind != NET_CLIENT_OPTIONS_KIND_NIC ||
-            !opts->nic->has_netdev) {
+        if (opts->type != NET_CLIENT_OPTIONS_KIND_NIC ||
+            !opts->u.nic->has_netdev) {
             peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
         }
     }

-    if (net_client_init_fun[opts->kind](opts, name, peer, errp) < 0) {
+    if (net_client_init_fun[opts->type](opts, name, peer, errp) < 0) {
         /* FIXME drop when all init functions store an Error */
         if (errp && !*errp) {
             error_setg(errp, QERR_DEVICE_INIT_FAILED,
-                       NetClientOptionsKind_lookup[opts->kind]);
+                       NetClientOptionsKind_lookup[opts->type]);
         }
         return -1;
     }
diff --git a/net/slirp.c b/net/slirp.c
index 7657b38..f505570 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -746,8 +746,8 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
     const NetdevUserOptions *user;
     const char **dnssearch;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_USER);
-    user = opts->user;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER);
+    user = opts->u.user;

     vnet = user->has_net ? g_strdup(user->net) :
            user->has_ip  ? g_strdup_printf("%s/24", user->ip) :
diff --git a/net/socket.c b/net/socket.c
index b1e3b1c..e8605d4 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -706,8 +706,8 @@ int net_init_socket(const NetClientOptions *opts, const char *name,
     Error *err = NULL;
     const NetdevSocketOptions *sock;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_SOCKET);
-    sock = opts->socket;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
+    sock = opts->u.socket;

     if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
         sock->has_udp != 1) {
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 625d53c..4e2fa55 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -767,8 +767,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
     /* FIXME error_setg(errp, ...) on failure */
     const NetdevTapOptions *tap;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = opts->tap;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    tap = opts->u.tap;

     if (!tap->has_ifname) {
         error_report("tap: no interface name");
diff --git a/net/tap.c b/net/tap.c
index bd01590..85c4142 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -565,8 +565,8 @@ int net_init_bridge(const NetClientOptions *opts, const char *name,
     TAPState *s;
     int fd, vnet_hdr;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_BRIDGE);
-    bridge = opts->bridge;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE);
+    bridge = opts->u.bridge;

     helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
     br     = bridge->has_br     ? bridge->br     : DEFAULT_BRIDGE_INTERFACE;
@@ -728,8 +728,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
     const char *vhostfdname;
     char ifname[128];

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = opts->tap;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    tap = opts->u.tap;
     queues = tap->has_queues ? tap->queues : 1;
     vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;

diff --git a/net/vde.c b/net/vde.c
index dacaa64..4475d92 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -115,8 +115,8 @@ int net_init_vde(const NetClientOptions *opts, const char *name,
     /* FIXME error_setg(errp, ...) on failure */
     const NetdevVdeOptions *vde;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_VDE);
-    vde = opts->vde;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_VDE);
+    vde = opts->u.vde;

     /* missing optional values have been initialized to "all bits zero" */
     if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group,
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 17b5c2a..0ebd7df 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -301,8 +301,8 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
     const NetdevVhostUserOptions *vhost_user_opts;
     CharDriverState *chr;

-    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
-    vhost_user_opts = opts->vhost_user;
+    assert(opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+    vhost_user_opts = opts->u.vhost_user;

     chr = net_vhost_parse_chardev(vhost_user_opts, errp);
     if (!chr) {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 18/25] char: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (16 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 17/25] net: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 19/25] input: " Eric Blake
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, armbru

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for character-related
code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 qemu-char.c       | 160 +++++++++++++++++++++++++++---------------------------
 spice-qemu-char.c |  12 ++--
 2 files changed, 86 insertions(+), 86 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 908e712..d842aa6 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -97,18 +97,18 @@ static int SocketAddress_to_str(char *dest, int max_len,
                                 const char *prefix, SocketAddress *addr,
                                 bool is_listen, bool is_telnet)
 {
-    switch (addr->kind) {
+    switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
         return snprintf(dest, max_len, "%s%s:%s:%s%s", prefix,
-                        is_telnet ? "telnet" : "tcp", addr->inet->host,
-                        addr->inet->port, is_listen ? ",server" : "");
+                        is_telnet ? "telnet" : "tcp", addr->u.inet->host,
+                        addr->u.inet->port, is_listen ? ",server" : "");
         break;
     case SOCKET_ADDRESS_KIND_UNIX:
         return snprintf(dest, max_len, "%sunix:%s%s", prefix,
-                        addr->q_unix->path, is_listen ? ",server" : "");
+                        addr->u.q_unix->path, is_listen ? ",server" : "");
         break;
     case SOCKET_ADDRESS_KIND_FD:
-        return snprintf(dest, max_len, "%sfd:%s%s", prefix, addr->fd->str,
+        return snprintf(dest, max_len, "%sfd:%s%s", prefix, addr->u.fd->str,
                         is_listen ? ",server" : "");
         break;
     default:
@@ -661,7 +661,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
                                           ChardevBackend *backend,
                                           ChardevReturn *ret, Error **errp)
 {
-    ChardevMux *mux = backend->mux;
+    ChardevMux *mux = backend->u.mux;
     CharDriverState *chr, *drv;
     MuxDriver *d;

@@ -1070,7 +1070,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id,
                                            ChardevReturn *ret,
                                            Error **errp)
 {
-    ChardevHostdev *opts = backend->pipe;
+    ChardevHostdev *opts = backend->u.pipe;
     int fd_in, fd_out;
     char filename_in[CHR_MAX_FILENAME_SIZE];
     char filename_out[CHR_MAX_FILENAME_SIZE];
@@ -1148,7 +1148,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
                                             ChardevReturn *ret,
                                             Error **errp)
 {
-    ChardevStdio *opts = backend->stdio;
+    ChardevStdio *opts = backend->u.stdio;
     CharDriverState *chr;
     struct sigaction act;

@@ -2147,7 +2147,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id,
                                            ChardevReturn *ret,
                                            Error **errp)
 {
-    ChardevHostdev *opts = backend->pipe;
+    ChardevHostdev *opts = backend->u.pipe;
     const char *filename = opts->device;
     CharDriverState *chr;
     WinCharState *s;
@@ -3202,7 +3202,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const char *id,
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevRingbuf *opts = backend->ringbuf;
+    ChardevRingbuf *opts = backend->u.ringbuf;
     CharDriverState *chr;
     RingBufCharDriver *d;

@@ -3477,16 +3477,16 @@ static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: file: no filename given");
         return;
     }
-    backend->file = g_new0(ChardevFile, 1);
-    backend->file->out = g_strdup(path);
+    backend->u.file = g_new0(ChardevFile, 1);
+    backend->u.file->out = g_strdup(path);
 }

 static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
                                  Error **errp)
 {
-    backend->stdio = g_new0(ChardevStdio, 1);
-    backend->stdio->has_signal = true;
-    backend->stdio->signal = qemu_opt_get_bool(opts, "signal", true);
+    backend->u.stdio = g_new0(ChardevStdio, 1);
+    backend->u.stdio->has_signal = true;
+    backend->u.stdio->signal = qemu_opt_get_bool(opts, "signal", true);
 }

 #ifdef HAVE_CHARDEV_SERIAL
@@ -3499,8 +3499,8 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: serial/tty: no device path given");
         return;
     }
-    backend->serial = g_new0(ChardevHostdev, 1);
-    backend->serial->device = g_strdup(device);
+    backend->u.serial = g_new0(ChardevHostdev, 1);
+    backend->u.serial->device = g_strdup(device);
 }
 #endif

@@ -3514,8 +3514,8 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: parallel: no device path given");
         return;
     }
-    backend->parallel = g_new0(ChardevHostdev, 1);
-    backend->parallel->device = g_strdup(device);
+    backend->u.parallel = g_new0(ChardevHostdev, 1);
+    backend->u.parallel->device = g_strdup(device);
 }
 #endif

@@ -3528,8 +3528,8 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: pipe: no device path given");
         return;
     }
-    backend->pipe = g_new0(ChardevHostdev, 1);
-    backend->pipe->device = g_strdup(device);
+    backend->u.pipe = g_new0(ChardevHostdev, 1);
+    backend->u.pipe->device = g_strdup(device);
 }

 static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
@@ -3537,12 +3537,12 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
 {
     int val;

-    backend->ringbuf = g_new0(ChardevRingbuf, 1);
+    backend->u.ringbuf = g_new0(ChardevRingbuf, 1);

     val = qemu_opt_get_size(opts, "size", 0);
     if (val != 0) {
-        backend->ringbuf->has_size = true;
-        backend->ringbuf->size = val;
+        backend->u.ringbuf->has_size = true;
+        backend->u.ringbuf->size = val;
     }
 }

@@ -3555,8 +3555,8 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: mux: no chardev given");
         return;
     }
-    backend->mux = g_new0(ChardevMux, 1);
-    backend->mux->chardev = g_strdup(chardev);
+    backend->u.mux = g_new0(ChardevMux, 1);
+    backend->u.mux->chardev = g_strdup(chardev);
 }

 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
@@ -3583,37 +3583,37 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
         }
     }

-    backend->socket = g_new0(ChardevSocket, 1);
+    backend->u.socket = g_new0(ChardevSocket, 1);

-    backend->socket->has_nodelay = true;
-    backend->socket->nodelay = do_nodelay;
-    backend->socket->has_server = true;
-    backend->socket->server = is_listen;
-    backend->socket->has_telnet = true;
-    backend->socket->telnet = is_telnet;
-    backend->socket->has_wait = true;
-    backend->socket->wait = is_waitconnect;
-    backend->socket->has_reconnect = true;
-    backend->socket->reconnect = reconnect;
+    backend->u.socket->has_nodelay = true;
+    backend->u.socket->nodelay = do_nodelay;
+    backend->u.socket->has_server = true;
+    backend->u.socket->server = is_listen;
+    backend->u.socket->has_telnet = true;
+    backend->u.socket->telnet = is_telnet;
+    backend->u.socket->has_wait = true;
+    backend->u.socket->wait = is_waitconnect;
+    backend->u.socket->has_reconnect = true;
+    backend->u.socket->reconnect = reconnect;

     addr = g_new0(SocketAddress, 1);
     if (path) {
-        addr->kind = SOCKET_ADDRESS_KIND_UNIX;
-        addr->q_unix = g_new0(UnixSocketAddress, 1);
-        addr->q_unix->path = g_strdup(path);
+        addr->type = SOCKET_ADDRESS_KIND_UNIX;
+        addr->u.q_unix = g_new0(UnixSocketAddress, 1);
+        addr->u.q_unix->path = g_strdup(path);
     } else {
-        addr->kind = SOCKET_ADDRESS_KIND_INET;
-        addr->inet = g_new0(InetSocketAddress, 1);
-        addr->inet->host = g_strdup(host);
-        addr->inet->port = g_strdup(port);
-        addr->inet->has_to = qemu_opt_get(opts, "to");
-        addr->inet->to = qemu_opt_get_number(opts, "to", 0);
-        addr->inet->has_ipv4 = qemu_opt_get(opts, "ipv4");
-        addr->inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0);
-        addr->inet->has_ipv6 = qemu_opt_get(opts, "ipv6");
-        addr->inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0);
+        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr->u.inet = g_new0(InetSocketAddress, 1);
+        addr->u.inet->host = g_strdup(host);
+        addr->u.inet->port = g_strdup(port);
+        addr->u.inet->has_to = qemu_opt_get(opts, "to");
+        addr->u.inet->to = qemu_opt_get_number(opts, "to", 0);
+        addr->u.inet->has_ipv4 = qemu_opt_get(opts, "ipv4");
+        addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0);
+        addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6");
+        addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0);
     }
-    backend->socket->addr = addr;
+    backend->u.socket->addr = addr;
 }

 static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
@@ -3644,27 +3644,27 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
         has_local = true;
     }

-    backend->udp = g_new0(ChardevUdp, 1);
+    backend->u.udp = g_new0(ChardevUdp, 1);

     addr = g_new0(SocketAddress, 1);
-    addr->kind = SOCKET_ADDRESS_KIND_INET;
-    addr->inet = g_new0(InetSocketAddress, 1);
-    addr->inet->host = g_strdup(host);
-    addr->inet->port = g_strdup(port);
-    addr->inet->has_ipv4 = qemu_opt_get(opts, "ipv4");
-    addr->inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0);
-    addr->inet->has_ipv6 = qemu_opt_get(opts, "ipv6");
-    addr->inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0);
-    backend->udp->remote = addr;
+    addr->type = SOCKET_ADDRESS_KIND_INET;
+    addr->u.inet = g_new0(InetSocketAddress, 1);
+    addr->u.inet->host = g_strdup(host);
+    addr->u.inet->port = g_strdup(port);
+    addr->u.inet->has_ipv4 = qemu_opt_get(opts, "ipv4");
+    addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0);
+    addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6");
+    addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0);
+    backend->u.udp->remote = addr;

     if (has_local) {
-        backend->udp->has_local = true;
+        backend->u.udp->has_local = true;
         addr = g_new0(SocketAddress, 1);
-        addr->kind = SOCKET_ADDRESS_KIND_INET;
-        addr->inet = g_new0(InetSocketAddress, 1);
-        addr->inet->host = g_strdup(localaddr);
-        addr->inet->port = g_strdup(localport);
-        backend->udp->local = addr;
+        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr->u.inet = g_new0(InetSocketAddress, 1);
+        addr->u.inet->host = g_strdup(localaddr);
+        addr->u.inet->port = g_strdup(localport);
+        backend->u.udp->local = addr;
     }
 }

@@ -3737,7 +3737,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
     }

     chr = NULL;
-    backend->kind = cd->kind;
+    backend->type = cd->kind;
     if (cd->parse) {
         cd->parse(opts, backend, &local_err);
         if (local_err) {
@@ -3754,9 +3754,9 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         qapi_free_ChardevBackend(backend);
         qapi_free_ChardevReturn(ret);
         backend = g_new0(ChardevBackend, 1);
-        backend->mux = g_new0(ChardevMux, 1);
-        backend->kind = CHARDEV_BACKEND_KIND_MUX;
-        backend->mux->chardev = g_strdup(bid);
+        backend->u.mux = g_new0(ChardevMux, 1);
+        backend->type = CHARDEV_BACKEND_KIND_MUX;
+        backend->u.mux->chardev = g_strdup(bid);
         ret = qmp_chardev_add(id, backend, errp);
         if (!ret) {
             chr = qemu_chr_find(bid);
@@ -4088,7 +4088,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id,
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevFile *file = backend->file;
+    ChardevFile *file = backend->u.file;
     int flags, in = -1, out;

     flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY;
@@ -4115,7 +4115,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id,
                                                 ChardevReturn *ret,
                                                 Error **errp)
 {
-    ChardevHostdev *serial = backend->serial;
+    ChardevHostdev *serial = backend->u.serial;
     int fd;

     fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
@@ -4133,7 +4133,7 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id,
                                                   ChardevReturn *ret,
                                                   Error **errp)
 {
-    ChardevHostdev *parallel = backend->parallel;
+    ChardevHostdev *parallel = backend->u.parallel;
     int fd;

     fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
@@ -4178,7 +4178,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
 {
     CharDriverState *chr;
     TCPCharDriver *s;
-    ChardevSocket *sock = backend->socket;
+    ChardevSocket *sock = backend->u.socket;
     SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
     bool is_listen      = sock->has_server  ? sock->server  : true;
@@ -4191,7 +4191,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,

     s->fd = -1;
     s->listen_fd = -1;
-    s->is_unix = addr->kind == SOCKET_ADDRESS_KIND_UNIX;
+    s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
     s->is_listen = is_listen;
     s->is_telnet = is_telnet;
     s->do_nodelay = do_nodelay;
@@ -4245,7 +4245,7 @@ static CharDriverState *qmp_chardev_open_udp(const char *id,
                                              ChardevReturn *ret,
                                              Error **errp)
 {
-    ChardevUdp *udp = backend->udp;
+    ChardevUdp *udp = backend->u.udp;
     int fd;

     fd = socket_dgram(udp->remote, udp->local, errp);
@@ -4274,7 +4274,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     for (i = backends; i; i = i->next) {
         cd = i->data;

-        if (cd->kind == backend->kind) {
+        if (cd->kind == backend->type) {
             chr = cd->create(id, backend, ret, &local_err);
             if (local_err) {
                 error_propagate(errp, local_err);
@@ -4292,9 +4292,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,

     chr->label = g_strdup(id);
     chr->avail_connections =
-        (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
+        (backend->type == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
     if (!chr->filename) {
-        chr->filename = g_strdup(ChardevBackendKind_lookup[backend->kind]);
+        chr->filename = g_strdup(ChardevBackendKind_lookup[backend->type]);
     }
     if (!chr->explicit_be_open) {
         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index a20fb5c..e70e0f7 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -301,7 +301,7 @@ static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
                                                 ChardevReturn *ret,
                                                 Error **errp)
 {
-    const char *type = backend->spicevmc->type;
+    const char *type = backend->u.spicevmc->type;
     const char **psubtype = spice_server_char_device_recognized_subtypes();

     for (; *psubtype != NULL; ++psubtype) {
@@ -324,7 +324,7 @@ static CharDriverState *qemu_chr_open_spice_port(const char *id,
                                                  ChardevReturn *ret,
                                                  Error **errp)
 {
-    const char *name = backend->spiceport->fqdn;
+    const char *name = backend->u.spiceport->fqdn;
     CharDriverState *chr;
     SpiceCharDriver *s;

@@ -362,8 +362,8 @@ static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: spice channel: no name given");
         return;
     }
-    backend->spicevmc = g_new0(ChardevSpiceChannel, 1);
-    backend->spicevmc->type = g_strdup(name);
+    backend->u.spicevmc = g_new0(ChardevSpiceChannel, 1);
+    backend->u.spicevmc->type = g_strdup(name);
 }

 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
@@ -375,8 +375,8 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
         error_setg(errp, "chardev: spice port: no name given");
         return;
     }
-    backend->spiceport = g_new0(ChardevSpicePort, 1);
-    backend->spiceport->fqdn = g_strdup(name);
+    backend->u.spiceport = g_new0(ChardevSpicePort, 1);
+    backend->u.spiceport->fqdn = g_strdup(name);
 }

 static void register_types(void)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 19/25] input: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (17 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 18/25] char: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 20/25] memory: " Eric Blake
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, Michael S. Tsirkin, Gerd Hoffmann, armbru,
	Luiz Capitulino

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for input-related code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 hmp.c                       |  8 ++---
 hw/char/escc.c              | 12 +++----
 hw/input/hid.c              | 32 ++++++++---------
 hw/input/ps2.c              | 24 ++++++-------
 hw/input/virtio-input-hid.c | 27 ++++++++-------
 ui/console.c                | 20 +++++------
 ui/input-keymap.c           | 20 +++++------
 ui/input-legacy.c           | 21 ++++++------
 ui/input.c                  | 84 ++++++++++++++++++++++-----------------------
 9 files changed, 125 insertions(+), 123 deletions(-)

diff --git a/hmp.c b/hmp.c
index 88fd804..cc4946d 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1735,15 +1735,15 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
             if (*endp != '\0') {
                 goto err_out;
             }
-            keylist->value->kind = KEY_VALUE_KIND_NUMBER;
-            keylist->value->number = value;
+            keylist->value->type = KEY_VALUE_KIND_NUMBER;
+            keylist->value->u.number = value;
         } else {
             int idx = index_from_key(keyname_buf);
             if (idx == Q_KEY_CODE_MAX) {
                 goto err_out;
             }
-            keylist->value->kind = KEY_VALUE_KIND_QCODE;
-            keylist->value->qcode = idx;
+            keylist->value->type = KEY_VALUE_KIND_QCODE;
+            keylist->value->u.qcode = idx;
         }

         if (!separator) {
diff --git a/hw/char/escc.c b/hw/char/escc.c
index ba653ef..c144e95 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -842,13 +842,13 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     ChannelState *s = (ChannelState *)dev;
     int qcode, keycode;

-    assert(evt->kind == INPUT_EVENT_KIND_KEY);
-    qcode = qemu_input_key_value_to_qcode(evt->key->key);
+    assert(evt->type == INPUT_EVENT_KIND_KEY);
+    qcode = qemu_input_key_value_to_qcode(evt->u.key->key);
     trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
-                               evt->key->down);
+                               evt->u.key->down);

     if (qcode == Q_KEY_CODE_CAPS_LOCK) {
-        if (evt->key->down) {
+        if (evt->u.key->down) {
             s->caps_lock_mode ^= 1;
             if (s->caps_lock_mode == 2) {
                 return; /* Drop second press */
@@ -862,7 +862,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     }

     if (qcode == Q_KEY_CODE_NUM_LOCK) {
-        if (evt->key->down) {
+        if (evt->u.key->down) {
             s->num_lock_mode ^= 1;
             if (s->num_lock_mode == 2) {
                 return; /* Drop second press */
@@ -876,7 +876,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
     }

     keycode = qcode_to_keycode[qcode];
-    if (!evt->key->down) {
+    if (!evt->u.key->down) {
         keycode |= 0x80;
     }
     trace_escc_sunkbd_event_out(keycode);
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 21ebd9e..e39269f 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -119,33 +119,33 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
     assert(hs->n < QUEUE_LENGTH);
     e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];

-    switch (evt->kind) {
+    switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        if (evt->rel->axis == INPUT_AXIS_X) {
-            e->xdx += evt->rel->value;
-        } else if (evt->rel->axis == INPUT_AXIS_Y) {
-            e->ydy += evt->rel->value;
+        if (evt->u.rel->axis == INPUT_AXIS_X) {
+            e->xdx += evt->u.rel->value;
+        } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
+            e->ydy += evt->u.rel->value;
         }
         break;

     case INPUT_EVENT_KIND_ABS:
-        if (evt->rel->axis == INPUT_AXIS_X) {
-            e->xdx = evt->rel->value;
-        } else if (evt->rel->axis == INPUT_AXIS_Y) {
-            e->ydy = evt->rel->value;
+        if (evt->u.rel->axis == INPUT_AXIS_X) {
+            e->xdx = evt->u.rel->value;
+        } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
+            e->ydy = evt->u.rel->value;
         }
         break;

     case INPUT_EVENT_KIND_BTN:
-        if (evt->btn->down) {
-            e->buttons_state |= bmap[evt->btn->button];
-            if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
+        if (evt->u.btn->down) {
+            e->buttons_state |= bmap[evt->u.btn->button];
+            if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
                 e->dz--;
-            } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+            } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
                 e->dz++;
             }
         } else {
-            e->buttons_state &= ~bmap[evt->btn->button];
+            e->buttons_state &= ~bmap[evt->u.btn->button];
         }
         break;

@@ -223,8 +223,8 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
     int scancodes[3], i, count;
     int slot;

-    count = qemu_input_key_value_to_scancode(evt->key->key,
-                                             evt->key->down,
+    count = qemu_input_key_value_to_scancode(evt->u.key->key,
+                                             evt->u.key->down,
                                              scancodes);
     if (hs->n + count > QUEUE_LENGTH) {
         fprintf(stderr, "usb-kbd: warning: key event queue full\n");
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index fdbe565..3d6d496 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -183,8 +183,8 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
     int scancodes[3], i, count;

     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-    count = qemu_input_key_value_to_scancode(evt->key->key,
-                                             evt->key->down,
+    count = qemu_input_key_value_to_scancode(evt->u.key->key,
+                                             evt->u.key->down,
                                              scancodes);
     for (i = 0; i < count; i++) {
         ps2_put_keycode(s, scancodes[i]);
@@ -393,25 +393,25 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
         return;

-    switch (evt->kind) {
+    switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        if (evt->rel->axis == INPUT_AXIS_X) {
-            s->mouse_dx += evt->rel->value;
-        } else if (evt->rel->axis == INPUT_AXIS_Y) {
-            s->mouse_dy -= evt->rel->value;
+        if (evt->u.rel->axis == INPUT_AXIS_X) {
+            s->mouse_dx += evt->u.rel->value;
+        } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
+            s->mouse_dy -= evt->u.rel->value;
         }
         break;

     case INPUT_EVENT_KIND_BTN:
-        if (evt->btn->down) {
-            s->mouse_buttons |= bmap[evt->btn->button];
-            if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
+        if (evt->u.btn->down) {
+            s->mouse_buttons |= bmap[evt->u.btn->button];
+            if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
                 s->mouse_dz--;
-            } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+            } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
                 s->mouse_dz++;
             }
         } else {
-            s->mouse_buttons &= ~bmap[evt->btn->button];
+            s->mouse_buttons &= ~bmap[evt->u.btn->button];
         }
         break;

diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 4d85dad..bdd479c 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -191,44 +191,45 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
     virtio_input_event event;
     int qcode;

-    switch (evt->kind) {
+    switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        qcode = qemu_input_key_value_to_qcode(evt->key->key);
+        qcode = qemu_input_key_value_to_qcode(evt->u.key->key);
         if (qcode && keymap_qcode[qcode]) {
             event.type  = cpu_to_le16(EV_KEY);
             event.code  = cpu_to_le16(keymap_qcode[qcode]);
-            event.value = cpu_to_le32(evt->key->down ? 1 : 0);
+            event.value = cpu_to_le32(evt->u.key->down ? 1 : 0);
             virtio_input_send(vinput, &event);
         } else {
-            if (evt->key->down) {
+            if (evt->u.key->down) {
                 fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
                         qcode, QKeyCode_lookup[qcode]);
             }
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        if (keymap_button[evt->btn->button]) {
+        if (keymap_button[evt->u.btn->button]) {
             event.type  = cpu_to_le16(EV_KEY);
-            event.code  = cpu_to_le16(keymap_button[evt->btn->button]);
-            event.value = cpu_to_le32(evt->btn->down ? 1 : 0);
+            event.code  = cpu_to_le16(keymap_button[evt->u.btn->button]);
+            event.value = cpu_to_le32(evt->u.btn->down ? 1 : 0);
             virtio_input_send(vinput, &event);
         } else {
-            if (evt->btn->down) {
+            if (evt->u.btn->down) {
                 fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
-                        evt->btn->button, InputButton_lookup[evt->btn->button]);
+                        evt->u.btn->button,
+                        InputButton_lookup[evt->u.btn->button]);
             }
         }
         break;
     case INPUT_EVENT_KIND_REL:
         event.type  = cpu_to_le16(EV_REL);
-        event.code  = cpu_to_le16(axismap_rel[evt->rel->axis]);
-        event.value = cpu_to_le32(evt->rel->value);
+        event.code  = cpu_to_le16(axismap_rel[evt->u.rel->axis]);
+        event.value = cpu_to_le32(evt->u.rel->value);
         virtio_input_send(vinput, &event);
         break;
     case INPUT_EVENT_KIND_ABS:
         event.type  = cpu_to_le16(EV_ABS);
-        event.code  = cpu_to_le16(axismap_abs[evt->abs->axis]);
-        event.value = cpu_to_le32(evt->abs->value);
+        event.code  = cpu_to_le16(axismap_abs[evt->u.abs->axis]);
+        event.value = cpu_to_le32(evt->u.abs->value);
         virtio_input_send(vinput, &event);
         break;
     default:
diff --git a/ui/console.c b/ui/console.c
index cf649b2..f26544e 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2016,7 +2016,7 @@ static VcHandler *vc_handler = text_console_init;
 static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
                                 ChardevReturn *ret, Error **errp)
 {
-    return vc_handler(backend->vc, errp);
+    return vc_handler(backend->u.vc, errp);
 }

 void register_vc_handler(VcHandler *handler)
@@ -2057,30 +2057,30 @@ static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
 {
     int val;

-    backend->vc = g_new0(ChardevVC, 1);
+    backend->u.vc = g_new0(ChardevVC, 1);

     val = qemu_opt_get_number(opts, "width", 0);
     if (val != 0) {
-        backend->vc->has_width = true;
-        backend->vc->width = val;
+        backend->u.vc->has_width = true;
+        backend->u.vc->width = val;
     }

     val = qemu_opt_get_number(opts, "height", 0);
     if (val != 0) {
-        backend->vc->has_height = true;
-        backend->vc->height = val;
+        backend->u.vc->has_height = true;
+        backend->u.vc->height = val;
     }

     val = qemu_opt_get_number(opts, "cols", 0);
     if (val != 0) {
-        backend->vc->has_cols = true;
-        backend->vc->cols = val;
+        backend->u.vc->has_cols = true;
+        backend->u.vc->cols = val;
     }

     val = qemu_opt_get_number(opts, "rows", 0);
     if (val != 0) {
-        backend->vc->has_rows = true;
-        backend->vc->rows = val;
+        backend->u.vc->has_rows = true;
+        backend->u.vc->rows = val;
     }
 }

diff --git a/ui/input-keymap.c b/ui/input-keymap.c
index 7635cb0..d36be4b 100644
--- a/ui/input-keymap.c
+++ b/ui/input-keymap.c
@@ -139,11 +139,11 @@ static int number_to_qcode[0x100];

 int qemu_input_key_value_to_number(const KeyValue *value)
 {
-    if (value->kind == KEY_VALUE_KIND_QCODE) {
-        return qcode_to_number[value->qcode];
+    if (value->type == KEY_VALUE_KIND_QCODE) {
+        return qcode_to_number[value->u.qcode];
     } else {
-        assert(value->kind == KEY_VALUE_KIND_NUMBER);
-        return value->number;
+        assert(value->type == KEY_VALUE_KIND_NUMBER);
+        return value->u.number;
     }
 }

@@ -166,11 +166,11 @@ int qemu_input_key_number_to_qcode(uint8_t nr)

 int qemu_input_key_value_to_qcode(const KeyValue *value)
 {
-    if (value->kind == KEY_VALUE_KIND_QCODE) {
-        return value->qcode;
+    if (value->type == KEY_VALUE_KIND_QCODE) {
+        return value->u.qcode;
     } else {
-        assert(value->kind == KEY_VALUE_KIND_NUMBER);
-        return qemu_input_key_number_to_qcode(value->number);
+        assert(value->type == KEY_VALUE_KIND_NUMBER);
+        return qemu_input_key_number_to_qcode(value->u.number);
     }
 }

@@ -180,8 +180,8 @@ int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
     int keycode = qemu_input_key_value_to_number(value);
     int count = 0;

-    if (value->kind == KEY_VALUE_KIND_QCODE &&
-        value->qcode == Q_KEY_CODE_PAUSE) {
+    if (value->type == KEY_VALUE_KIND_QCODE &&
+        value->u.qcode == Q_KEY_CODE_PAUSE) {
         /* specific case */
         int v = down ? 0 : 0x80;
         codes[count++] = 0xe1;
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index e50f296..a67ed32 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -113,8 +113,8 @@ static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
     if (!entry || !entry->put_kbd) {
         return;
     }
-    count = qemu_input_key_value_to_scancode(evt->key->key,
-                                             evt->key->down,
+    count = qemu_input_key_value_to_scancode(evt->u.key->key,
+                                             evt->u.key->down,
                                              scancodes);
     for (i = 0; i < count; i++) {
         entry->put_kbd(entry->opaque, scancodes[i]);
@@ -150,21 +150,22 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
     };
     QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;

-    switch (evt->kind) {
+    switch (evt->type) {
     case INPUT_EVENT_KIND_BTN:
-        if (evt->btn->down) {
-            s->buttons |= bmap[evt->btn->button];
+        if (evt->u.btn->down) {
+            s->buttons |= bmap[evt->u.btn->button];
         } else {
-            s->buttons &= ~bmap[evt->btn->button];
+            s->buttons &= ~bmap[evt->u.btn->button];
         }
-        if (evt->btn->down && evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
+        if (evt->u.btn->down && evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
             s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
                                     s->axis[INPUT_AXIS_X],
                                     s->axis[INPUT_AXIS_Y],
                                     -1,
                                     s->buttons);
         }
-        if (evt->btn->down && evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+        if (evt->u.btn->down &&
+            evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
             s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
                                     s->axis[INPUT_AXIS_X],
                                     s->axis[INPUT_AXIS_Y],
@@ -173,10 +174,10 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
         }
         break;
     case INPUT_EVENT_KIND_ABS:
-        s->axis[evt->abs->axis] = evt->abs->value;
+        s->axis[evt->u.abs->axis] = evt->u.abs->value;
         break;
     case INPUT_EVENT_KIND_REL:
-        s->axis[evt->rel->axis] += evt->rel->value;
+        s->axis[evt->u.rel->axis] += evt->u.rel->value;
         break;
     default:
         break;
diff --git a/ui/input.c b/ui/input.c
index 1a552d1..643f885 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -147,10 +147,10 @@ void qmp_x_input_send_event(bool has_console, int64_t console,
     for (e = events; e != NULL; e = e->next) {
         InputEvent *event = e->value;

-        if (!qemu_input_find_handler(1 << event->kind, con)) {
+        if (!qemu_input_find_handler(1 << event->type, con)) {
             error_setg(errp, "Input handler not found for "
                              "event type %s",
-                            InputEventKind_lookup[event->kind]);
+                            InputEventKind_lookup[event->type]);
             return;
         }
     }
@@ -168,22 +168,22 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt)
 {
     switch (graphic_rotate) {
     case 90:
-        if (evt->abs->axis == INPUT_AXIS_X) {
-            evt->abs->axis = INPUT_AXIS_Y;
-        } else if (evt->abs->axis == INPUT_AXIS_Y) {
-            evt->abs->axis = INPUT_AXIS_X;
-            evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
+        if (evt->u.abs->axis == INPUT_AXIS_X) {
+            evt->u.abs->axis = INPUT_AXIS_Y;
+        } else if (evt->u.abs->axis == INPUT_AXIS_Y) {
+            evt->u.abs->axis = INPUT_AXIS_X;
+            evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
         }
         break;
     case 180:
-        evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
+        evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
         break;
     case 270:
-        if (evt->abs->axis == INPUT_AXIS_X) {
-            evt->abs->axis = INPUT_AXIS_Y;
-            evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
-        } else if (evt->abs->axis == INPUT_AXIS_Y) {
-            evt->abs->axis = INPUT_AXIS_X;
+        if (evt->u.abs->axis == INPUT_AXIS_X) {
+            evt->u.abs->axis = INPUT_AXIS_Y;
+            evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
+        } else if (evt->u.abs->axis == INPUT_AXIS_Y) {
+            evt->u.abs->axis = INPUT_AXIS_X;
         }
         break;
     }
@@ -197,18 +197,18 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
     if (src) {
         idx = qemu_console_get_index(src);
     }
-    switch (evt->kind) {
+    switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        switch (evt->key->key->kind) {
+        switch (evt->u.key->key->type) {
         case KEY_VALUE_KIND_NUMBER:
-            qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
+            qcode = qemu_input_key_number_to_qcode(evt->u.key->key->u.number);
             name = QKeyCode_lookup[qcode];
-            trace_input_event_key_number(idx, evt->key->key->number,
-                                         name, evt->key->down);
+            trace_input_event_key_number(idx, evt->u.key->key->u.number,
+                                         name, evt->u.key->down);
             break;
         case KEY_VALUE_KIND_QCODE:
-            name = QKeyCode_lookup[evt->key->key->qcode];
-            trace_input_event_key_qcode(idx, name, evt->key->down);
+            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:
             /* keep gcc happy */
@@ -216,16 +216,16 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        name = InputButton_lookup[evt->btn->button];
-        trace_input_event_btn(idx, name, evt->btn->down);
+        name = InputButton_lookup[evt->u.btn->button];
+        trace_input_event_btn(idx, name, evt->u.btn->down);
         break;
     case INPUT_EVENT_KIND_REL:
-        name = InputAxis_lookup[evt->rel->axis];
-        trace_input_event_rel(idx, name, evt->rel->value);
+        name = InputAxis_lookup[evt->u.rel->axis];
+        trace_input_event_rel(idx, name, evt->u.rel->value);
         break;
     case INPUT_EVENT_KIND_ABS:
-        name = InputAxis_lookup[evt->abs->axis];
-        trace_input_event_abs(idx, name, evt->abs->value);
+        name = InputAxis_lookup[evt->u.abs->axis];
+        trace_input_event_abs(idx, name, evt->u.abs->value);
         break;
     case INPUT_EVENT_KIND_MAX:
         /* keep gcc happy */
@@ -311,12 +311,12 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
     qemu_input_event_trace(src, evt);

     /* pre processing */
-    if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
+    if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) {
             qemu_input_transform_abs_rotate(evt);
     }

     /* send event */
-    s = qemu_input_find_handler(1 << evt->kind, src);
+    s = qemu_input_find_handler(1 << evt->type, src);
     if (!s) {
         return;
     }
@@ -348,10 +348,10 @@ void qemu_input_event_sync(void)
 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
 {
     InputEvent *evt = g_new0(InputEvent, 1);
-    evt->key = g_new0(InputKeyEvent, 1);
-    evt->kind = INPUT_EVENT_KIND_KEY;
-    evt->key->key = key;
-    evt->key->down = down;
+    evt->u.key = g_new0(InputKeyEvent, 1);
+    evt->type = INPUT_EVENT_KIND_KEY;
+    evt->u.key->key = key;
+    evt->u.key->down = down;
     return evt;
 }

@@ -372,16 +372,16 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
 {
     KeyValue *key = g_new0(KeyValue, 1);
-    key->kind = KEY_VALUE_KIND_NUMBER;
-    key->number = num;
+    key->type = KEY_VALUE_KIND_NUMBER;
+    key->u.number = num;
     qemu_input_event_send_key(src, key, down);
 }

 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
 {
     KeyValue *key = g_new0(KeyValue, 1);
-    key->kind = KEY_VALUE_KIND_QCODE;
-    key->qcode = q;
+    key->type = KEY_VALUE_KIND_QCODE;
+    key->u.qcode = q;
     qemu_input_event_send_key(src, key, down);
 }

@@ -398,10 +398,10 @@ void qemu_input_event_send_key_delay(uint32_t delay_ms)
 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
 {
     InputEvent *evt = g_new0(InputEvent, 1);
-    evt->btn = g_new0(InputBtnEvent, 1);
-    evt->kind = INPUT_EVENT_KIND_BTN;
-    evt->btn->button = btn;
-    evt->btn->down = down;
+    evt->u.btn = g_new0(InputBtnEvent, 1);
+    evt->type = INPUT_EVENT_KIND_BTN;
+    evt->u.btn->button = btn;
+    evt->u.btn->down = down;
     return evt;
 }

@@ -451,8 +451,8 @@ InputEvent *qemu_input_event_new_move(InputEventKind kind,
     InputEvent *evt = g_new0(InputEvent, 1);
     InputMoveEvent *move = g_new0(InputMoveEvent, 1);

-    evt->kind = kind;
-    evt->data = move;
+    evt->type = kind;
+    evt->u.data = move;
     move->axis = axis;
     move->value = value;
     return evt;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 20/25] memory: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (18 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 19/25] input: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 21/25] tpm: " Eric Blake
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Igor Mammedov, Michael S. Tsirkin, armbru, Eduardo Habkost,
	Luiz Capitulino

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for memory-related code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 hmp.c            | 6 +++---
 hw/mem/pc-dimm.c | 6 +++---
 numa.c           | 8 ++++----
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/hmp.c b/hmp.c
index cc4946d..39d5815 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1958,12 +1958,12 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
         value = info->value;

         if (value) {
-            switch (value->kind) {
+            switch (value->type) {
             case MEMORY_DEVICE_INFO_KIND_DIMM:
-                di = value->dimm;
+                di = value->u.dimm;

                 monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
-                               MemoryDeviceInfoKind_lookup[value->kind],
+                               MemoryDeviceInfoKind_lookup[value->type],
                                di->id ? di->id : "");
                 monitor_printf(mon, "  addr: 0x%" PRIx64 "\n", di->addr);
                 monitor_printf(mon, "  slot: %" PRId64 "\n", di->slot);
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 2bae994..fd84a90 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -180,7 +180,7 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque)
                                                NULL);
             di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));

-            info->dimm = di;
+            info->u.dimm = di;
             elem->value = info;
             elem->next = NULL;
             **prev = elem;
@@ -204,9 +204,9 @@ ram_addr_t get_current_ram_size(void)
         MemoryDeviceInfo *value = info->value;

         if (value) {
-            switch (value->kind) {
+            switch (value->type) {
             case MEMORY_DEVICE_INFO_KIND_DIMM:
-                size += value->dimm->size;
+                size += value->u.dimm->size;
                 break;
             default:
                 break;
diff --git a/numa.c b/numa.c
index e9b18f5..fdfe294 100644
--- a/numa.c
+++ b/numa.c
@@ -226,9 +226,9 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
         goto error;
     }

-    switch (object->kind) {
+    switch (object->type) {
     case NUMA_OPTIONS_KIND_NODE:
-        numa_node_parse(object->node, opts, &err);
+        numa_node_parse(object->u.node, opts, &err);
         if (err) {
             goto error;
         }
@@ -487,9 +487,9 @@ static void numa_stat_memory_devices(uint64_t node_mem[])
         MemoryDeviceInfo *value = info->value;

         if (value) {
-            switch (value->kind) {
+            switch (value->type) {
             case MEMORY_DEVICE_INFO_KIND_DIMM:
-                node_mem[value->dimm->node] += value->dimm->size;
+                node_mem[value->u.dimm->node] += value->u.dimm->size;
                 break;
             default:
                 break;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 21/25] tpm: Convert to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (19 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 20/25] memory: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 22/25] qapi: Finish converting " Eric Blake
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Luiz Capitulino

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

Make the conversion to the new layout for TPM-related code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 hmp.c | 6 +++---
 tpm.c | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/hmp.c b/hmp.c
index 39d5815..a15d00c 100644
--- a/hmp.c
+++ b/hmp.c
@@ -841,11 +841,11 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
                        c, TpmModel_lookup[ti->model]);

         monitor_printf(mon, "  \\ %s: type=%s",
-                       ti->id, TpmTypeOptionsKind_lookup[ti->options->kind]);
+                       ti->id, TpmTypeOptionsKind_lookup[ti->options->type]);

-        switch (ti->options->kind) {
+        switch (ti->options->type) {
         case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH:
-            tpo = ti->options->passthrough;
+            tpo = ti->options->u.passthrough;
             monitor_printf(mon, "%s%s%s%s",
                            tpo->has_path ? ",path=" : "",
                            tpo->has_path ? tpo->path : "",
diff --git a/tpm.c b/tpm.c
index 4e9b109..f2c59d1 100644
--- a/tpm.c
+++ b/tpm.c
@@ -260,9 +260,9 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)

     switch (drv->ops->type) {
     case TPM_TYPE_PASSTHROUGH:
-        res->options->kind = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
+        res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
         tpo = g_new0(TPMPassthroughOptions, 1);
-        res->options->passthrough = tpo;
+        res->options->u.passthrough = tpo;
         if (drv->path) {
             tpo->path = g_strdup(drv->path);
             tpo->has_path = true;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 22/25] qapi: Finish converting to new qapi union layout
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (20 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 21/25] tpm: " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-27  8:33   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 23/25] qapi: Reserve 'u' member name Eric Blake
                   ` (3 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

We have two issues with our qapi union layout:
1) Even though the QMP wire format spells the tag 'type', the
C code spells it 'kind', requiring some hacks in the generator.
2) The C struct uses an anonymous union, which places all tag
values in the same namespace as all non-variant members. This
leads to spurious collisions if a tag value matches a QMP name.

This patch is the back end for a series that converts to a
saner qapi union layout.  Now that all clients have been
converted to use 'type' and 'obj->u.value', we can drop the
temporary parallel support for 'kind' and 'obj->value'.

Given a simple union qapi type:

{ 'union':'Foo', 'data': { 'a':'int', 'b':'bool' } }

this is the overall effect, when compared to the state before
this series of patches:

| struct Foo {
|-    FooKind kind;
|-    union { /* union tag is @kind */
|+    FooKind type;
|+    union { /* union tag is @type */
|         void *data;
|         int64_t a;
|         bool b;
|-    };
|+    } u;
| };

Note, however, that we do not rename the generated enum, which
is still 'FooKind'.  A further patch could generate implicit
enums as 'FooType', but while the generator already reserved
the '*Kind' namespace (commit 4dc2e69), there are already QMP
constructs with '*Type' naming, which means changing our
reservation namespace would have lots of churn to C code to
deal with a forced name change.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: rebase to earlier changes, match commit wording
v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
---
 scripts/qapi-types.py | 26 +++++---------------------
 1 file changed, 5 insertions(+), 21 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 579532d..d131430 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -148,23 +148,10 @@ struct %(c_name)s {
     if base:
         ret += gen_struct_fields([], base)
     else:
-        # TODO As a hack, we emit both 'kind' and 'type'. Ultimately, we
-        # want to use only 'type', but the conversion is large enough to
-        # require staging over several commits.
-        ret += mcgen('''
-    union {
-        %(c_type)s kind;
-        %(c_type)s type;
-    };
-''',
-                     c_type=c_name(variants.tag_member.type.name))
+        ret += gen_struct_field(variants.tag_member.name,
+                                variants.tag_member.type,
+                                False)

-    # TODO As a hack, we emit the union twice, once as an anonymous union
-    # and once as a named union.  Ultimately, we want to use only the
-    # named union version (as it avoids conflicts between tag values as
-    # branch names competing with non-variant QMP names), but the conversion
-    # is large enough to require staging over several commits.
-    tmp = ''
     # 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
@@ -173,7 +160,7 @@ 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?
-    tmp += mcgen('''
+    ret += mcgen('''
     union { /* union tag is @%(c_name)s */
         void *data;
 ''',
@@ -182,17 +169,14 @@ struct %(c_name)s {
     for var in variants.variants:
         # Ugly special case for simple union TODO get rid of it
         typ = var.simple_union_type() or var.type
-        tmp += mcgen('''
+        ret += mcgen('''
         %(c_type)s %(c_name)s;
 ''',
                      c_type=typ.c_type(),
                      c_name=c_name(var.name))

-    ret += tmp
-    ret += '    ' + '\n    '.join(tmp.split('\n'))
     ret += mcgen('''
     } u;
-    };
 };
 ''')

-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 23/25] qapi: Reserve 'u' member name
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (21 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 22/25] qapi: Finish converting " Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-26 17:27   ` Markus Armbruster
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 24/25] qapi: Remove outdated tests related to QMP/branch collisions Eric Blake
                   ` (2 subsequent siblings)
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Now that we have separated union tag values from colliding with
non-variant C names, by naming the union 'u', we should reserve
this name for our use.  Note that we want to forbid 'u' even in
a struct with no variants, because it is possible for a future
qemu release to extend QMP in a backwards-compatible manner while
converting from a struct to a flat union.  Fortunately, no
existing clients were using this member name.  If we ever find
the need for QMP to have a member 'u', we could at that time
relax things, perhaps by having c_name() munge the QMP member to
'q_u'.

Note that we cannot forbid 'u' everywhere (by adding the
rejection code to check_name()), because the existing QKeyCode
enum already uses it.  And it is still okay to use it as a
branch name within a union, although not worth adding a
positive test to qapi-schema-test for this corner case.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch, split from 1/17 and 3/17; by deferring this until
after the rename was complete, it reduces churn due to the new feature
---
 scripts/qapi.py                        | 2 +-
 tests/Makefile                         | 1 +
 tests/qapi-schema/struct-member-u.err  | 1 +
 tests/qapi-schema/struct-member-u.exit | 1 +
 tests/qapi-schema/struct-member-u.json | 7 +++++++
 tests/qapi-schema/struct-member-u.out  | 0
 6 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 tests/qapi-schema/struct-member-u.err
 create mode 100644 tests/qapi-schema/struct-member-u.exit
 create mode 100644 tests/qapi-schema/struct-member-u.json
 create mode 100644 tests/qapi-schema/struct-member-u.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8b9f5f7..b941ccf 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -490,7 +490,7 @@ def check_type(expr_info, source, value, allow_array=False,
     for (key, arg) in value.items():
         check_name(expr_info, "Member of %s" % source, key,
                    allow_optional=allow_optional)
-        if c_name(key).startswith('has_'):
+        if key == 'u' or c_name(key).startswith('has_'):
             raise QAPIExprError(expr_info,
                                 "Member of %s uses reserved name '%s'"
                                 % (source, key))
diff --git a/tests/Makefile b/tests/Makefile
index 9194264..8c239f8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -326,6 +326,7 @@ qapi-schema += struct-base-clash-deep.json
 qapi-schema += struct-base-clash.json
 qapi-schema += struct-data-invalid.json
 qapi-schema += struct-member-invalid.json
+qapi-schema += struct-member-u.json
 qapi-schema += struct-name-list.json
 qapi-schema += trailing-comma-list.json
 qapi-schema += trailing-comma-object.json
diff --git a/tests/qapi-schema/struct-member-u.err b/tests/qapi-schema/struct-member-u.err
new file mode 100644
index 0000000..0dc354c
--- /dev/null
+++ b/tests/qapi-schema/struct-member-u.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u'
diff --git a/tests/qapi-schema/struct-member-u.exit b/tests/qapi-schema/struct-member-u.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/struct-member-u.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/struct-member-u.json b/tests/qapi-schema/struct-member-u.json
new file mode 100644
index 0000000..1eaf0f3
--- /dev/null
+++ b/tests/qapi-schema/struct-member-u.json
@@ -0,0 +1,7 @@
+# Potential C member name collision
+# We reject use of 'u' as a member name, to allow it for internal use in
+# putting union branch members in a separate namespace from QMP members.
+# This is true even for non-unions, because it is possible to convert a
+# struct to flat union while remaining backwards compatible in QMP.
+# TODO - we could munge the member name to 'q_u' to avoid the collision
+{ 'struct': 'Oops', 'data': { 'u': 'str' } }
diff --git a/tests/qapi-schema/struct-member-u.out b/tests/qapi-schema/struct-member-u.out
new file mode 100644
index 0000000..e69de29
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v10 24/25] qapi: Remove outdated tests related to QMP/branch collisions
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (22 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 23/25] qapi: Reserve 'u' member name Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-23 23:27   ` Eric Blake
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 25/25] qapi: Simplify gen_struct_field() Eric Blake
  2015-10-26 17:55 ` [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Markus Armbruster
  25 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

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.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: new patch
---
 scripts/qapi.py                                |  7 +------
 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, 1 insertion(+), 69 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 b941ccf..3a5dbac 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -548,7 +548,7 @@ def check_union(expr, expr_info):
     base = expr.get('base')
     discriminator = expr.get('discriminator')
     members = expr['data']
-    values = {'MAX': '(automatic)', 'TYPE': '(automatic tag)'}
+    values = {'MAX': '(automatic)'}

     # Two types of unions, determined by discriminator.

@@ -614,11 +614,6 @@ def check_union(expr, 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 8c239f8..70524df 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -277,9 +277,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
@@ -339,7 +337,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 eca7c1d..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 'type' clashes with '(automatic tag)'
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] 58+ messages in thread

* [Qemu-devel] [PATCH v10 25/25] qapi: Simplify gen_struct_field()
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (23 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 24/25] qapi: Remove outdated tests related to QMP/branch collisions Eric Blake
@ 2015-10-23  5:09 ` Eric Blake
  2015-10-26 17:55 ` [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Markus Armbruster
  25 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23  5:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Rather than having all callers pass a name, type, and optional
flag, have them instead pass a QAPISchemaObjectTypeMember which
already has all that information.

No change to generated code.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v10: no change
v9: rebase after kind/base cleanups, don't rely on member.c_name()
v8: new patch
---
 scripts/qapi-types.py | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index d131430..f8fc272 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -36,18 +36,18 @@ struct %(c_name)s {
                  c_name=c_name(name), c_type=element_type.c_type())


-def gen_struct_field(name, typ, optional):
+def gen_struct_field(member):
     ret = ''

-    if optional:
+    if member.optional:
         ret += mcgen('''
     bool has_%(c_name)s;
 ''',
-                     c_name=c_name(name))
+                     c_name=c_name(member.name))
     ret += mcgen('''
     %(c_type)s %(c_name)s;
 ''',
-                 c_type=typ.c_type(), c_name=c_name(name))
+                 c_type=member.type.c_type(), c_name=c_name(member.name))
     return ret


@@ -65,7 +65,7 @@ def gen_struct_fields(members, base=None):
 ''')

     for memb in members:
-        ret += gen_struct_field(memb.name, memb.type, memb.optional)
+        ret += gen_struct_field(memb)
     return ret


@@ -148,9 +148,7 @@ struct %(c_name)s {
     if base:
         ret += gen_struct_fields([], base)
     else:
-        ret += gen_struct_field(variants.tag_member.name,
-                                variants.tag_member.type,
-                                False)
+        ret += gen_struct_field(variants.tag_member)

     # 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
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct Eric Blake
@ 2015-10-23 12:33   ` Markus Armbruster
  2015-10-23 12:39     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 12:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> We are failing to detect a collision between a QMP member and
> the implicit 'has_*' flag for another optional QMP member. The
> easiest fix would be for a future patch to reserve the entire
> "has[-_]" namespace for member names (the collision is also
> possible for branch names within flat unions, but only as long
> as branch names can collide with QMP names; since future
> patches are about to remove that, it is not worth testing here).

This is args-has-clash.json.

> A similar collision exists between a QMP member where c_name()
> munges what might otherwise be a reserved name to start with
> 'q_', and another member explicitly starts with "q[-_]".  Again,
> the easiest task for a future patch will be reserving the entire

s/task/solution/ ?

> namespace, but here for commands as well as members.

This is reserved-member.json.

> Our current representation of qapi arrays is done by appending
> 'List' to the element name; but we are not preventing the
> creation of a non-array type with the same name.

This is struct-name-list.json.

> Finally, our testsuite does not have any compilation coverage
> of struct inheritance with empty qapi structs.

This is qapi-schema-test.json.

Left undescribed: reserved-commands.json :)

> Add tests to cover these issues.
>
> On the other hand, there is currently no technical reason to
> forbid type name patterns from member names, or member name
> patterns from types, since the two are not in the same namespace
> in C and won't collide (but it's not worth adding positive tests
> of these corner cases, especially while there is other churn
> pending in patches that rearrange which collisions actually
> happen).
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: retitle, split off 'u' collisions and positive tests for
> later, add 'q_' collisions and empty struct inheritance, improve
> commit message, rename args-name-has to args-has-clash
> v9: new patch
> ---
>  tests/Makefile                          | 4 ++++
>  tests/qapi-schema/args-has-clash.err    | 0
>  tests/qapi-schema/args-has-clash.exit   | 1 +
>  tests/qapi-schema/args-has-clash.json   | 6 ++++++
>  tests/qapi-schema/args-has-clash.out    | 6 ++++++
>  tests/qapi-schema/qapi-schema-test.json | 4 ++++
>  tests/qapi-schema/qapi-schema-test.out  | 3 +++
>  tests/qapi-schema/reserved-command.err  | 0
>  tests/qapi-schema/reserved-command.exit | 1 +
>  tests/qapi-schema/reserved-command.json | 7 +++++++
>  tests/qapi-schema/reserved-command.out  | 5 +++++
>  tests/qapi-schema/reserved-member.err   | 0
>  tests/qapi-schema/reserved-member.exit  | 1 +
>  tests/qapi-schema/reserved-member.json  | 6 ++++++
>  tests/qapi-schema/reserved-member.out   | 4 ++++
>  tests/qapi-schema/struct-name-list.err  | 0
>  tests/qapi-schema/struct-name-list.exit | 1 +
>  tests/qapi-schema/struct-name-list.json | 5 +++++
>  tests/qapi-schema/struct-name-list.out  | 3 +++
>  19 files changed, 57 insertions(+)
>  create mode 100644 tests/qapi-schema/args-has-clash.err
>  create mode 100644 tests/qapi-schema/args-has-clash.exit
>  create mode 100644 tests/qapi-schema/args-has-clash.json
>  create mode 100644 tests/qapi-schema/args-has-clash.out
>  create mode 100644 tests/qapi-schema/reserved-command.err
>  create mode 100644 tests/qapi-schema/reserved-command.exit
>  create mode 100644 tests/qapi-schema/reserved-command.json
>  create mode 100644 tests/qapi-schema/reserved-command.out
>  create mode 100644 tests/qapi-schema/reserved-member.err
>  create mode 100644 tests/qapi-schema/reserved-member.exit
>  create mode 100644 tests/qapi-schema/reserved-member.json
>  create mode 100644 tests/qapi-schema/reserved-member.out
>  create mode 100644 tests/qapi-schema/struct-name-list.err
>  create mode 100644 tests/qapi-schema/struct-name-list.exit
>  create mode 100644 tests/qapi-schema/struct-name-list.json
>  create mode 100644 tests/qapi-schema/struct-name-list.out
>
> diff --git a/tests/Makefile b/tests/Makefile
> index 0531b30..cc6b24f 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -237,6 +237,7 @@ qapi-schema += args-alternate.json
>  qapi-schema += args-any.json
>  qapi-schema += args-array-empty.json
>  qapi-schema += args-array-unknown.json
> +qapi-schema += args-has-clash.json
>  qapi-schema += args-int.json
>  qapi-schema += args-invalid.json
>  qapi-schema += args-member-array-bad.json
> @@ -314,6 +315,8 @@ qapi-schema += redefined-builtin.json
>  qapi-schema += redefined-command.json
>  qapi-schema += redefined-event.json
>  qapi-schema += redefined-type.json
> +qapi-schema += reserved-command.json
> +qapi-schema += reserved-member.json
>  qapi-schema += returns-alternate.json
>  qapi-schema += returns-array-bad.json
>  qapi-schema += returns-dict.json
> @@ -324,6 +327,7 @@ qapi-schema += struct-base-clash-deep.json
>  qapi-schema += struct-base-clash.json
>  qapi-schema += struct-data-invalid.json
>  qapi-schema += struct-member-invalid.json
> +qapi-schema += struct-name-list.json
>  qapi-schema += trailing-comma-list.json
>  qapi-schema += trailing-comma-object.json
>  qapi-schema += type-bypass-bad-gen.json
> diff --git a/tests/qapi-schema/args-has-clash.err b/tests/qapi-schema/args-has-clash.err
> new file mode 100644
> index 0000000..e69de29
> diff --git a/tests/qapi-schema/args-has-clash.exit b/tests/qapi-schema/args-has-clash.exit
> new file mode 100644
> index 0000000..573541a
> --- /dev/null
> +++ b/tests/qapi-schema/args-has-clash.exit
> @@ -0,0 +1 @@
> +0
> diff --git a/tests/qapi-schema/args-has-clash.json b/tests/qapi-schema/args-has-clash.json
> new file mode 100644
> index 0000000..a2197de
> --- /dev/null
> +++ b/tests/qapi-schema/args-has-clash.json
> @@ -0,0 +1,6 @@
> +# C member name collision
> +# FIXME - This parses, but fails to compile, because the C struct is given
> +# two 'has_a' members, one from the flag for optional 'a', and the other
> +# from member 'has-a'.  Either reject this at parse time, or munge the C
> +# names to avoid the collision.
> +{ 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
> diff --git a/tests/qapi-schema/args-has-clash.out b/tests/qapi-schema/args-has-clash.out
> new file mode 100644
> index 0000000..5a18b6b
> --- /dev/null
> +++ b/tests/qapi-schema/args-has-clash.out
> @@ -0,0 +1,6 @@
> +object :empty
> +object :obj-oops-arg
> +    member a: str optional=True
> +    member has-a: str optional=False
> +command oops :obj-oops-arg -> None
> +   gen=True success_response=True
> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
> index 4e2d7c2..48e104b 100644
> --- a/tests/qapi-schema/qapi-schema-test.json
> +++ b/tests/qapi-schema/qapi-schema-test.json
> @@ -11,6 +11,10 @@
>  # An empty enum, although unusual, is currently acceptable
>  { 'enum': 'MyEnum', 'data': [ ] }
>
> +# Likewise for an empty struct, including an empty base
> +{ 'struct': 'Empty1', 'data': { } }
> +{ 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
> +
>  # for testing override of default naming heuristic
>  { 'enum': 'QEnumTwo',
>    'prefix': 'QENUM_TWO',
> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index a6c80e0..a7e9aab 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -81,6 +81,9 @@ event EVENT_A None
>  event EVENT_B None
>  event EVENT_C :obj-EVENT_C-arg
>  event EVENT_D :obj-EVENT_D-arg
> +object Empty1
> +object Empty2
> +    base Empty1
>  enum EnumOne ['value1', 'value2', 'value3']
>  object EventStructOne
>      member struct1: UserDefOne optional=False
> diff --git a/tests/qapi-schema/reserved-command.err b/tests/qapi-schema/reserved-command.err
> new file mode 100644
> index 0000000..e69de29
> diff --git a/tests/qapi-schema/reserved-command.exit b/tests/qapi-schema/reserved-command.exit
> new file mode 100644
> index 0000000..573541a
> --- /dev/null
> +++ b/tests/qapi-schema/reserved-command.exit
> @@ -0,0 +1 @@
> +0
> diff --git a/tests/qapi-schema/reserved-command.json b/tests/qapi-schema/reserved-command.json
> new file mode 100644
> index 0000000..be9944c
> --- /dev/null
> +++ b/tests/qapi-schema/reserved-command.json
> @@ -0,0 +1,7 @@
> +# C entity name collision
> +# FIXME - This parses, but fails to compile, because it attempts to declare
> +# two 'qmp_q_unix' functions (one for 'q-unix', the other because c_name()
> +# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
> +# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
> +{ 'command': 'unix' }
> +{ 'command': 'q-unix' }

Note that mangling 'unix' to 'q-unix' is pretty pointless for command
names, because their C name occurs only in identifiers qmp_CNAME() and
qmp_marshal_CNAME().

> diff --git a/tests/qapi-schema/reserved-command.out b/tests/qapi-schema/reserved-command.out
> new file mode 100644
> index 0000000..b31b38f
> --- /dev/null
> +++ b/tests/qapi-schema/reserved-command.out
> @@ -0,0 +1,5 @@
> +object :empty
> +command q-unix None -> None
> +   gen=True success_response=True
> +command unix None -> None
> +   gen=True success_response=True
> diff --git a/tests/qapi-schema/reserved-member.err b/tests/qapi-schema/reserved-member.err
> new file mode 100644
> index 0000000..e69de29
> diff --git a/tests/qapi-schema/reserved-member.exit b/tests/qapi-schema/reserved-member.exit
> new file mode 100644
> index 0000000..573541a
> --- /dev/null
> +++ b/tests/qapi-schema/reserved-member.exit
> @@ -0,0 +1 @@
> +0
> diff --git a/tests/qapi-schema/reserved-member.json b/tests/qapi-schema/reserved-member.json
> new file mode 100644
> index 0000000..1602ed3
> --- /dev/null
> +++ b/tests/qapi-schema/reserved-member.json
> @@ -0,0 +1,6 @@
> +# C member name collision
> +# FIXME - This parses, but fails to compile, because it attempts to declare
> +# two 'q_unix' members (one for 'q-unix', the other because c_name()
> +# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
> +# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
> +{ 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }

Unlike command names, member names actually occur by themselves, so some
name mangling is required.

A less ham-fisted approach would mangle *complete* identifiers, i.e.
c_name('qmp_' + name) instead of 'qmp_' + c_name(name).

Please feel free to stick to ham-fisted for now.  We need to make
progress flushing the queue.

> diff --git a/tests/qapi-schema/reserved-member.out b/tests/qapi-schema/reserved-member.out
> new file mode 100644
> index 0000000..0d8685a
> --- /dev/null
> +++ b/tests/qapi-schema/reserved-member.out
> @@ -0,0 +1,4 @@
> +object :empty
> +object Foo
> +    member unix: int optional=False
> +    member q-unix: bool optional=False
> diff --git a/tests/qapi-schema/struct-name-list.err b/tests/qapi-schema/struct-name-list.err
> new file mode 100644
> index 0000000..e69de29
> diff --git a/tests/qapi-schema/struct-name-list.exit b/tests/qapi-schema/struct-name-list.exit
> new file mode 100644
> index 0000000..573541a
> --- /dev/null
> +++ b/tests/qapi-schema/struct-name-list.exit
> @@ -0,0 +1 @@
> +0
> diff --git a/tests/qapi-schema/struct-name-list.json b/tests/qapi-schema/struct-name-list.json
> new file mode 100644
> index 0000000..8ad38e6
> --- /dev/null
> +++ b/tests/qapi-schema/struct-name-list.json
> @@ -0,0 +1,5 @@
> +# Potential C name collision
> +# FIXME - This parses and compiles on its own, but prevents the user from
> +# creating a type named 'Foo' and using ['Foo'] for an array.  We should
> +# reject the use of any non-array type names ending in 'List'.
> +{ 'struct': 'FooList', 'data': { 's': 'str' } }

"Non-array type name" makes no sense when talking about the QAPI schema,
because arrays don't have names there.

> diff --git a/tests/qapi-schema/struct-name-list.out b/tests/qapi-schema/struct-name-list.out
> new file mode 100644
> index 0000000..0406bfe
> --- /dev/null
> +++ b/tests/qapi-schema/struct-name-list.out
> @@ -0,0 +1,3 @@
> +object :empty
> +object FooList
> +    member s: str optional=False

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct
  2015-10-23 12:33   ` Markus Armbruster
@ 2015-10-23 12:39     ` Eric Blake
  2015-10-23 14:17       ` Markus Armbruster
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23 12:39 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 4644 bytes --]

On 10/23/2015 06:33 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> We are failing to detect a collision between a QMP member and
>> the implicit 'has_*' flag for another optional QMP member. The
>> easiest fix would be for a future patch to reserve the entire
>> "has[-_]" namespace for member names (the collision is also
>> possible for branch names within flat unions, but only as long
>> as branch names can collide with QMP names; since future
>> patches are about to remove that, it is not worth testing here).
> 
> This is args-has-clash.json.
> 
>> A similar collision exists between a QMP member where c_name()
>> munges what might otherwise be a reserved name to start with
>> 'q_', and another member explicitly starts with "q[-_]".  Again,
>> the easiest task for a future patch will be reserving the entire
> 
> s/task/solution/ ?
> 

Sounds better.

>> namespace, but here for commands as well as members.
> 
> This is reserved-member.json.

And reserve-commands.json

> 
>> Our current representation of qapi arrays is done by appending
>> 'List' to the element name; but we are not preventing the
>> creation of a non-array type with the same name.
> 
> This is struct-name-list.json.
> 
>> Finally, our testsuite does not have any compilation coverage
>> of struct inheritance with empty qapi structs.
> 
> This is qapi-schema-test.json.
> 
> Left undescribed: reserved-commands.json :)

No, the 'q_' paragraph covered both.  But yes, mentioning the actual
test names in the commit body can't hurt.

> 
>> Add tests to cover these issues.
>>
>> On the other hand, there is currently no technical reason to
>> forbid type name patterns from member names, or member name
>> patterns from types, since the two are not in the same namespace
>> in C and won't collide (but it's not worth adding positive tests
>> of these corner cases, especially while there is other churn
>> pending in patches that rearrange which collisions actually
>> happen).
>>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
>>
>> ---

>> +++ b/tests/qapi-schema/reserved-command.json
>> @@ -0,0 +1,7 @@
>> +# C entity name collision
>> +# FIXME - This parses, but fails to compile, because it attempts to declare
>> +# two 'qmp_q_unix' functions (one for 'q-unix', the other because c_name()
>> +# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
>> +# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
>> +{ 'command': 'unix' }
>> +{ 'command': 'q-unix' }
> 
> Note that mangling 'unix' to 'q-unix' is pretty pointless for command
> names, because their C name occurs only in identifiers qmp_CNAME() and
> qmp_marshal_CNAME().
> 

Probably true, but it is the current implementation, and we DO have a
compile time collision until (unless?) we bother to fix it.

>> +++ b/tests/qapi-schema/reserved-member.json
>> @@ -0,0 +1,6 @@
>> +# C member name collision
>> +# FIXME - This parses, but fails to compile, because it attempts to declare
>> +# two 'q_unix' members (one for 'q-unix', the other because c_name()
>> +# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
>> +# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
>> +{ 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }
> 
> Unlike command names, member names actually occur by themselves, so some
> name mangling is required.
> 
> A less ham-fisted approach would mangle *complete* identifiers, i.e.
> c_name('qmp_' + name) instead of 'qmp_' + c_name(name).
> 
> Please feel free to stick to ham-fisted for now.  We need to make
> progress flushing the queue.

Indeed - cleaning up command name mangling can come at a later date, and
maybe at that point we can decide 'q_' reservations for command names
doesn't add any power, and relax it at that point.

>> +++ b/tests/qapi-schema/struct-name-list.json
>> @@ -0,0 +1,5 @@
>> +# Potential C name collision
>> +# FIXME - This parses and compiles on its own, but prevents the user from
>> +# creating a type named 'Foo' and using ['Foo'] for an array.  We should
>> +# reject the use of any non-array type names ending in 'List'.
>> +{ 'struct': 'FooList', 'data': { 's': 'str' } }
> 
> "Non-array type name" makes no sense when talking about the QAPI schema,
> because arrays don't have names there.

Suggestions? Maybe s/non-array//? The wording changes in 2/25 when the
test starts working.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 03/25] qapi: More robust conditions for when labels are needed
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 03/25] qapi: More robust conditions for when labels are needed Eric Blake
@ 2015-10-23 12:44   ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 12:44 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> We were using regular expressions to see if ret included
> any earlier text that emitted a 'goto out;' line, to decide
> whether we needed to output an 'out:' label.  But this is
> fragile, if the ret text can possibly combine more than one
> generated function body, where the first function used a
> goto but the second does not.  Change the code to just check
> for the known conditions which cause an error check to be
> needed.  Besides, it's slightly more efficient to use plain
> checks than regular expression searching.
>
> No change to generated code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: new patch, split in part from 6/17
> ---
>  scripts/qapi-commands.py | 2 +-
>  scripts/qapi-visit.py    | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
> index 43a893b..d6a4bf4 100644
> --- a/scripts/qapi-commands.py
> +++ b/scripts/qapi-commands.py
> @@ -175,7 +175,7 @@ def gen_marshal(name, arg_type, ret_type):
>      ret += gen_marshal_input_visit(arg_type)
>      ret += gen_call(name, arg_type, ret_type)
>
> -    if re.search('^ *goto out;', ret, re.MULTILINE):
> +    if (arg_type and arg_type.members) or ret_type:
>          ret += mcgen('''
>
>  out:

I think this could use a comment pointing to the spot that generates the
goto out.  I believe it's exactly gen_err_check() in gen_visit_fields().

Now let me convince myself your condition works.  We call
gen_visit_fields() when arg_type, and gen_visit_fields() calls
gen_err_check() for each memb in arg_type.members.  Good.

> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index d0759d7..e878018 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -87,7 +87,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **e
>
>      ret += gen_visit_fields(members, prefix='(*obj)->')
>
> -    if re.search('^ *goto out;', ret, re.MULTILINE):
> +    if base or members:
>          ret += mcgen('''
>
>  out:

Again, could use a comment.  I believe it's gen_err_check() here, and in
gen_visit_fields().

Now let me convince myself your condition works.  We call
gen_err_check() when base, and gen_visit_fields() unconditionally, which
in turn calls gen_err_check() for each memb in members.  Good.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 04/25] qapi: Reserve '*List' type names for list types
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 04/25] qapi: Reserve '*List' type names for list types Eric Blake
@ 2015-10-23 12:53   ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 12:53 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> Type names ending in 'List' can clash with qapi list types in
> generated C.  We don't currently use such names. It is easier to
> outlaw them now than to worry about how to resolve such a clash
> in the future. For precedence, see commit 4dc2e69, which did the
> same for names ending in 'Kind' versus implicit enum types for
> qapi unions.
>
> Note that this only forbids explicit creation of new (non-array)
> types or commands ending in 'List'; the parser already rejects
> attempts to use ['intList'] as the type for an object member
> (although 'intList' happens to be the C spelling for the qapi
> type ['int'], that does not make it a recognized name in qapi).
> Whether we later turn on support for multi-dimensional arrays
> (via [['int']], not ['intList']) is a design decision best left
> for another day.

I'd drop this paragraph, because I find it distracting.  Its first
sentence boils down to "we reject type names you didn't declare", but it
takes some mental effort to figure that out.  The second sentence talks
about a design detail of a possible future extension.  Neither is
necessary to understand this commit.

> Update the testsuite to match.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>

Patch looks good.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names Eric Blake
@ 2015-10-23 13:05   ` Markus Armbruster
  2015-10-23 14:14     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 13:05 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> c_name() produces names starting with 'q_' when protecting
> a QMP member name that would fail to directly compile, but
> in doing so can cause clashes with any QMP name already
> beginning with 'q-' or 'q_'.  Likewise, we create a C name
> 'has_' for any optional member, that can clash with any QMP
> name beginning with 'has-' or 'has_'.
>
> Technically, rather than blindly reserving the namespace,
> we could try to complain about user names only when an actual
> collision occurs, or even teach c_name() how to munge names
> to avoid collisions.  But it is not trivial, especially when
> collisions can occur across multiple types (such as via
> inheritance or flat unions).  Besides, no existing .json
> files are trying to use these names.  So it's easier to just
> outright forbid the potential for collision.  We can always
> relax things in the future if a real need arises for QMP to
> express member names that have been forbidden here.
>
> 'has_' only has to be reserved for struct/union member names,
> while 'q_' is reserved everywhere (matching the fact that
> we only have optional members, but use c_name() everywhere).
>
> Update and add tests to cover the new error messages.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: retitle, improve comments, defer 'u' changes for later, use
> c_name(name).startswith('has_') rather than open coding
> v9: new patch
> ---
>  docs/qapi-code-gen.txt                  | 11 +++++++----
>  scripts/qapi.py                         |  8 +++++++-
>  tests/qapi-schema/args-has-clash.err    |  1 +
>  tests/qapi-schema/args-has-clash.exit   |  2 +-
>  tests/qapi-schema/args-has-clash.json   |  8 ++++----
>  tests/qapi-schema/args-has-clash.out    |  6 ------
>  tests/qapi-schema/reserved-command.err  |  1 +
>  tests/qapi-schema/reserved-command.exit |  2 +-
>  tests/qapi-schema/reserved-command.json |  7 +++----
>  tests/qapi-schema/reserved-command.out  |  5 -----
>  tests/qapi-schema/reserved-member.err   |  1 +
>  tests/qapi-schema/reserved-member.exit  |  2 +-
>  tests/qapi-schema/reserved-member.json  |  7 +++----
>  tests/qapi-schema/reserved-member.out   |  4 ----
>  14 files changed, 30 insertions(+), 35 deletions(-)

All right, this is simple enough to be done now.  And as you say, we can
always relax things again later.

> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index c4264a8..4d8c2fc 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -112,7 +112,9 @@ and field names within a type, should be all lower case with words
>  separated by a hyphen.  However, some existing older commands and
>  complex types use underscore; when extending such expressions,
>  consistency is preferred over blindly avoiding underscore.  Event
> -names should be ALL_CAPS with words separated by underscore.
> +names should be ALL_CAPS with words separated by underscore.  Field
> +names cannot start with 'has-' or 'has_', as this is reserved for
> +tracking optional fields.
>
>  Any name (command, event, type, field, or enum value) beginning with
>  "x-" is marked experimental, and may be withdrawn or changed
> @@ -123,9 +125,10 @@ 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.
> -It is okay to reuse names that match C keywords; the generator will
> -rename a field named "default" in the QAPI to "q_default" in the
> -generated C code.
> +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 d53b5c4..04bcbf7 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -376,7 +376,9 @@ def check_name(expr_info, source, name, allow_optional=False,
>      # code always prefixes it with the enum name
>      if enum_member:
>          membername = '_' + membername
> -    if not valid_name.match(membername):
> +    # Reserve the entire 'q_' namespace for c_name()
> +    if not valid_name.match(membername) or \
> +       membername.replace('-', '_').startswith('q_'):

Why not c_name(membername).startswith('q_')?

>          raise QAPIExprError(expr_info,
>                              "%s uses invalid name '%s'" % (source, name))
>
> @@ -488,6 +490,10 @@ def check_type(expr_info, source, value, allow_array=False,
>      for (key, arg) in value.items():
>          check_name(expr_info, "Member of %s" % source, key,
>                     allow_optional=allow_optional)
> +        if c_name(key).startswith('has_'):
> +            raise QAPIExprError(expr_info,
> +                                "Member of %s uses reserved name '%s'"
> +                                % (source, key))
>          # Todo: allow dictionaries to represent default values of
>          # an optional argument.
>          check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
> diff --git a/tests/qapi-schema/args-has-clash.err b/tests/qapi-schema/args-has-clash.err
> index e69de29..595fe93 100644
> --- a/tests/qapi-schema/args-has-clash.err
> +++ b/tests/qapi-schema/args-has-clash.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/args-has-clash.json:6: Member of 'data' for command 'oops' uses reserved name 'has-a'
> diff --git a/tests/qapi-schema/args-has-clash.exit b/tests/qapi-schema/args-has-clash.exit
> index 573541a..d00491f 100644
> --- a/tests/qapi-schema/args-has-clash.exit
> +++ b/tests/qapi-schema/args-has-clash.exit
> @@ -1 +1 @@
> -0
> +1
> diff --git a/tests/qapi-schema/args-has-clash.json b/tests/qapi-schema/args-has-clash.json
> index a2197de..38453e7 100644
> --- a/tests/qapi-schema/args-has-clash.json
> +++ b/tests/qapi-schema/args-has-clash.json
> @@ -1,6 +1,6 @@
>  # C member name collision
> -# FIXME - This parses, but fails to compile, because the C struct is given
> -# two 'has_a' members, one from the flag for optional 'a', and the other
> -# from member 'has-a'.  Either reject this at parse time, or munge the C
> -# names to avoid the collision.
> +# This would attempt to create two 'has_a' members of the C struct, one
> +# from the flag for optional 'a', and the other from member 'has-a'; so
> +# instead we reject any member with a name that would collide with 'has_'.

Suggest something like:

# We reject names like 'has-a', because they can collide with the flag
# for an optional 'a' in generated C.

> +# TODO we could munge the optional flag name to avoid the collision.
>  { 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
> diff --git a/tests/qapi-schema/args-has-clash.out b/tests/qapi-schema/args-has-clash.out
> index 5a18b6b..e69de29 100644
> --- a/tests/qapi-schema/args-has-clash.out
> +++ b/tests/qapi-schema/args-has-clash.out
> @@ -1,6 +0,0 @@
> -object :empty
> -object :obj-oops-arg
> -    member a: str optional=True
> -    member has-a: str optional=False
> -command oops :obj-oops-arg -> None
> -   gen=True success_response=True
> diff --git a/tests/qapi-schema/reserved-command.err b/tests/qapi-schema/reserved-command.err
> index e69de29..a70856b 100644
> --- a/tests/qapi-schema/reserved-command.err
> +++ b/tests/qapi-schema/reserved-command.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/reserved-command.json:6: 'command' uses invalid name 'q-unix'
> diff --git a/tests/qapi-schema/reserved-command.exit b/tests/qapi-schema/reserved-command.exit
> index 573541a..d00491f 100644
> --- a/tests/qapi-schema/reserved-command.exit
> +++ b/tests/qapi-schema/reserved-command.exit
> @@ -1 +1 @@
> -0
> +1
> diff --git a/tests/qapi-schema/reserved-command.json b/tests/qapi-schema/reserved-command.json
> index be9944c..d662a96 100644
> --- a/tests/qapi-schema/reserved-command.json
> +++ b/tests/qapi-schema/reserved-command.json
> @@ -1,7 +1,6 @@
>  # C entity name collision
> -# FIXME - This parses, but fails to compile, because it attempts to declare
> -# two 'qmp_q_unix' functions (one for 'q-unix', the other because c_name()
> -# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
> -# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
> +# This would attempt to declare two 'qmp_q_unix' functions (one for 'q-unix',
> +# the other because c_name() munges 'unix' to 'q_unix' to avoid reserved word
> +# collisions). Therefore, we reserve 'q_' names for qapi.

Suggest something like:

# We reject names like 'q-unix', because they can collide with the
# mangled name for 'unix' in generated C.

>  { 'command': 'unix' }
>  { 'command': 'q-unix' }
> diff --git a/tests/qapi-schema/reserved-command.out b/tests/qapi-schema/reserved-command.out
> index b31b38f..e69de29 100644
> --- a/tests/qapi-schema/reserved-command.out
> +++ b/tests/qapi-schema/reserved-command.out
> @@ -1,5 +0,0 @@
> -object :empty
> -command q-unix None -> None
> -   gen=True success_response=True
> -command unix None -> None
> -   gen=True success_response=True
> diff --git a/tests/qapi-schema/reserved-member.err b/tests/qapi-schema/reserved-member.err
> index e69de29..8752c5b 100644
> --- a/tests/qapi-schema/reserved-member.err
> +++ b/tests/qapi-schema/reserved-member.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/reserved-member.json:5: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
> diff --git a/tests/qapi-schema/reserved-member.exit b/tests/qapi-schema/reserved-member.exit
> index 573541a..d00491f 100644
> --- a/tests/qapi-schema/reserved-member.exit
> +++ b/tests/qapi-schema/reserved-member.exit
> @@ -1 +1 @@
> -0
> +1
> diff --git a/tests/qapi-schema/reserved-member.json b/tests/qapi-schema/reserved-member.json
> index 1602ed3..a8dac22 100644
> --- a/tests/qapi-schema/reserved-member.json
> +++ b/tests/qapi-schema/reserved-member.json
> @@ -1,6 +1,5 @@
>  # C member name collision
> -# FIXME - This parses, but fails to compile, because it attempts to declare
> -# two 'q_unix' members (one for 'q-unix', the other because c_name()
> -# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
> -# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
> +# This would attempt to declare two 'q_unix' members (one for 'q-unix',
> +# the other because c_name() munges 'unix' to 'q_unix' to avoid reserved word
> +# collisions). Therefore, we reserve 'q_' names for qapi.
>  { 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }

Likewise.

Remind me, why do we need both reserved-command.json and
reserved-member.json?

> diff --git a/tests/qapi-schema/reserved-member.out b/tests/qapi-schema/reserved-member.out
> index 0d8685a..e69de29 100644
> --- a/tests/qapi-schema/reserved-member.out
> +++ b/tests/qapi-schema/reserved-member.out
> @@ -1,4 +0,0 @@
> -object :empty
> -object Foo
> -    member unix: int optional=False
> -    member q-unix: bool optional=False

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl Eric Blake
@ 2015-10-23 13:46   ` Markus Armbruster
  2015-10-23 14:35     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 13:46 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> We generate a static visit_type_FOO_fields() for every type
> FOO.  However, sometimes we need a forward declaration. Split
> the code to generate the forward declaration out of
> gen_visit_implicit_struct() into a new gen_visit_fields_decl(),
> and also prepare for a forward declaration to be emitted
> during gen_visit_struct(), so that a future patch can switch
> from using visit_type_FOO_implicit() to the simpler
> visit_type_FOO_fields() as part of unboxing the base class
> of a struct.
>
> No change to generated code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: new patch, split from 5/17
> ---
>  scripts/qapi-visit.py | 35 ++++++++++++++++++++++++-----------
>  1 file changed, 24 insertions(+), 11 deletions(-)
>
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index e878018..7204ed0 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -15,7 +15,12 @@
>  from qapi import *
>  import re
>
> +# visit_type_FOO_implicit() is emitted as needed; track if it has already
> +# been output. No forward declaration is needed.
>  implicit_structs_seen = set()

I initially read this as "No forward is needed then", but that's wrong.
Suggest to drop that sentence.

> +
> +# visit_type_FOO_fields() is always emitted; track if a forward declaration
> +# or implementation has already been output.
>  struct_fields_seen = set()

Yup.

> @@ -29,19 +34,24 @@ void visit_type_%(c_name)s(Visitor *v, %(c_type)sobj, const char *name, Error **
>                   c_name=c_name(name), c_type=c_type)
>
>
> +def gen_visit_fields_decl(typ):
> +    ret = ''
> +    if typ.name not in struct_fields_seen:
> +        ret += mcgen('''
> +
> +static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
> +''',
> +                     c_type=typ.c_name())
> +        struct_fields_seen.add(typ.name)
> +    return ret
> +
> +
>  def gen_visit_implicit_struct(typ):
>      if typ in implicit_structs_seen:
>          return ''
>      implicit_structs_seen.add(typ)
>
> -    ret = ''
> -    if typ.name not in struct_fields_seen:
> -        # Need a forward declaration
> -        ret += mcgen('''
> -
> -static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
> -''',
> -                     c_type=typ.c_name())
> +    ret = gen_visit_fields_decl(typ)
>
>      ret += mcgen('''
>
> @@ -62,13 +72,12 @@ static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error *
>
>
>  def gen_visit_struct_fields(name, base, members):
> -    struct_fields_seen.add(name)
> -
>      ret = ''
>
>      if base:
>          ret += gen_visit_implicit_struct(base)
>
> +    struct_fields_seen.add(name)
>      ret += mcgen('''
>

Minor cleanup not mentioned in commit message.  Okay.

>  static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
> @@ -100,7 +109,11 @@ out:
>
>
>  def gen_visit_struct(name, base, members):
> -    ret = gen_visit_struct_fields(name, base, members)
> +    ret = ''
> +    if base:
> +        ret += gen_visit_fields_decl(base)
> +
> +    ret += gen_visit_struct_fields(name, base, members)
>
>      # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
>      # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj

What's the purpose of this hunk?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names
  2015-10-23 13:05   ` Markus Armbruster
@ 2015-10-23 14:14     ` Eric Blake
  2015-10-23 14:47       ` Markus Armbruster
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23 14:14 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 3289 bytes --]

On 10/23/2015 07:05 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> c_name() produces names starting with 'q_' when protecting
>> a QMP member name that would fail to directly compile, but
>> in doing so can cause clashes with any QMP name already
>> beginning with 'q-' or 'q_'.  Likewise, we create a C name
>> 'has_' for any optional member, that can clash with any QMP
>> name beginning with 'has-' or 'has_'.
>>
>> Technically, rather than blindly reserving the namespace,
>> we could try to complain about user names only when an actual
>> collision occurs, or even teach c_name() how to munge names
>> to avoid collisions.  But it is not trivial, especially when
>> collisions can occur across multiple types (such as via
>> inheritance or flat unions).  Besides, no existing .json
>> files are trying to use these names.  So it's easier to just
>> outright forbid the potential for collision.  We can always
>> relax things in the future if a real need arises for QMP to
>> express member names that have been forbidden here.
>>
>> 'has_' only has to be reserved for struct/union member names,
>> while 'q_' is reserved everywhere (matching the fact that
>> we only have optional members, but use c_name() everywhere).
>>
>> Update and add tests to cover the new error messages.
>>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
>>

>> +++ b/scripts/qapi.py
>> @@ -376,7 +376,9 @@ def check_name(expr_info, source, name, allow_optional=False,
>>      # code always prefixes it with the enum name
>>      if enum_member:
>>          membername = '_' + membername
>> -    if not valid_name.match(membername):
>> +    # Reserve the entire 'q_' namespace for c_name()
>> +    if not valid_name.match(membername) or \
>> +       membername.replace('-', '_').startswith('q_'):
> 
> Why not c_name(membername).startswith('q_')?

Recursion.  c_name('unix') is 'q_unix', which would be rejected, even
though we want to accept it. (And yes, that was my first try, before the
approach you see here)


>> +++ b/tests/qapi-schema/args-has-clash.json
>> @@ -1,6 +1,6 @@
>>  # C member name collision
>> -# FIXME - This parses, but fails to compile, because the C struct is given
>> -# two 'has_a' members, one from the flag for optional 'a', and the other
>> -# from member 'has-a'.  Either reject this at parse time, or munge the C
>> -# names to avoid the collision.
>> +# This would attempt to create two 'has_a' members of the C struct, one
>> +# from the flag for optional 'a', and the other from member 'has-a'; so
>> +# instead we reject any member with a name that would collide with 'has_'.
> 
> Suggest something like:
> 
> # We reject names like 'has-a', because they can collide with the flag
> # for an optional 'a' in generated C.

Sure, your wording changes are fine.

> 
> Remind me, why do we need both reserved-command.json and
> reserved-member.json?

Because they are different namespaces.  Your comment in 1/25 pointed out
that we could change the command munging to allow qmp_q_unix()
independently from qmp_unix(), even when we can't do the same for members.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct
  2015-10-23 12:39     ` Eric Blake
@ 2015-10-23 14:17       ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 14:17 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> On 10/23/2015 06:33 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
[...]
>>> +++ b/tests/qapi-schema/struct-name-list.json
>>> @@ -0,0 +1,5 @@
>>> +# Potential C name collision
>>> +# FIXME - This parses and compiles on its own, but prevents the user from
>>> +# creating a type named 'Foo' and using ['Foo'] for an array.  We should
>>> +# reject the use of any non-array type names ending in 'List'.
>>> +{ 'struct': 'FooList', 'data': { 's': 'str' } }
>> 
>> "Non-array type name" makes no sense when talking about the QAPI schema,
>> because arrays don't have names there.
>
> Suggestions? Maybe s/non-array//? The wording changes in 2/25 when the
> test starts working.

Dropping non-array works for me.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl
  2015-10-23 13:46   ` Markus Armbruster
@ 2015-10-23 14:35     ` Eric Blake
  2015-10-23 18:05       ` Markus Armbruster
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23 14:35 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 4283 bytes --]

On 10/23/2015 07:46 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> We generate a static visit_type_FOO_fields() for every type
>> FOO.  However, sometimes we need a forward declaration. Split
>> the code to generate the forward declaration out of
>> gen_visit_implicit_struct() into a new gen_visit_fields_decl(),
>> and also prepare for a forward declaration to be emitted
>> during gen_visit_struct(), so that a future patch can switch
>> from using visit_type_FOO_implicit() to the simpler
>> visit_type_FOO_fields() as part of unboxing the base class
>> of a struct.
>>
>> No change to generated code.
>>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
>>
>> ---
>> v10: new patch, split from 5/17
>> ---
>>  scripts/qapi-visit.py | 35 ++++++++++++++++++++++++-----------
>>  1 file changed, 24 insertions(+), 11 deletions(-)
>>
>> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
>> index e878018..7204ed0 100644
>> --- a/scripts/qapi-visit.py
>> +++ b/scripts/qapi-visit.py
>> @@ -15,7 +15,12 @@
>>  from qapi import *
>>  import re
>>
>> +# visit_type_FOO_implicit() is emitted as needed; track if it has already
>> +# been output. No forward declaration is needed.
>>  implicit_structs_seen = set()
> 
> I initially read this as "No forward is needed then", but that's wrong.
> Suggest to drop that sentence.

No forward declaration of visit_type_FOO_implicit() is ever needed. But
yes, dropping the sentence doesn't lose any information, and avoids
confusion.

> 
>> +
>> +# visit_type_FOO_fields() is always emitted; track if a forward declaration
>> +# or implementation has already been output.
>>  struct_fields_seen = set()
> 
> Yup.

Actually, I have plans for a later patch to only emit it for non-empty
structs (getting rid of no-op visit_type_Abort_fields() and friends), as
part of unifying it with gen_visit_union() (since unions don't have
local members, they also wouldn't get a visit_type_Union_fields) - but
not in this subset of the series.

>> @@ -62,13 +72,12 @@ static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error *
>>
>>
>>  def gen_visit_struct_fields(name, base, members):
>> -    struct_fields_seen.add(name)
>> -
>>      ret = ''
>>
>>      if base:
>>          ret += gen_visit_implicit_struct(base)
>>
>> +    struct_fields_seen.add(name)
>>      ret += mcgen('''
>>
> 
> Minor cleanup not mentioned in commit message.  Okay.

Not minor, and I probably should mention it explicitly in the message. I
moved it to make sure that gen_visit_implicit_struct() properly emits a
forward declaration when necessary; we must not modify
struct_fields_seen any sooner than when the next thing in the output
stream is either the forward declaration or the implementation.

>> @@ -100,7 +109,11 @@ out:
>>
>>
>>  def gen_visit_struct(name, base, members):
>> -    ret = gen_visit_struct_fields(name, base, members)
>> +    ret = ''
>> +    if base:
>> +        ret += gen_visit_fields_decl(base)
>> +
>> +    ret += gen_visit_struct_fields(name, base, members)
>>
>>      # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
>>      # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
> 
> What's the purpose of this hunk?

Umm, no clue. Maybe to test that you are reviewing things closely? :)

Actually, I think I have a real answer: leftovers from rebasing.  Once I
fix gen_visit_union() to reuse visit_type_BASE_fields() (patch 11/25),
then gen_visit_struct_fields() no longer calls
gen_visit_implicit_struct(base), and had to replace it with a call to
gen_visit_fields_decl() somewhere.  And I didn't always have this patch
in this position of the series.

But for this patch, you are right that taking it out changes nothing at
this point (since gen_visit_struct_fields(, base) calls
gen_visit_implicit_struct(base) calls gen_visit_fields_decl(base)).

I'm testing if removing this hunk breaks anything later, and will either
post fixup patches or roll v11 at the end of v10 review (depends on how
many other findings you have).

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names
  2015-10-23 14:14     ` Eric Blake
@ 2015-10-23 14:47       ` Markus Armbruster
  2015-10-23 14:52         ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 14:47 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> On 10/23/2015 07:05 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> c_name() produces names starting with 'q_' when protecting
>>> a QMP member name that would fail to directly compile, but
>>> in doing so can cause clashes with any QMP name already
>>> beginning with 'q-' or 'q_'.  Likewise, we create a C name
>>> 'has_' for any optional member, that can clash with any QMP
>>> name beginning with 'has-' or 'has_'.
>>>
>>> Technically, rather than blindly reserving the namespace,
>>> we could try to complain about user names only when an actual
>>> collision occurs, or even teach c_name() how to munge names
>>> to avoid collisions.  But it is not trivial, especially when
>>> collisions can occur across multiple types (such as via
>>> inheritance or flat unions).  Besides, no existing .json
>>> files are trying to use these names.  So it's easier to just
>>> outright forbid the potential for collision.  We can always
>>> relax things in the future if a real need arises for QMP to
>>> express member names that have been forbidden here.
>>>
>>> 'has_' only has to be reserved for struct/union member names,
>>> while 'q_' is reserved everywhere (matching the fact that
>>> we only have optional members, but use c_name() everywhere).
>>>
>>> Update and add tests to cover the new error messages.
>>>
>>> Signed-off-by: Eric Blake <eblake@redhat.com>
>>>
>
>>> +++ b/scripts/qapi.py
>>> @@ -376,7 +376,9 @@ def check_name(expr_info, source, name, allow_optional=False,
>>>      # code always prefixes it with the enum name
>>>      if enum_member:
>>>          membername = '_' + membername
>>> -    if not valid_name.match(membername):
>>> +    # Reserve the entire 'q_' namespace for c_name()
>>> +    if not valid_name.match(membername) or \
>>> +       membername.replace('-', '_').startswith('q_'):
>> 
>> Why not c_name(membername).startswith('q_')?
>
> Recursion.  c_name('unix') is 'q_unix', which would be rejected, even
> though we want to accept it. (And yes, that was my first try, before the
> approach you see here)

c_name(membername, False).startswith('q_')?

[...]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names
  2015-10-23 14:47       ` Markus Armbruster
@ 2015-10-23 14:52         ` Eric Blake
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23 14:52 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 1248 bytes --]

On 10/23/2015 08:47 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> On 10/23/2015 07:05 AM, Markus Armbruster wrote:
>>> Eric Blake <eblake@redhat.com> writes:
>>>
>>>> c_name() produces names starting with 'q_' when protecting
>>>> a QMP member name that would fail to directly compile, but
>>>> in doing so can cause clashes with any QMP name already
>>>> beginning with 'q-' or 'q_'.  Likewise, we create a C name
>>>> 'has_' for any optional member, that can clash with any QMP
>>>> name beginning with 'has-' or 'has_'.
>>>>

>>>> -    if not valid_name.match(membername):
>>>> +    # Reserve the entire 'q_' namespace for c_name()
>>>> +    if not valid_name.match(membername) or \
>>>> +       membername.replace('-', '_').startswith('q_'):
>>>
>>> Why not c_name(membername).startswith('q_')?
>>
>> Recursion.  c_name('unix') is 'q_unix', which would be rejected, even
>> though we want to accept it. (And yes, that was my first try, before the
>> approach you see here)
> 
> c_name(membername, False).startswith('q_')?

Oh, I forgot about the optional bool.  I'll try it.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output Eric Blake
@ 2015-10-23 15:06   ` Markus Armbruster
  2015-10-23 15:16     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 15:06 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> Move code from gen_union() into gen_struct_fields() in order for
> a later patch to share code when enumerating inherited fields
> for struct types.
>
> No change to generated code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: new patch, split off of 5/17
> ---
>  scripts/qapi-types.py | 21 ++++++++++++---------
>  1 file changed, 12 insertions(+), 9 deletions(-)
>
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index 4fe618e..a97cc10 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -51,9 +51,19 @@ def gen_struct_field(name, typ, optional):
>      return ret
>
>
> -def gen_struct_fields(members):
> +def gen_struct_fields(members, base=None):
>      ret = ''
>
> +    if base:
> +        ret += mcgen('''
> +    /* Members inherited from %(c_name)s: */
> +''',
> +                     c_name=base.c_name())
> +        ret += gen_struct_fields(base.members)
> +        ret += mcgen('''
> +    /* Own members: */
> +''')
> +
>      for memb in members:
>          ret += gen_struct_field(memb.name, memb.type, memb.optional)
>      return ret
> @@ -126,14 +136,7 @@ struct %(c_name)s {
>  ''',
>                  c_name=c_name(name))
>      if base:
> -        ret += mcgen('''
> -    /* Members inherited from %(c_name)s: */
> -''',
> -                     c_name=c_name(base.name))
> -        ret += gen_struct_fields(base.members)
> -        ret += mcgen('''
> -    /* Own members: */
> -''')
> +        ret += gen_struct_fields([], base)
>      else:
>          ret += mcgen('''
>      %(c_type)s kind;

One baby step towards

    gen_struct_fields(members, base);

which is where we want both gen_struct() and gen_union() to go.

Slightly confusing: members are *local* members, while base.members are
*all* members.  But the same exists elsewhere already, so let's not
worry about it.

I kind of dislike gen_struct_fields() taking two parameters and calling
itself for one, but I guess we can reconsider after gen_struct() and
gen_union() are unified.  gen_struct_fields() might have just one caller
then.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output
  2015-10-23 15:06   ` Markus Armbruster
@ 2015-10-23 15:16     ` Eric Blake
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23 15:16 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 2076 bytes --]

On 10/23/2015 09:06 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> Move code from gen_union() into gen_struct_fields() in order for
>> a later patch to share code when enumerating inherited fields
>> for struct types.
>>
>> No change to generated code.
>>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
>>
>> ---

>>      if base:
>> -        ret += mcgen('''
>> -    /* Members inherited from %(c_name)s: */
>> -''',
>> -                     c_name=c_name(base.name))
>> -        ret += gen_struct_fields(base.members)
>> -        ret += mcgen('''
>> -    /* Own members: */
>> -''')
>> +        ret += gen_struct_fields([], base)
>>      else:
>>          ret += mcgen('''
>>      %(c_type)s kind;
> 
> One baby step towards
> 
>     gen_struct_fields(members, base);
> 
> which is where we want both gen_struct() and gen_union() to go.

Yep, it's almost like you're peering ahead to my unpublished patch queue :)

> 
> Slightly confusing: members are *local* members, while base.members are
> *all* members.  But the same exists elsewhere already, so let's not
> worry about it.

I am seriously debating about renaming things to
gen_visit_struct(...local_members), just to make it obvious that we have
only local members in that variable.  Separate patch, I can add it in
v11 if we need a respin, otherwise a later subset would be fine.

> 
> I kind of dislike gen_struct_fields() taking two parameters and calling
> itself for one, but I guess we can reconsider after gen_struct() and
> gen_union() are unified.  gen_struct_fields() might have just one caller
> then.

Yes, after my patch that unifies gen_struct/union into a single
gen_object(), there is just a single caller, so I could inline it at
that point.

I also debated whether to open-code the for loop over members, instead
of using a 1-deep recursive call with base=None, just so things are a
bit less magic.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes Eric Blake
@ 2015-10-23 15:30   ` Markus Armbruster
  2015-10-23 20:44     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 15:30 UTC (permalink / raw)
  To: Eric Blake; +Cc: Michael Roth, qemu-devel, Gerd Hoffmann

Eric Blake <eblake@redhat.com> writes:

> A previous patch (commit 1e6c1616) made it possible to
> directly cast from a qapi type to its base type. A future
> patch will do likewise for structs.  However, it requires
> the client code to use a C cast, which turns off compiler
> type-safety checks if the client gets it wrong.  So this

Who's the client?  Suggest to simply drop "if the client gets it wrong".

> patch adds inline type-safe wrappers named qapi_FOO_base()
> for any type FOO that has a base, which can be used to
> upcast a qapi type to its base, then uses the new generated
> functions in places where we were already casting.
>
> Some of the ugliness of this patch will disappear once
> structs are laid out in the same manner as unions; mark
> it with TODO for now.
>
> Note that C makes const-correct upcasts annoying because
> it lacks overloads; these functions cast away const so that
> they can accept user pointers whether const or not, and the
> result in turn can be assigned to normal or const pointers.
> Alternatively, this could have been done with macros, but
> those tend to not have quite as much type safety.

Well, if you torture the preprocessor hard enough, it surrenders and
lets you do type checking.  Torture isn't pretty, though.  See for
instance

http://git.ozlabs.org/?p=ccan;a=blob;f=ccan/check_type/check_type.h;h=77501a95597c3e73396c270d54a8ed53a9defbc4;hb=HEAD

> This patch just adds upcasts.  None of our code needed to
> downcast from a base qapi class to a child.  Also, in the
> case of grandchildren (such as BlockdevOptionsQcow2), the
> caller will need to call two functions to get to the inner
> base (although it wouldn't be too hard to generate a
> qapi_FOO_base_base() if desired).  If a user changes qapi
> to alter the base class hierarchy, such as going from
> 'A -> C' to 'A -> B -> C', it will change the type of
> 'qapi_C_base()', and the compiler will point out the places
> that are affected by the new base.
>
> One alternative was proposed, but was deemed too ugly to use
> in practice: the generators could output redundant
> information using anonymous types:
> | struct Child {
> |     union {
> |         struct {
> |             Type1 parent_member1;
> |             Type2 parent_member2;
> |         };
> |         Parent base;
> |     };
> | };
> With that ugly proposal, for a given qapi type, obj->member
> and obj->base.member would refer to the same storage; allowing
> convenience in working with members without needing 'base.'
> allowing typesafe upcast without needing a C cast by accessing
> '&obj->base', and allowing downcasts from the parent back to
> the child possible through container_of(obj, Child, base).
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: new patch
> ---
>  scripts/qapi-types.py | 20 ++++++++++++++++++++
>  ui/spice-core.c       | 14 ++++++++++----
>  ui/vnc.c              |  9 ++++++---
>  3 files changed, 36 insertions(+), 7 deletions(-)
>
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index a97cc10..ed4a11c 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -97,6 +97,23 @@ struct %(c_name)s {
>      return ret
>
>
> +def gen_upcast(name, base, struct):
> +    # C makes const-correctness ugly.  We have to cast away const to let
> +    # this function work for both const and non-const obj.
> +    # TODO Ugly difference between struct and flat union bases
> +    member = ''
> +    if struct:
> +        member = '->base'
> +    return mcgen('''
> +
> +static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
> +{
> +    return (%(base)s *)obj%(member)s;

> +}
> +''',
> +                 c_name=c_name(name), base=base.c_name(), member=member)

The ugliness doesn't bother me much, because it'll go away.  But perhaps
we should simply limit gen_upcast() to unions now, and extend it to
structs when we unbox their base.

> +
> +
>  def gen_alternate_qtypes_decl(name):
>      return mcgen('''
>
> @@ -268,6 +285,9 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>              self.decl += gen_union(name, base, variants)
>          else:
>              self.decl += gen_struct(name, base, members)
> +        if base:
> +            # TODO Drop last param once structs have sane layout
> +            self.decl += gen_upcast(name, base, not variants)
>          self._gen_type_cleanup(name)
>
>      def visit_alternate_type(self, name, info, variants):
> diff --git a/ui/spice-core.c b/ui/spice-core.c
> index bf4fd07..d43cfbe 100644
> --- a/ui/spice-core.c
> +++ b/ui/spice-core.c
> @@ -218,9 +218,11 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
>      }
>
>      if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
> -        add_addr_info(client->base, (struct sockaddr *)&info->paddr_ext,
> +        add_addr_info(qapi_SpiceChannel_base(client),
> +                      (struct sockaddr *)&info->paddr_ext,
>                        info->plen_ext);
> -        add_addr_info(server->base, (struct sockaddr *)&info->laddr_ext,
> +        add_addr_info(qapi_SpiceServerInfo_base(server),
> +                      (struct sockaddr *)&info->laddr_ext,
>                        info->llen_ext);
>      } else {
>          error_report("spice: %s, extended address is expected",

This change will start to make sense when we unbox base.  Right now, it
doesn't :)

> @@ -229,7 +231,9 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
>
>      switch (event) {
>      case SPICE_CHANNEL_EVENT_CONNECTED:
> -        qapi_event_send_spice_connected(server->base, client->base, &error_abort);
> +        qapi_event_send_spice_connected(qapi_SpiceServerInfo_base(server),
> +                                        qapi_SpiceChannel_base(client),
> +                                        &error_abort);
>          break;
>      case SPICE_CHANNEL_EVENT_INITIALIZED:
>          if (auth) {
> @@ -242,7 +246,9 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
>          break;
>      case SPICE_CHANNEL_EVENT_DISCONNECTED:
>          channel_list_del(info);
> -        qapi_event_send_spice_disconnected(server->base, client->base, &error_abort);
> +        qapi_event_send_spice_disconnected(qapi_SpiceServerInfo_base(server),
> +                                           qapi_SpiceChannel_base(client),
> +                                           &error_abort);
>          break;
>      default:
>          break;
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 502a10a..9473b32 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -263,7 +263,8 @@ static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
>
>      info = g_malloc(sizeof(*info));
>      info->base = g_malloc(sizeof(*info->base));
> -    vnc_init_basic_info_from_server_addr(vd->lsock, info->base, &err);
> +    vnc_init_basic_info_from_server_addr(vd->lsock,
> +                                         qapi_VncServerInfo_base(info), &err);
>      info->has_auth = true;
>      info->auth = g_strdup(vnc_auth_name(vd));
>      if (err) {
> @@ -301,7 +302,8 @@ static void vnc_client_cache_addr(VncState *client)
>
>      client->info = g_malloc0(sizeof(*client->info));
>      client->info->base = g_malloc0(sizeof(*client->info->base));
> -    vnc_init_basic_info_from_remote_addr(client->csock, client->info->base,
> +    vnc_init_basic_info_from_remote_addr(client->csock,
> +                                         qapi_VncClientInfo_base(client->info),
>                                           &err);
>      if (err) {
>          qapi_free_VncClientInfo(client->info);
> @@ -326,7 +328,8 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event)
>
>      switch (event) {
>      case QAPI_EVENT_VNC_CONNECTED:
> -        qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
> +        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
> +                                      &error_abort);
>          break;
>      case QAPI_EVENT_VNC_INITIALIZED:
>          qapi_event_send_vnc_initialized(si, vs->info, &error_abort);

Not a single cast to union base?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl
  2015-10-23 14:35     ` Eric Blake
@ 2015-10-23 18:05       ` Markus Armbruster
  2015-10-23 19:44         ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 18:05 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> On 10/23/2015 07:46 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> We generate a static visit_type_FOO_fields() for every type
>>> FOO.  However, sometimes we need a forward declaration. Split
>>> the code to generate the forward declaration out of
>>> gen_visit_implicit_struct() into a new gen_visit_fields_decl(),
>>> and also prepare for a forward declaration to be emitted
>>> during gen_visit_struct(), so that a future patch can switch
>>> from using visit_type_FOO_implicit() to the simpler
>>> visit_type_FOO_fields() as part of unboxing the base class
>>> of a struct.
>>>
>>> No change to generated code.
>>>
>>> Signed-off-by: Eric Blake <eblake@redhat.com>
>>>
>>> ---
>>> v10: new patch, split from 5/17
>>> ---
>>>  scripts/qapi-visit.py | 35 ++++++++++++++++++++++++-----------
>>>  1 file changed, 24 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
>>> index e878018..7204ed0 100644
>>> --- a/scripts/qapi-visit.py
>>> +++ b/scripts/qapi-visit.py
>>> @@ -15,7 +15,12 @@
>>>  from qapi import *
>>>  import re
>>>
>>> +# visit_type_FOO_implicit() is emitted as needed; track if it has already
>>> +# been output. No forward declaration is needed.
>>>  implicit_structs_seen = set()
>> 
>> I initially read this as "No forward is needed then", but that's wrong.
>> Suggest to drop that sentence.
>
> No forward declaration of visit_type_FOO_implicit() is ever needed. But
> yes, dropping the sentence doesn't lose any information, and avoids
> confusion.
>
>> 
>>> +
>>> +# visit_type_FOO_fields() is always emitted; track if a forward declaration
>>> +# or implementation has already been output.
>>>  struct_fields_seen = set()
>> 
>> Yup.
>
> Actually, I have plans for a later patch to only emit it for non-empty
> structs (getting rid of no-op visit_type_Abort_fields() and friends), as
> part of unifying it with gen_visit_union() (since unions don't have
> local members, they also wouldn't get a visit_type_Union_fields) - but
> not in this subset of the series.
>
>>> @@ -62,13 +72,12 @@ static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error *
>>>
>>>
>>>  def gen_visit_struct_fields(name, base, members):
>>> -    struct_fields_seen.add(name)
>>> -
>>>      ret = ''
>>>
>>>      if base:
>>>          ret += gen_visit_implicit_struct(base)
>>>
>>> +    struct_fields_seen.add(name)
>>>      ret += mcgen('''
>>>
>> 
>> Minor cleanup not mentioned in commit message.  Okay.
>
> Not minor, and I probably should mention it explicitly in the message. I
> moved it to make sure that gen_visit_implicit_struct() properly emits a
> forward declaration when necessary; we must not modify
> struct_fields_seen any sooner than when the next thing in the output
> stream is either the forward declaration or the implementation.

The proper place for the .add() is right next to where the thing it
tracks gets done, no argument.

I believe your cleanup makes an actual difference only when
gen_visit_implicit_struct(base) can call gen_visit_struct_fields(name).
Obviously impossible now, which is why I called it "minor".

PATCH 10 will drop the code between the old spot and the new spot.
Unless something between this patch and PATCH 10 depends on this
cleanup, I'd simply leave it dirty until then.

>>> @@ -100,7 +109,11 @@ out:
>>>
>>>
>>>  def gen_visit_struct(name, base, members):
>>> -    ret = gen_visit_struct_fields(name, base, members)
>>> +    ret = ''
>>> +    if base:
>>> +        ret += gen_visit_fields_decl(base)
>>> +
>>> +    ret += gen_visit_struct_fields(name, base, members)
>>>
>>>      # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
>>>      # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
>> 
>> What's the purpose of this hunk?
>
> Umm, no clue. Maybe to test that you are reviewing things closely? :)

Passed the test, I guess ;)

> Actually, I think I have a real answer: leftovers from rebasing.  Once I
> fix gen_visit_union() to reuse visit_type_BASE_fields() (patch 11/25),
> then gen_visit_struct_fields() no longer calls
> gen_visit_implicit_struct(base), and had to replace it with a call to
> gen_visit_fields_decl() somewhere.  And I didn't always have this patch
> in this position of the series.
>
> But for this patch, you are right that taking it out changes nothing at
> this point (since gen_visit_struct_fields(, base) calls
> gen_visit_implicit_struct(base) calls gen_visit_fields_decl(base)).
>
> I'm testing if removing this hunk breaks anything later, and will either
> post fixup patches or roll v11 at the end of v10 review (depends on how
> many other findings you have).

Okay.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members Eric Blake
@ 2015-10-23 19:14   ` Markus Armbruster
  2015-10-23 19:19     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 19:14 UTC (permalink / raw)
  To: Eric Blake; +Cc: Luiz Capitulino, Gerd Hoffmann, qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> Rather than storing a base class as a pointer to a box, just
> store the fields of that base class in the same order, so that
> a child struct can be directly cast to its parent.  This gives
> less malloc overhead, less pointer dereferencing, and even less
> generated code.  Compare to the earlier commit 1e6c1616a "qapi:
> Generate a nicer struct for flat unions" (although that patch
> had fewer places to change, as less of qemu was directly using
> qapi structs for flat unions).  It also drops a hack that was
> needed for type-safe casting to the base class of a struct.
>
> Changes to the generated code look like this in qapi-types.h:
>
> | struct SpiceChannel {
> |-    SpiceBasicInfo *base;
> |+    /* Members inherited from SpiceBasicInfo: */
> |+    char *host;
> |+    char *port;
> |+    NetworkAddressFamily family;
> |+    /* Own members: */
> |     int64_t connection_id;
>
> as well as:
>
> | static inline SpiceBasicInfo *qapi_SpiceChannel_base(const SpiceChannel *obj)
> | {
> |-    return (SpiceBasicInfo *)obj->base;
> |+    return (SpiceBasicInfo *)obj;
> | }

No more, PATCH 09 hides this change.  If you limit that one to just
unions, it'll be visible again here, but it'll look different.

>
> and this in qapi-visit.c:
>
> | static void visit_type_SpiceChannel_fields(Visitor *v, SpiceChannel **obj, Error **errp)
> | {
> |     Error *err = NULL;
> |
> |-    visit_type_implicit_SpiceBasicInfo(v, &(*obj)->base, &err);
> |+    visit_type_SpiceBasiInfo_fields(v, (SpiceBasicInfo **)obj, &err);

s/BasiI/BasicI/

> |     if (err) {
>
> plus the wholesale elimination of some now-unused
> visit_type_implicit_FOO() functions.
>
> Without boxing, the corner case of one empty struct having
> another empty struct as its base type now requires inserting a
> dummy member (previously, the pointer to the base would have
> sufficed).
>
> And now that we no longer consume a 'base' member in the generated
> C struct, we can delete the former negative struct-base-clash-base
> test.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>

Patch looks good.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members
  2015-10-23 19:14   ` Markus Armbruster
@ 2015-10-23 19:19     ` Eric Blake
  2015-10-23 20:45       ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23 19:19 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Luiz Capitulino, Gerd Hoffmann, qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 2358 bytes --]

On 10/23/2015 01:14 PM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> Rather than storing a base class as a pointer to a box, just
>> store the fields of that base class in the same order, so that
>> a child struct can be directly cast to its parent.  This gives
>> less malloc overhead, less pointer dereferencing, and even less
>> generated code.  Compare to the earlier commit 1e6c1616a "qapi:
>> Generate a nicer struct for flat unions" (although that patch
>> had fewer places to change, as less of qemu was directly using
>> qapi structs for flat unions).  It also drops a hack that was
>> needed for type-safe casting to the base class of a struct.
>>
>> Changes to the generated code look like this in qapi-types.h:
>>

>>
>> as well as:
>>
>> | static inline SpiceBasicInfo *qapi_SpiceChannel_base(const SpiceChannel *obj)
>> | {
>> |-    return (SpiceBasicInfo *)obj->base;
>> |+    return (SpiceBasicInfo *)obj;
>> | }
> 
> No more, PATCH 09 hides this change.  If you limit that one to just
> unions, it'll be visible again here, but it'll look different.

No, this change is new to v10, because of patch 09.  In v9, we did not
have gen_upcast(); in v10, patch 9's version of gen_upcast() had to
special-case struct to output 'obj->base', and patch 10 gets rid of the
special case to output 'obj' always.

If I limit patch 9 to just unions, then there would be no clients using
the upcast wrappers in patch 9.  The only users of upcasts that benefit
from the result of gen_upcast() are the struct users in ui/*.c, that
were touched in patch 9, and then where _this_ change in the generated
code in patch 10 lets ui/ code remain unchanged (the way the upcast
happens changed, but it was nicely hidden behind the nice wrapper
interface).

> 
>>
>> and this in qapi-visit.c:
>>
>> | static void visit_type_SpiceChannel_fields(Visitor *v, SpiceChannel **obj, Error **errp)
>> | {
>> |     Error *err = NULL;
>> |
>> |-    visit_type_implicit_SpiceBasicInfo(v, &(*obj)->base, &err);
>> |+    visit_type_SpiceBasiInfo_fields(v, (SpiceBasicInfo **)obj, &err);
> 
> s/BasiI/BasicI/

I should have used the mouse to copy-paste instead of typing late at
night :)

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 11/25] qapi-visit: Remove redundant functions for flat union base
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 11/25] qapi-visit: Remove redundant functions for flat union base Eric Blake
@ 2015-10-23 19:35   ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-23 19:35 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> The code for visiting the base class of a child struct created
> visit_type_Base_fields() which covers all fields of Base; while
> the code for visiting the base class of a flat union created
> visit_type_Union_fields() covering all fields of the base
> except the discriminator.  But since the base class includes
> the discriminator of a flat union, we can just visit the entire
> base, without needing a separate visit of the discriminator.
> Not only is consistently visiting all fields easier to
> understand, it lets us share code.
>
> The generated code in qapi-visit.c loses several now-unused
> visit_type_UNION_fields(), along with changes like:
>
> |@@ -1654,11 +1557,7 @@ void visit_type_BlockdevOptions(Visitor
> |     if (!*obj) {
> |         goto out_obj;
> |     }
> |-    visit_type_BlockdevOptions_fields(v, obj, &err);
> |-    if (err) {
> |-        goto out_obj;
> |-    }
> |-    visit_type_BlockdevDriver(v, &(*obj)->driver, "driver", &err);
> |+    visit_type_BlockdevOptionsBase_fields(v, (BlockdevOptionsBase **)obj, &err);
> |     if (err) {
> |         goto out_obj;
> |     }
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: split out regex to earlier commit, rebase to earlier changes,
> improve commit message
> v9: (no v6-8): hoist from v5 35/46; rebase to master; fix indentation
> botch in gen_visit_union(); polish commit message
> ---
>  scripts/qapi-visit.py | 32 +++++++++++++++-----------------
>  1 file changed, 15 insertions(+), 17 deletions(-)
>
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index e30062b..3c23c53 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -226,8 +226,7 @@ def gen_visit_union(name, base, variants):
>      ret = ''
>
>      if base:
> -        members = [m for m in base.members if m != variants.tag_member]
> -        ret += gen_visit_struct_fields(name, None, members)
> +        ret += gen_visit_fields_decl(base)
>
>      for var in variants.variants:
>          # Ugly special case for simple union TODO get rid of it

Instead of generating a _fields() for the union, we'll reuse the base's.
May have to generate a forward declaration for it.

> @@ -252,31 +251,30 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
>

Visit the non-variant members:

>      if base:

A flat union's non-variant members are exactly the base's members, so
call the base's _fields():

>          ret += mcgen('''
> -    visit_type_%(c_name)s_fields(v, obj, &err);
> +    visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err);
>  ''',
> -                     c_name=c_name(name))
  +                     c_name=base.c_name())

I stared at the new cast here some until I realized: to call the base's
_fields(), we need to cast obj to base.

> -        ret += gen_err_check(label='out_obj')
> -
> -    tag_key = variants.tag_member.name
> -    if not variants.tag_name:
> -        # we pointlessly use a different key for simple unions
> -        tag_key = 'type'
> -    ret += mcgen('''
> +                     c_name=base.c_name())
> +    else:

A simple union's non-variant member is the implicit tag, and no more, so
visit it:

> +        ret += mcgen('''
>      visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
> -    if (err) {
> -        goto out_obj;
> -    }
> +''',
> +                     c_type=variants.tag_member.type.c_name(),
> +                     # TODO ugly special case for simple union
> +                     # Use same tag name in C as on the wire to get rid of
> +                     # it, then: c_name=c_name(variants.tag_member.name)
> +                     c_name='kind',
> +                     name=variants.tag_member.name)

The 'type' vs. 'kind' stupidity never fails to confuse me, and at this
time of day I give up, and diff the generated output.  It looks okay.

Common error check for both branches of the if:

> +    ret += gen_err_check(label='out_obj')
> +    ret += mcgen('''
>      if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
>          goto out_obj;
>      }

Visit variant members:

>      switch ((*obj)->%(c_name)s) {
>  ''',
> -                 c_type=variants.tag_member.type.c_name(),
>                   # TODO ugly special case for simple union
>                   # Use same tag name in C as on the wire to get rid of
>                   # it, then: c_name=c_name(variants.tag_member.name)
> -                 c_name=c_name(variants.tag_name or 'kind'),
> -                 name=tag_key)
> +                 c_name=c_name(variants.tag_name or 'kind'))
>
>      for var in variants.variants:
>          # TODO ugly special case for simple union

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl
  2015-10-23 18:05       ` Markus Armbruster
@ 2015-10-23 19:44         ` Eric Blake
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23 19:44 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 1647 bytes --]

On 10/23/2015 12:05 PM, Markus Armbruster wrote:

>>>>  def gen_visit_struct_fields(name, base, members):
>>>> -    struct_fields_seen.add(name)
>>>> -
>>>>      ret = ''
>>>>
>>>>      if base:
>>>>          ret += gen_visit_implicit_struct(base)
>>>>
>>>> +    struct_fields_seen.add(name)
>>>>      ret += mcgen('''
>>>>
>>>
>>> Minor cleanup not mentioned in commit message.  Okay.
>>
>> Not minor, and I probably should mention it explicitly in the message. I
>> moved it to make sure that gen_visit_implicit_struct() properly emits a
>> forward declaration when necessary; we must not modify
>> struct_fields_seen any sooner than when the next thing in the output
>> stream is either the forward declaration or the implementation.
> 
> The proper place for the .add() is right next to where the thing it
> tracks gets done, no argument.
> 
> I believe your cleanup makes an actual difference only when
> gen_visit_implicit_struct(base) can call gen_visit_struct_fields(name).
> Obviously impossible now, which is why I called it "minor".

Oh, I was probably confusing that the implicit struct is for a different
type (base) than what we are adding to struct_fields_seen (name).

> 
> PATCH 10 will drop the code between the old spot and the new spot.
> Unless something between this patch and PATCH 10 depends on this
> cleanup, I'd simply leave it dirty until then.

Indeed, dropping this hunk and letting subsequent cleanup do it right
makes no difference.  Will add it to my fixup queue.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-23 15:30   ` Markus Armbruster
@ 2015-10-23 20:44     ` Eric Blake
  2015-10-26  7:33       ` Markus Armbruster
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-23 20:44 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Michael Roth, qemu-devel, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 4020 bytes --]

On 10/23/2015 09:30 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> A previous patch (commit 1e6c1616) made it possible to
>> directly cast from a qapi type to its base type. A future
>> patch will do likewise for structs.  However, it requires
>> the client code to use a C cast, which turns off compiler
>> type-safety checks if the client gets it wrong.  So this
> 
> Who's the client?  Suggest to simply drop "if the client gets it wrong".
> 
>> patch adds inline type-safe wrappers named qapi_FOO_base()
>> for any type FOO that has a base, which can be used to
>> upcast a qapi type to its base, then uses the new generated
>> functions in places where we were already casting.
>>
>> Some of the ugliness of this patch will disappear once
>> structs are laid out in the same manner as unions; mark
>> it with TODO for now.
>>
>> Note that C makes const-correct upcasts annoying because
>> it lacks overloads; these functions cast away const so that
>> they can accept user pointers whether const or not, and the
>> result in turn can be assigned to normal or const pointers.
>> Alternatively, this could have been done with macros, but
>> those tend to not have quite as much type safety.
> 
> Well, if you torture the preprocessor hard enough, it surrenders and
> lets you do type checking.  Torture isn't pretty, though.  See for
> instance
> 
> http://git.ozlabs.org/?p=ccan;a=blob;f=ccan/check_type/check_type.h;h=77501a95597c3e73396c270d54a8ed53a9defbc4;hb=HEAD

Oddly enough, our container_of() macro looks verrrrry similar to the
comments in that sample code (that is, we DO use the preprocessor for a
type check).  :)


>> +++ b/scripts/qapi-types.py
>> @@ -97,6 +97,23 @@ struct %(c_name)s {
>>      return ret
>>
>>
>> +def gen_upcast(name, base, struct):
>> +    # C makes const-correctness ugly.  We have to cast away const to let
>> +    # this function work for both const and non-const obj.
>> +    # TODO Ugly difference between struct and flat union bases
>> +    member = ''
>> +    if struct:
>> +        member = '->base'
>> +    return mcgen('''
>> +
>> +static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
>> +{
>> +    return (%(base)s *)obj%(member)s;
> 
>> +}
>> +''',
>> +                 c_name=c_name(name), base=base.c_name(), member=member)
> 
> The ugliness doesn't bother me much, because it'll go away.  But perhaps
> we should simply limit gen_upcast() to unions now, and extend it to
> structs when we unbox their base.
> 

Okay, I could do that.  Then I definitely need to post a v11 respin,
this is starting to be too much for simple fixups to v10.


>> -        add_addr_info(server->base, (struct sockaddr *)&info->laddr_ext,
>> +        add_addr_info(qapi_SpiceServerInfo_base(server),
>> +                      (struct sockaddr *)&info->laddr_ext,
>>                        info->llen_ext);
>>      } else {
>>          error_report("spice: %s, extended address is expected",
> 
> This change will start to make sense when we unbox base.  Right now, it
> doesn't :)

Indeed, if I don't port gen_upcast() to types until patch 10/25, then
this hunk also has to move to patch 10.  That means no clients of the
upcast macros in patch 9/25, _unless_ I add testsuite coverage.  Which I
probably ought to do.

>>      switch (event) {
>>      case QAPI_EVENT_VNC_CONNECTED:
>> -        qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
>> +        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
>> +                                      &error_abort);
>>          break;
>>      case QAPI_EVENT_VNC_INITIALIZED:
>>          qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
> 
> Not a single cast to union base?

Not that I could find. So I'll have to create one in the testsuite.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members
  2015-10-23 19:19     ` Eric Blake
@ 2015-10-23 20:45       ` Eric Blake
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23 20:45 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, Michael Roth, Gerd Hoffmann, Luiz Capitulino

[-- Attachment #1: Type: text/plain, Size: 1722 bytes --]

On 10/23/2015 01:19 PM, Eric Blake wrote:
> On 10/23/2015 01:14 PM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>>
>>> Rather than storing a base class as a pointer to a box, just
>>> store the fields of that base class in the same order, so that
>>> a child struct can be directly cast to its parent.  This gives
>>> less malloc overhead, less pointer dereferencing, and even less
>>> generated code.  Compare to the earlier commit 1e6c1616a "qapi:
>>> Generate a nicer struct for flat unions" (although that patch
>>> had fewer places to change, as less of qemu was directly using
>>> qapi structs for flat unions).  It also drops a hack that was
>>> needed for type-safe casting to the base class of a struct.
>>>
>>> Changes to the generated code look like this in qapi-types.h:
>>>
> 
>>>
>>> as well as:
>>>
>>> | static inline SpiceBasicInfo *qapi_SpiceChannel_base(const SpiceChannel *obj)
>>> | {
>>> |-    return (SpiceBasicInfo *)obj->base;
>>> |+    return (SpiceBasicInfo *)obj;
>>> | }
>>
>> No more, PATCH 09 hides this change.  If you limit that one to just
>> unions, it'll be visible again here, but it'll look different.
> 
> No, this change is new to v10, because of patch 09.  In v9, we did not
> have gen_upcast(); in v10, patch 9's version of gen_upcast() had to
> special-case struct to output 'obj->base', and patch 10 gets rid of the
> special case to output 'obj' always.

Serves me right for reading this response before the 9/25 response. I
see what you mean now, and will be floating hunks differently on the v11
respin.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 24/25] qapi: Remove outdated tests related to QMP/branch collisions
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 24/25] qapi: Remove outdated tests related to QMP/branch collisions Eric Blake
@ 2015-10-23 23:27   ` Eric Blake
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-23 23:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 859 bytes --]

On 10/22/2015 11:09 PM, Eric Blake wrote:
> 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.
> 
> Signed-off-by: Eric Blake <eblake@redhat.com>
> 
> ---
> v10: new patch

Does not belong in subset B.  This is basically reverting 7b2a5c2, but
that means we have assertion failures until a later patch of mine in
subset C fixes things:
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg04114.html

So I'm deferring this patch out of v11.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-23 20:44     ` Eric Blake
@ 2015-10-26  7:33       ` Markus Armbruster
  2015-10-26 16:24         ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-26  7:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: Gerd Hoffmann, Michael Roth, qemu-devel

Eric Blake <eblake@redhat.com> writes:

> On 10/23/2015 09:30 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> A previous patch (commit 1e6c1616) made it possible to
>>> directly cast from a qapi type to its base type. A future
>>> patch will do likewise for structs.  However, it requires
>>> the client code to use a C cast, which turns off compiler
>>> type-safety checks if the client gets it wrong.  So this
>> 
>> Who's the client?  Suggest to simply drop "if the client gets it wrong".
>> 
>>> patch adds inline type-safe wrappers named qapi_FOO_base()
>>> for any type FOO that has a base, which can be used to
>>> upcast a qapi type to its base, then uses the new generated
>>> functions in places where we were already casting.
>>>
>>> Some of the ugliness of this patch will disappear once
>>> structs are laid out in the same manner as unions; mark
>>> it with TODO for now.
>>>
>>> Note that C makes const-correct upcasts annoying because
>>> it lacks overloads; these functions cast away const so that
>>> they can accept user pointers whether const or not, and the
>>> result in turn can be assigned to normal or const pointers.
>>> Alternatively, this could have been done with macros, but
>>> those tend to not have quite as much type safety.
>> 
>> Well, if you torture the preprocessor hard enough, it surrenders and
>> lets you do type checking.  Torture isn't pretty, though.  See for
>> instance
>> 
>> http://git.ozlabs.org/?p=ccan;a=blob;f=ccan/check_type/check_type.h;h=77501a95597c3e73396c270d54a8ed53a9defbc4;hb=HEAD
>
> Oddly enough, our container_of() macro looks verrrrry similar to the
> comments in that sample code (that is, we DO use the preprocessor for a
> type check).  :)
>
>
>>> +++ b/scripts/qapi-types.py
>>> @@ -97,6 +97,23 @@ struct %(c_name)s {
>>>      return ret
>>>
>>>
>>> +def gen_upcast(name, base, struct):
>>> +    # C makes const-correctness ugly.  We have to cast away const to let
>>> +    # this function work for both const and non-const obj.
>>> +    # TODO Ugly difference between struct and flat union bases
>>> +    member = ''
>>> +    if struct:
>>> +        member = '->base'
>>> +    return mcgen('''
>>> +
>>> +static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
>>> +{
>>> +    return (%(base)s *)obj%(member)s;
>> 
>>> +}
>>> +''',
>>> +                 c_name=c_name(name), base=base.c_name(), member=member)
>> 
>> The ugliness doesn't bother me much, because it'll go away.  But perhaps
>> we should simply limit gen_upcast() to unions now, and extend it to
>> structs when we unbox their base.
>> 
>
> Okay, I could do that.  Then I definitely need to post a v11 respin,
> this is starting to be too much for simple fixups to v10.
>
>
>>> -        add_addr_info(server->base, (struct sockaddr *)&info->laddr_ext,
>>> +        add_addr_info(qapi_SpiceServerInfo_base(server),
>>> +                      (struct sockaddr *)&info->laddr_ext,
>>>                        info->llen_ext);
>>>      } else {
>>>          error_report("spice: %s, extended address is expected",
>> 
>> This change will start to make sense when we unbox base.  Right now, it
>> doesn't :)
>
> Indeed, if I don't port gen_upcast() to types until patch 10/25, then
> this hunk also has to move to patch 10.  That means no clients of the
> upcast macros in patch 9/25, _unless_ I add testsuite coverage.  Which I
> probably ought to do.
>
>>>      switch (event) {
>>>      case QAPI_EVENT_VNC_CONNECTED:
>>> -        qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
>>> +        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
>>> +                                      &error_abort);
>>>          break;
>>>      case QAPI_EVENT_VNC_INITIALIZED:
>>>          qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
>> 
>> Not a single cast to union base?
>
> Not that I could find. So I'll have to create one in the testsuite.

I guess I'd introduce gen_upcast() only with its first real user,
i.e. when unboxing struct base.  At that time, its obvious
implementation should work for both struct and union, even though we
actually use it only for struct.  If you want to add a test case for
unions, go ahead.  I'm not sure I'd bother, because once we unify code
generation for the two, testing them separately won't add much value
anymore.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-26  7:33       ` Markus Armbruster
@ 2015-10-26 16:24         ` Eric Blake
  2015-10-26 17:54           ` Markus Armbruster
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-26 16:24 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Gerd Hoffmann, Michael Roth, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2703 bytes --]

On 10/26/2015 01:33 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> On 10/23/2015 09:30 AM, Markus Armbruster wrote:
>>> Eric Blake <eblake@redhat.com> writes:
>>>
>>>> A previous patch (commit 1e6c1616) made it possible to
>>>> directly cast from a qapi type to its base type. A future
>>>> patch will do likewise for structs.  However, it requires
>>>> the client code to use a C cast, which turns off compiler
>>>> type-safety checks if the client gets it wrong.  So this
>>>
>>> Who's the client?  Suggest to simply drop "if the client gets it wrong".
>>>
>>>> patch adds inline type-safe wrappers named qapi_FOO_base()
>>>> for any type FOO that has a base, which can be used to
>>>> upcast a qapi type to its base, then uses the new generated
>>>> functions in places where we were already casting.
>>>>

>>
>> Indeed, if I don't port gen_upcast() to types until patch 10/25, then
>> this hunk also has to move to patch 10.  That means no clients of the
>> upcast macros in patch 9/25, _unless_ I add testsuite coverage.  Which I
>> probably ought to do.
>>
>>>>      switch (event) {
>>>>      case QAPI_EVENT_VNC_CONNECTED:
>>>> -        qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
>>>> +        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
>>>> +                                      &error_abort);
>>>>          break;
>>>>      case QAPI_EVENT_VNC_INITIALIZED:
>>>>          qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
>>>
>>> Not a single cast to union base?
>>
>> Not that I could find. So I'll have to create one in the testsuite.
> 
> I guess I'd introduce gen_upcast() only with its first real user,
> i.e. when unboxing struct base.  At that time, its obvious
> implementation should work for both struct and union, even though we
> actually use it only for struct.  If you want to add a test case for
> unions, go ahead.  I'm not sure I'd bother, because once we unify code
> generation for the two, testing them separately won't add much value
> anymore.

It sounds like I have two options for v11:

1. Keep 9/25 introducing gen_upcast(), just for union types, and
including testsuite coverage. In 10/25, make use of the upcast functions
to struct as part of making structs sane.

2. Swap the patch order: do 10/25 to alter struct layout first, using
ugly casts; then implement 9/25 that adds gen_upcast() and fixes the
ugly casts to instead use the new upcast functions.

I can go either way, so do you have any preference?

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert to new qapi union layout
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert " Eric Blake
@ 2015-10-26 17:07   ` Markus Armbruster
  2015-10-26 20:39     ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-26 17:07 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> We have two issues with our qapi union layout:
> 1) Even though the QMP wire format spells the tag 'type', the
> C code spells it 'kind', requiring some hacks in the generator.
> 2) The C struct uses an anonymous union, which places all tag
> values in the same namespace as all non-variant members. This
> leads to spurious collisions if a tag value matches a QMP name.
>
> Make the conversion to the new layout for qapi-visit.py.

This part is nicely mechanical: ->kind becomes ->type, ->variant becomes
->u.variant, and variants.tag_name or 'kind' becomes
variants.tag_member.name.

>                                                           Also
> make a change in qapi.py to quit using the name 'kind', and
> the corresponding change in the testsuite.

This isn't really part of "qapi-visit: Convert to new qapi union
layout".  Could be made a separate patch, but I'd simply squash it into
the previous one "qapi: Start converting to new qapi union layout".  See
also my remark inline.

>                                             However, many more
> changes will be made to the testsuite later, including the
> entire deletion of union-clash-type.json, after the completion
> of the conversion eliminates collisions between union tag
> branch names and non-variant names.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: new patch, split from 7/17 an 8/17
> v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
> http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
> ---
>  scripts/qapi-visit.py                  | 24 +++++++++---------------
>  scripts/qapi.py                        |  2 +-
>  tests/qapi-schema/union-clash-type.err |  2 +-
>  3 files changed, 11 insertions(+), 17 deletions(-)
>
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 3c23c53..421fcb6 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -187,18 +187,18 @@ 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)->kind, %(c_name)s_qtypes, name, &err);
> +    visit_get_next_type(v, (int*) &(*obj)->type, %(c_name)s_qtypes, name, &err);
>      if (err) {
>          goto out_obj;
>      }
> -    switch ((*obj)->kind) {
> +    switch ((*obj)->type) {
>  ''',
>                  c_name=c_name(name))
>
>      for var in variants.variants:
>          ret += mcgen('''
>      case %(case)s:
> -        visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, name, &err);
> +        visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err);
>          break;
>  ''',
>                       case=c_enum_const(variants.tag_member.type.name,
> @@ -259,22 +259,16 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
>      visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
>  ''',
>                       c_type=variants.tag_member.type.c_name(),
> -                     # TODO ugly special case for simple union
> -                     # Use same tag name in C as on the wire to get rid of
> -                     # it, then: c_name=c_name(variants.tag_member.name)
> -                     c_name='kind',
> +                     c_name=c_name(variants.tag_member.name),
>                       name=variants.tag_member.name)
>      ret += gen_err_check(label='out_obj')
>      ret += mcgen('''
> -    if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
> +    if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
>          goto out_obj;
>      }
>      switch ((*obj)->%(c_name)s) {
>  ''',
> -                 # TODO ugly special case for simple union
> -                 # Use same tag name in C as on the wire to get rid of
> -                 # it, then: c_name=c_name(variants.tag_member.name)
> -                 c_name=c_name(variants.tag_name or 'kind'))
> +                 c_name=c_name(variants.tag_member.name))
>
>      for var in variants.variants:
>          # TODO ugly special case for simple union
> @@ -286,13 +280,13 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
>                                         var.name))
>          if simple_union_type:
>              ret += mcgen('''
> -        visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "data", &err);
> +        visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, "data", &err);
>  ''',
>                           c_type=simple_union_type.c_name(),
>                           c_name=c_name(var.name))
>          else:
>              ret += mcgen('''
> -        visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
> +        visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
>  ''',
>                           c_type=var.type.c_name(),
>                           c_name=c_name(var.name))
> @@ -308,7 +302,7 @@ out_obj:
>      error_propagate(errp, err);
>      err = NULL;
>      if (*obj) {
> -        visit_end_union(v, !!(*obj)->data, &err);
> +        visit_end_union(v, !!(*obj)->u.data, &err);
>      }
>      error_propagate(errp, err);
>      err = NULL;
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 04bcbf7..8b9f5f7 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -548,7 +548,7 @@ def check_union(expr, expr_info):
>      base = expr.get('base')
>      discriminator = expr.get('discriminator')
>      members = expr['data']
> -    values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
> +    values = {'MAX': '(automatic)', 'TYPE': '(automatic tag)'}
>
>      # Two types of unions, determined by discriminator.
>

Took me a minute to remember what's going on here.  A simple union's tag
values, become an enum type.  Here, we catch two differend kinds of
clashes:

1. Tag value with the implicitly defined enum member _MAX, i.e. a clash
in the enum member name space

2. Member of the (as of yet still) unnamed union holding the variants
with the tag variable type, formerly kind (i.e. a clash in the struct
member name space).

The previous patch added type to the struct member name space without
updating clash detection.

A future patch will remove the unnamed union, thus clash kind 2.  It'll
also remove kind from the struct member name space, but that doesn't
matter.

I believe the following would be slightly cleaner: amend the previous
patch to *add* key 'TYPE' to values.  Drop both 'KIND' and 'TYPE' when
you remove the unnamed union.

> diff --git a/tests/qapi-schema/union-clash-type.err b/tests/qapi-schema/union-clash-type.err
> index a5dead1..eca7c1d 100644
> --- a/tests/qapi-schema/union-clash-type.err
> +++ b/tests/qapi-schema/union-clash-type.err
> @@ -1 +1 @@
> -tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'kind' clashes with '(automatic)'
> +tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'type' clashes with '(automatic tag)'

You might be able to avoid this change by adding 'TYPE' in the right
spot.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 23/25] qapi: Reserve 'u' member name
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 23/25] qapi: Reserve 'u' member name Eric Blake
@ 2015-10-26 17:27   ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-26 17:27 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> Now that we have separated union tag values from colliding with
> non-variant C names, by naming the union 'u', we should reserve
> this name for our use.  Note that we want to forbid 'u' even in
> a struct with no variants, because it is possible for a future
> qemu release to extend QMP in a backwards-compatible manner while
> converting from a struct to a flat union.  Fortunately, no
> existing clients were using this member name.  If we ever find
> the need for QMP to have a member 'u', we could at that time
> relax things, perhaps by having c_name() munge the QMP member to
> 'q_u'.
>
> Note that we cannot forbid 'u' everywhere (by adding the
> rejection code to check_name()), because the existing QKeyCode
> enum already uses it.

Suggest to add something like: Therefore, we only reserve it as a struct
type member name.

>                        And it is still okay to use it as a
> branch name within a union, although not worth adding a
> positive test to qapi-schema-test for this corner case.

Not sure this sentence is needed.

> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: new patch, split from 1/17 and 3/17; by deferring this until
> after the rename was complete, it reduces churn due to the new feature
> ---
>  scripts/qapi.py                        | 2 +-
>  tests/Makefile                         | 1 +
>  tests/qapi-schema/struct-member-u.err  | 1 +
>  tests/qapi-schema/struct-member-u.exit | 1 +
>  tests/qapi-schema/struct-member-u.json | 7 +++++++
>  tests/qapi-schema/struct-member-u.out  | 0
>  6 files changed, 11 insertions(+), 1 deletion(-)
>  create mode 100644 tests/qapi-schema/struct-member-u.err
>  create mode 100644 tests/qapi-schema/struct-member-u.exit
>  create mode 100644 tests/qapi-schema/struct-member-u.json
>  create mode 100644 tests/qapi-schema/struct-member-u.out
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 8b9f5f7..b941ccf 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -490,7 +490,7 @@ def check_type(expr_info, source, value, allow_array=False,
>      for (key, arg) in value.items():
>          check_name(expr_info, "Member of %s" % source, key,
>                     allow_optional=allow_optional)
> -        if c_name(key).startswith('has_'):
> +        if key == 'u' or c_name(key).startswith('has_'):

Perhaps c_name(key) == 'u' would be very slightly cleaner.  No
difference in practice, of course.

>              raise QAPIExprError(expr_info,
>                                  "Member of %s uses reserved name '%s'"
>                                  % (source, key))
> diff --git a/tests/Makefile b/tests/Makefile
> index 9194264..8c239f8 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -326,6 +326,7 @@ qapi-schema += struct-base-clash-deep.json
>  qapi-schema += struct-base-clash.json
>  qapi-schema += struct-data-invalid.json
>  qapi-schema += struct-member-invalid.json
> +qapi-schema += struct-member-u.json

The closely related test for the reserved 'has_' prefix is called
args-has-clash.json.

More losely related tests for other reserved names are called
reserved-command.json, reserved-member.json.

Should these all be called like reserved-WHATEVER-WHERE.json?

>  qapi-schema += struct-name-list.json
>  qapi-schema += trailing-comma-list.json
>  qapi-schema += trailing-comma-object.json
> diff --git a/tests/qapi-schema/struct-member-u.err b/tests/qapi-schema/struct-member-u.err
> new file mode 100644
> index 0000000..0dc354c
> --- /dev/null
> +++ b/tests/qapi-schema/struct-member-u.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/struct-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u'
> diff --git a/tests/qapi-schema/struct-member-u.exit b/tests/qapi-schema/struct-member-u.exit
> new file mode 100644
> index 0000000..d00491f
> --- /dev/null
> +++ b/tests/qapi-schema/struct-member-u.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/struct-member-u.json b/tests/qapi-schema/struct-member-u.json
> new file mode 100644
> index 0000000..1eaf0f3
> --- /dev/null
> +++ b/tests/qapi-schema/struct-member-u.json
> @@ -0,0 +1,7 @@
> +# Potential C member name collision
> +# We reject use of 'u' as a member name, to allow it for internal use in
> +# putting union branch members in a separate namespace from QMP members.
> +# This is true even for non-unions, because it is possible to convert a
> +# struct to flat union while remaining backwards compatible in QMP.
> +# TODO - we could munge the member name to 'q_u' to avoid the collision
> +{ 'struct': 'Oops', 'data': { 'u': 'str' } }
> diff --git a/tests/qapi-schema/struct-member-u.out b/tests/qapi-schema/struct-member-u.out
> new file mode 100644
> index 0000000..e69de29

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-26 16:24         ` Eric Blake
@ 2015-10-26 17:54           ` Markus Armbruster
  2015-10-26 20:53             ` Eric Blake
  0 siblings, 1 reply; 58+ messages in thread
From: Markus Armbruster @ 2015-10-26 17:54 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Gerd Hoffmann, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> On 10/26/2015 01:33 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> On 10/23/2015 09:30 AM, Markus Armbruster wrote:
>>>> Eric Blake <eblake@redhat.com> writes:
>>>>
>>>>> A previous patch (commit 1e6c1616) made it possible to
>>>>> directly cast from a qapi type to its base type. A future
>>>>> patch will do likewise for structs.  However, it requires
>>>>> the client code to use a C cast, which turns off compiler
>>>>> type-safety checks if the client gets it wrong.  So this
>>>>
>>>> Who's the client?  Suggest to simply drop "if the client gets it wrong".
>>>>
>>>>> patch adds inline type-safe wrappers named qapi_FOO_base()
>>>>> for any type FOO that has a base, which can be used to
>>>>> upcast a qapi type to its base, then uses the new generated
>>>>> functions in places where we were already casting.
>>>>>
>
>>>
>>> Indeed, if I don't port gen_upcast() to types until patch 10/25, then
>>> this hunk also has to move to patch 10.  That means no clients of the
>>> upcast macros in patch 9/25, _unless_ I add testsuite coverage.  Which I
>>> probably ought to do.
>>>
>>>>>      switch (event) {
>>>>>      case QAPI_EVENT_VNC_CONNECTED:
>>>>> -        qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
>>>>> +        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
>>>>> +                                      &error_abort);
>>>>>          break;
>>>>>      case QAPI_EVENT_VNC_INITIALIZED:
>>>>>          qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
>>>>
>>>> Not a single cast to union base?
>>>
>>> Not that I could find. So I'll have to create one in the testsuite.
>> 
>> I guess I'd introduce gen_upcast() only with its first real user,
>> i.e. when unboxing struct base.  At that time, its obvious
>> implementation should work for both struct and union, even though we
>> actually use it only for struct.  If you want to add a test case for
>> unions, go ahead.  I'm not sure I'd bother, because once we unify code
>> generation for the two, testing them separately won't add much value
>> anymore.
>
> It sounds like I have two options for v11:
>
> 1. Keep 9/25 introducing gen_upcast(), just for union types, and
> including testsuite coverage. In 10/25, make use of the upcast functions
> to struct as part of making structs sane.
>
> 2. Swap the patch order: do 10/25 to alter struct layout first, using
> ugly casts; then implement 9/25 that adds gen_upcast() and fixes the
> ugly casts to instead use the new upcast functions.
>
> I can go either way, so do you have any preference?

I think I'd 3. Do 10/25 first, with gen_upcast() squashed in, and used
for casts to base.  That gen_upcast() will just work for unions, too.
Least churn.

But any of the three options should work.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B')
  2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
                   ` (24 preceding siblings ...)
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 25/25] qapi: Simplify gen_struct_field() Eric Blake
@ 2015-10-26 17:55 ` Markus Armbruster
  25 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-26 17:55 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Eduardo Habkost

Eric Blake <eblake@redhat.com> writes:

> No pending prerequisites (applies to current master)
>
> Also available as a tag at this location:
> git fetch git://repo.or.cz/qemu/ericb.git qapi-cleanupv10b
>
> and I plan to eventually forcefully update my branch with the rest
> of the v5 series, at:
> http://repo.or.cz/qemu/ericb.git/shortlog/refs/heads/qapi

Compared to v9, I had fewer and more local comments.  Feel very close to
convergence.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert to new qapi union layout
  2015-10-26 17:07   ` Markus Armbruster
@ 2015-10-26 20:39     ` Eric Blake
  2015-10-27  7:08       ` Markus Armbruster
  0 siblings, 1 reply; 58+ messages in thread
From: Eric Blake @ 2015-10-26 20:39 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 3491 bytes --]

On 10/26/2015 11:07 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> We have two issues with our qapi union layout:
>> 1) Even though the QMP wire format spells the tag 'type', the
>> C code spells it 'kind', requiring some hacks in the generator.
>> 2) The C struct uses an anonymous union, which places all tag
>> values in the same namespace as all non-variant members. This
>> leads to spurious collisions if a tag value matches a QMP name.
>>
>> Make the conversion to the new layout for qapi-visit.py.
> 
> This part is nicely mechanical: ->kind becomes ->type, ->variant becomes
> ->u.variant, and variants.tag_name or 'kind' becomes
> variants.tag_member.name.
> 
>>                                                           Also
>> make a change in qapi.py to quit using the name 'kind', and
>> the corresponding change in the testsuite.
> 
> This isn't really part of "qapi-visit: Convert to new qapi union
> layout".  Could be made a separate patch, but I'd simply squash it into
> the previous one "qapi: Start converting to new qapi union layout".  See
> also my remark inline.
> 

It _was_ a part of the previous patch in v9 :)

[...]

>> +++ b/scripts/qapi.py
>> @@ -548,7 +548,7 @@ def check_union(expr, expr_info):
>>      base = expr.get('base')
>>      discriminator = expr.get('discriminator')
>>      members = expr['data']
>> -    values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
>> +    values = {'MAX': '(automatic)', 'TYPE': '(automatic tag)'}
>>
>>      # Two types of unions, determined by discriminator.
>>
> 
> Took me a minute to remember what's going on here.  A simple union's tag
> values, become an enum type.  Here, we catch two differend kinds of
> clashes:
> 
> 1. Tag value with the implicitly defined enum member _MAX, i.e. a clash
> in the enum member name space
> 
> 2. Member of the (as of yet still) unnamed union holding the variants
> with the tag variable type, formerly kind (i.e. a clash in the struct
> member name space).
> 
> The previous patch added type to the struct member name space without
> updating clash detection.
> 
> A future patch will remove the unnamed union, thus clash kind 2.  It'll
> also remove kind from the struct member name space, but that doesn't
> matter.
> 
> I believe the following would be slightly cleaner: amend the previous
> patch to *add* key 'TYPE' to values.  Drop both 'KIND' and 'TYPE' when
> you remove the unnamed union.

Okay, that works for me.  Reserve additional namespace in 12, then drop
the reservation in the later patch (now in subset C, see my comments to
24/25)...

> 
>> diff --git a/tests/qapi-schema/union-clash-type.err b/tests/qapi-schema/union-clash-type.err
>> index a5dead1..eca7c1d 100644
>> --- a/tests/qapi-schema/union-clash-type.err
>> +++ b/tests/qapi-schema/union-clash-type.err
>> @@ -1 +1 @@
>> -tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'kind' clashes with '(automatic)'
>> +tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'type' clashes with '(automatic tag)'
> 
> You might be able to avoid this change by adding 'TYPE' in the right
> spot.

...and see if I can avoid churn in union-clash-type.json up until the
point in subset C where it disappears.  I'll see how it plays out.
Expect v11 soon.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes
  2015-10-26 17:54           ` Markus Armbruster
@ 2015-10-26 20:53             ` Eric Blake
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Blake @ 2015-10-26 20:53 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, Gerd Hoffmann, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 1262 bytes --]

On 10/26/2015 11:54 AM, Markus Armbruster wrote:

>> It sounds like I have two options for v11:
>>
>> 1. Keep 9/25 introducing gen_upcast(), just for union types, and
>> including testsuite coverage. In 10/25, make use of the upcast functions
>> to struct as part of making structs sane.
>>
>> 2. Swap the patch order: do 10/25 to alter struct layout first, using
>> ugly casts; then implement 9/25 that adds gen_upcast() and fixes the
>> ugly casts to instead use the new upcast functions.
>>
>> I can go either way, so do you have any preference?
> 
> I think I'd 3. Do 10/25 first, with gen_upcast() squashed in, and used
> for casts to base.  That gen_upcast() will just work for unions, too.
> Least churn.

I actually started with option 3 back when first writing v10, then
decided that it made the patch big enough, and the addition was
orthogonal enough, to go with the split patches at the time I actually
posted v10.

> 
> But any of the three options should work.

Good.  Because I had already gone with option 1 locally before asking
the question, which means now I don't have to respin to get option 2 or 3 :)

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert to new qapi union layout
  2015-10-26 20:39     ` Eric Blake
@ 2015-10-27  7:08       ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-27  7:08 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> On 10/26/2015 11:07 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> We have two issues with our qapi union layout:
>>> 1) Even though the QMP wire format spells the tag 'type', the
>>> C code spells it 'kind', requiring some hacks in the generator.
>>> 2) The C struct uses an anonymous union, which places all tag
>>> values in the same namespace as all non-variant members. This
>>> leads to spurious collisions if a tag value matches a QMP name.
>>>
>>> Make the conversion to the new layout for qapi-visit.py.
>> 
>> This part is nicely mechanical: ->kind becomes ->type, ->variant becomes
>> ->u.variant, and variants.tag_name or 'kind' becomes
>> variants.tag_member.name.
>> 
>>>                                                           Also
>>> make a change in qapi.py to quit using the name 'kind', and
>>> the corresponding change in the testsuite.
>> 
>> This isn't really part of "qapi-visit: Convert to new qapi union
>> layout".  Could be made a separate patch, but I'd simply squash it into
>> the previous one "qapi: Start converting to new qapi union layout".  See
>> also my remark inline.
>> 
>
> It _was_ a part of the previous patch in v9 :)

Actually, it was in "[PATCH v9 08/17] tests: Convert to new qapi union
layout" (i.e. the next patch), not in "[PATCH v9 07/17] qapi: Start
converting to new qapi union layout" (the previous patch).


> [...]
>
>>> +++ b/scripts/qapi.py
>>> @@ -548,7 +548,7 @@ def check_union(expr, expr_info):
>>>      base = expr.get('base')
>>>      discriminator = expr.get('discriminator')
>>>      members = expr['data']
>>> -    values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
>>> +    values = {'MAX': '(automatic)', 'TYPE': '(automatic tag)'}
>>>
>>>      # Two types of unions, determined by discriminator.
>>>
>> 
>> Took me a minute to remember what's going on here.  A simple union's tag
>> values, become an enum type.  Here, we catch two differend kinds of
>> clashes:
>> 
>> 1. Tag value with the implicitly defined enum member _MAX, i.e. a clash
>> in the enum member name space
>> 
>> 2. Member of the (as of yet still) unnamed union holding the variants
>> with the tag variable type, formerly kind (i.e. a clash in the struct
>> member name space).
>> 
>> The previous patch added type to the struct member name space without
>> updating clash detection.
>> 
>> A future patch will remove the unnamed union, thus clash kind 2.  It'll
>> also remove kind from the struct member name space, but that doesn't
>> matter.
>> 
>> I believe the following would be slightly cleaner: amend the previous
>> patch to *add* key 'TYPE' to values.  Drop both 'KIND' and 'TYPE' when
>> you remove the unnamed union.
>
> Okay, that works for me.  Reserve additional namespace in 12, then drop
> the reservation in the later patch (now in subset C, see my comments to
> 24/25)...
>
>> 
>>> diff --git a/tests/qapi-schema/union-clash-type.err
>>> b/tests/qapi-schema/union-clash-type.err
>>> index a5dead1..eca7c1d 100644
>>> --- a/tests/qapi-schema/union-clash-type.err
>>> +++ b/tests/qapi-schema/union-clash-type.err
>>> @@ -1 +1 @@
>>> -tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion'
>>> member 'kind' clashes with '(automatic)'
>>> +tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion'
>>> member 'type' clashes with '(automatic tag)'
>> 
>> You might be able to avoid this change by adding 'TYPE' in the right
>> spot.
>
> ...and see if I can avoid churn in union-clash-type.json up until the
> point in subset C where it disappears.  I'll see how it plays out.
> Expect v11 soon.

Thanks!

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v10 22/25] qapi: Finish converting to new qapi union layout
  2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 22/25] qapi: Finish converting " Eric Blake
@ 2015-10-27  8:33   ` Markus Armbruster
  0 siblings, 0 replies; 58+ messages in thread
From: Markus Armbruster @ 2015-10-27  8:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, Michael Roth

Eric Blake <eblake@redhat.com> writes:

> We have two issues with our qapi union layout:
> 1) Even though the QMP wire format spells the tag 'type', the
> C code spells it 'kind', requiring some hacks in the generator.
> 2) The C struct uses an anonymous union, which places all tag
> values in the same namespace as all non-variant members. This
> leads to spurious collisions if a tag value matches a QMP name.

"a non-variant member name"

Could use an example.  Pointer to flat-union-clash-branch.json would
do.

> This patch is the back end for a series that converts to a
> saner qapi union layout.  Now that all clients have been
> converted to use 'type' and 'obj->u.value', we can drop the
> temporary parallel support for 'kind' and 'obj->value'.
>
> Given a simple union qapi type:
>
> { 'union':'Foo', 'data': { 'a':'int', 'b':'bool' } }
>
> this is the overall effect, when compared to the state before
> this series of patches:
>
> | struct Foo {
> |-    FooKind kind;
> |-    union { /* union tag is @kind */
> |+    FooKind type;
> |+    union { /* union tag is @type */
> |         void *data;
> |         int64_t a;
> |         bool b;
> |-    };
> |+    } u;
> | };
>
> Note, however, that we do not rename the generated enum, which
> is still 'FooKind'.  A further patch could generate implicit
> enums as 'FooType', but while the generator already reserved
> the '*Kind' namespace (commit 4dc2e69), there are already QMP
> constructs with '*Type' naming, which means changing our
> reservation namespace would have lots of churn to C code to
> deal with a forced name change.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v10: rebase to earlier changes, match commit wording
> v9: new patch, but incorporates parts of v5 31/46 and Markus' RFC:
> http://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02236.html
> ---
>  scripts/qapi-types.py | 26 +++++---------------------
>  1 file changed, 5 insertions(+), 21 deletions(-)
>
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index 579532d..d131430 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -148,23 +148,10 @@ struct %(c_name)s {
>      if base:
>          ret += gen_struct_fields([], base)
>      else:
> -        # TODO As a hack, we emit both 'kind' and 'type'. Ultimately, we
> -        # want to use only 'type', but the conversion is large enough to
> -        # require staging over several commits.
> -        ret += mcgen('''
> -    union {
> -        %(c_type)s kind;
> -        %(c_type)s type;
> -    };
> -''',
> -                     c_type=c_name(variants.tag_member.type.name))
> +        ret += gen_struct_field(variants.tag_member.name,
> +                                variants.tag_member.type,
> +                                False)
>
> -    # TODO As a hack, we emit the union twice, once as an anonymous union
> -    # and once as a named union.  Ultimately, we want to use only the
> -    # named union version (as it avoids conflicts between tag values as
> -    # branch names competing with non-variant QMP names), but the conversion
> -    # is large enough to require staging over several commits.
> -    tmp = ''
>      # 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
> @@ -173,7 +160,7 @@ 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?
> -    tmp += mcgen('''
> +    ret += mcgen('''
>      union { /* union tag is @%(c_name)s */
>          void *data;
>  ''',
> @@ -182,17 +169,14 @@ struct %(c_name)s {
>      for var in variants.variants:
>          # Ugly special case for simple union TODO get rid of it
>          typ = var.simple_union_type() or var.type
> -        tmp += mcgen('''
> +        ret += mcgen('''
>          %(c_type)s %(c_name)s;
>  ''',
>                       c_type=typ.c_type(),
>                       c_name=c_name(var.name))
>
> -    ret += tmp
> -    ret += '    ' + '\n    '.join(tmp.split('\n'))
>      ret += mcgen('''
>      } u;
> -    };
>  };
>  ''')

Tag values can no longer clash with non-variant member names, but we
still have a bunch of restrictions stemming from that clash, notably the
one you updated in PATCH 12 (outlaw 'TYPE' in addition to 'KIND').  You
previously cleaned them up in "[PATCH v10 24/25] qapi: Remove outdated
tests related to QMP/branch collisions", but that one's now delayed
until later.  I haven't tried to understand why, because I think
delaying it a bit is okay, but I'd like to have it noted in the commit
message.  If you supply a suitably updated one, I'll touch it up in my
tree.

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2015-10-27  8:33 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-23  5:09 [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 01/25] tests/qapi-schema: Test for reserved names, empty struct Eric Blake
2015-10-23 12:33   ` Markus Armbruster
2015-10-23 12:39     ` Eric Blake
2015-10-23 14:17       ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 02/25] qapi: More idiomatic string operations Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 03/25] qapi: More robust conditions for when labels are needed Eric Blake
2015-10-23 12:44   ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 04/25] qapi: Reserve '*List' type names for list types Eric Blake
2015-10-23 12:53   ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 05/25] qapi: Reserve 'q_*' and 'has_*' member names Eric Blake
2015-10-23 13:05   ` Markus Armbruster
2015-10-23 14:14     ` Eric Blake
2015-10-23 14:47       ` Markus Armbruster
2015-10-23 14:52         ` Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 06/25] vnc: Hoist allocation of VncBasicInfo to callers Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 07/25] qapi-visit: Split off visit_type_FOO_fields forward decl Eric Blake
2015-10-23 13:46   ` Markus Armbruster
2015-10-23 14:35     ` Eric Blake
2015-10-23 18:05       ` Markus Armbruster
2015-10-23 19:44         ` Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 08/25] qapi-types: Refactor base fields output Eric Blake
2015-10-23 15:06   ` Markus Armbruster
2015-10-23 15:16     ` Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 09/25] qapi: Prefer typesafe upcasts to qapi base classes Eric Blake
2015-10-23 15:30   ` Markus Armbruster
2015-10-23 20:44     ` Eric Blake
2015-10-26  7:33       ` Markus Armbruster
2015-10-26 16:24         ` Eric Blake
2015-10-26 17:54           ` Markus Armbruster
2015-10-26 20:53             ` Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 10/25] qapi: Unbox base members Eric Blake
2015-10-23 19:14   ` Markus Armbruster
2015-10-23 19:19     ` Eric Blake
2015-10-23 20:45       ` Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 11/25] qapi-visit: Remove redundant functions for flat union base Eric Blake
2015-10-23 19:35   ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 12/25] qapi: Start converting to new qapi union layout Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 13/25] qapi-visit: Convert " Eric Blake
2015-10-26 17:07   ` Markus Armbruster
2015-10-26 20:39     ` Eric Blake
2015-10-27  7:08       ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 14/25] tests: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 15/25] block: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 16/25] sockets: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 17/25] net: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 18/25] char: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 19/25] input: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 20/25] memory: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 21/25] tpm: " Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 22/25] qapi: Finish converting " Eric Blake
2015-10-27  8:33   ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 23/25] qapi: Reserve 'u' member name Eric Blake
2015-10-26 17:27   ` Markus Armbruster
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 24/25] qapi: Remove outdated tests related to QMP/branch collisions Eric Blake
2015-10-23 23:27   ` Eric Blake
2015-10-23  5:09 ` [Qemu-devel] [PATCH v10 25/25] qapi: Simplify gen_struct_field() Eric Blake
2015-10-26 17:55 ` [Qemu-devel] [PATCH v10 00/25] qapi collision reduction (post-introspection subset B') Markus Armbruster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.