Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2016-03-18' into staging

QAPI patches for 2016-03-18

# gpg: Signature made Fri 18 Mar 2016 09:54:57 GMT using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-qapi-2016-03-18:
  qapi: Use anonymous bases in QMP flat unions
  qapi: Allow anonymous base for flat union
  qapi: Make BlockdevOptions doc example closer to reality
  qapi: Don't special-case simple union wrappers
  qapi: Drop unused c_null()
  qapi: Inline gen_visit_members() into lone caller
  qapi-commands: Inline single-use helpers of gen_marshal()
  qapi-commands: Utilize implicit struct visits
  qapi-event: Utilize implicit struct visits
  qapi-event: Drop qmp_output_get_qobject() null check
  qapi: Emit implicit structs in generated C
  qapi: Adjust names of implicit types
  qapi: Make c_type() more OO-like
  qapi: Fix command with named empty argument type
  qapi: Assert in places where variants are not handled

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/backends/baum.c b/backends/baum.c
index c11320e..eef3467 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -567,7 +567,7 @@
                                       ChardevReturn *ret,
                                       Error **errp)
 {
-    ChardevCommon *common = backend->u.braille;
+    ChardevCommon *common = backend->u.braille.data;
     BaumDriverState *baum;
     CharDriverState *chr;
     brlapi_handle_t *handle;
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 5e1833c..8dea5a1 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -68,7 +68,7 @@
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevCommon *common = backend->u.msmouse;
+    ChardevCommon *common = backend->u.msmouse.data;
     CharDriverState *chr;
 
     chr = qemu_chr_alloc(common, errp);
diff --git a/block/nbd.c b/block/nbd.c
index 9f333c9..836424c 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -206,13 +206,13 @@
     if (qdict_haskey(options, "path")) {
         UnixSocketAddress *q_unix;
         saddr->type = SOCKET_ADDRESS_KIND_UNIX;
-        q_unix = saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
+        q_unix = saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
         q_unix->path = g_strdup(qdict_get_str(options, "path"));
         qdict_del(options, "path");
     } else {
         InetSocketAddress *inet;
         saddr->type = SOCKET_ADDRESS_KIND_INET;
-        inet = saddr->u.inet = g_new0(InetSocketAddress, 1);
+        inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
         inet->host = g_strdup(qdict_get_str(options, "host"));
         if (!qdict_get_try_str(options, "port")) {
             inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
@@ -321,7 +321,7 @@
             error_setg(errp, "TLS only supported over IP sockets");
             goto error;
         }
-        hostname = saddr->u.inet->host;
+        hostname = saddr->u.inet.data->host;
     }
 
     /* establish TCP connection, return error if it fails
diff --git a/block/qcow2.c b/block/qcow2.c
index 5f4fea6..cec5bd0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2800,15 +2800,15 @@
 
     *spec_info = (ImageInfoSpecific){
         .type  = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
-        .u.qcow2 = g_new(ImageInfoSpecificQCow2, 1),
+        .u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1),
     };
     if (s->qcow_version == 2) {
-        *spec_info->u.qcow2 = (ImageInfoSpecificQCow2){
+        *spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
             .compat             = g_strdup("0.10"),
             .refcount_bits      = s->refcount_bits,
         };
     } else if (s->qcow_version == 3) {
-        *spec_info->u.qcow2 = (ImageInfoSpecificQCow2){
+        *spec_info->u.qcow2.data = (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 80f0338..29c8fc3 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -2203,18 +2203,18 @@
 
     *spec_info = (ImageInfoSpecific){
         .type = IMAGE_INFO_SPECIFIC_KIND_VMDK,
-        {
-            .vmdk = g_new0(ImageInfoSpecificVmdk, 1),
+        .u = {
+            .vmdk.data = g_new0(ImageInfoSpecificVmdk, 1),
         },
     };
 
-    *spec_info->u.vmdk = (ImageInfoSpecificVmdk) {
+    *spec_info->u.vmdk.data = (ImageInfoSpecificVmdk) {
         .create_type = g_strdup(s->create_type),
         .cid = s->cid,
         .parent_cid = s->parent_cid,
     };
 
-    next = &spec_info->u.vmdk->extents;
+    next = &spec_info->u.vmdk.data->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 85dee57..24c8861 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1247,7 +1247,7 @@
     };
     TransactionAction action = {
         .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC,
-        .u.blockdev_snapshot_sync = &snapshot,
+        .u.blockdev_snapshot_sync.data = &snapshot,
     };
     blockdev_do_action(&action, errp);
 }
@@ -1261,7 +1261,7 @@
     };
     TransactionAction action = {
         .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT,
-        .u.blockdev_snapshot = &snapshot_data,
+        .u.blockdev_snapshot.data = &snapshot_data,
     };
     blockdev_do_action(&action, errp);
 }
@@ -1276,7 +1276,7 @@
     };
     TransactionAction action = {
         .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC,
-        .u.blockdev_snapshot_internal_sync = &snapshot,
+        .u.blockdev_snapshot_internal_sync.data = &snapshot,
     };
     blockdev_do_action(&action, errp);
 }
@@ -1515,7 +1515,7 @@
 
     g_assert(common->action->type ==
              TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC);
-    internal = common->action->u.blockdev_snapshot_internal_sync;
+    internal = common->action->u.blockdev_snapshot_internal_sync.data;
     state = DO_UPCAST(InternalSnapshotState, common, common);
 
     /* 1. parse input */
@@ -1665,7 +1665,7 @@
     switch (action->type) {
     case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT:
         {
-            BlockdevSnapshot *s = action->u.blockdev_snapshot;
+            BlockdevSnapshot *s = action->u.blockdev_snapshot.data;
             device = s->node;
             node_name = s->node;
             new_image_file = NULL;
@@ -1674,7 +1674,7 @@
         break;
     case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
         {
-            BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync;
+            BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
             device = s->has_device ? s->device : NULL;
             node_name = s->has_node_name ? s->node_name : NULL;
             new_image_file = s->snapshot_file;
@@ -1723,7 +1723,7 @@
     }
 
     if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
-        BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync;
+        BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
         const char *format = s->has_format ? s->format : "qcow2";
         enum NewImageMode mode;
         const char *snapshot_node_name =
@@ -1861,7 +1861,7 @@
     Error *local_err = NULL;
 
     assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
-    backup = common->action->u.drive_backup;
+    backup = common->action->u.drive_backup.data;
 
     blk = blk_by_name(backup->device);
     if (!blk) {
@@ -1943,7 +1943,7 @@
     Error *local_err = NULL;
 
     assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
-    backup = common->action->u.blockdev_backup;
+    backup = common->action->u.blockdev_backup.data;
 
     blk = blk_by_name(backup->device);
     if (!blk) {
@@ -2029,7 +2029,7 @@
         return;
     }
 
-    action = common->action->u.block_dirty_bitmap_add;
+    action = common->action->u.block_dirty_bitmap_add.data;
     /* AIO context taken and released within qmp_block_dirty_bitmap_add */
     qmp_block_dirty_bitmap_add(action->node, action->name,
                                action->has_granularity, action->granularity,
@@ -2048,7 +2048,7 @@
     BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
                                              common, common);
 
-    action = common->action->u.block_dirty_bitmap_add;
+    action = common->action->u.block_dirty_bitmap_add.data;
     /* Should not be able to fail: IF the bitmap was added via .prepare(),
      * then the node reference and bitmap name must have been valid.
      */
@@ -2068,7 +2068,7 @@
         return;
     }
 
-    action = common->action->u.block_dirty_bitmap_clear;
+    action = common->action->u.block_dirty_bitmap_clear.data;
     state->bitmap = block_dirty_bitmap_lookup(action->node,
                                               action->name,
                                               &state->bs,
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index e0b2ef1..0e4baff 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -284,7 +284,7 @@
 === Union types ===
 
 Usage: { 'union': STRING, 'data': DICT }
-or:    { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
+or:    { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME-OR-DICT,
          'discriminator': ENUM-MEMBER-OF-BASE }
 
 Union types are used to let the user choose between several different
@@ -297,22 +297,22 @@
 A simple union type defines a mapping from automatic discriminator
 values to data types like in this example:
 
- { 'struct': 'FileOptions', 'data': { 'filename': 'str' } }
- { 'struct': 'Qcow2Options',
-   'data': { 'backing-file': 'str', 'lazy-refcounts': 'bool' } }
+ { 'struct': 'BlockdevOptionsFile', 'data': { 'filename': 'str' } }
+ { 'struct': 'BlockdevOptionsQcow2',
+   'data': { 'backing': 'str', '*lazy-refcounts': 'bool' } }
 
- { 'union': 'BlockdevOptions',
-   'data': { 'file': 'FileOptions',
-             'qcow2': 'Qcow2Options' } }
+ { 'union': 'BlockdevOptionsSimple',
+   'data': { 'file': 'BlockdevOptionsFile',
+             'qcow2': 'BlockdevOptionsQcow2' } }
 
 In the Client JSON Protocol, a simple union is represented by a
 dictionary that contains the 'type' member as a discriminator, and a
 'data' member that is of the specified data type corresponding to the
 discriminator value, as in these examples:
 
- { "type": "file", "data" : { "filename": "/some/place/my-image" } }
- { "type": "qcow2", "data" : { "backing-file": "/some/place/my-image",
-                               "lazy-refcounts": true } }
+ { "type": "file", "data": { "filename": "/some/place/my-image" } }
+ { "type": "qcow2", "data": { "backing": "/some/place/my-image",
+                              "lazy-refcounts": true } }
 
 The generated C code uses a struct containing a union. Additionally,
 an implicit C enum 'NameKind' is created, corresponding to the union
@@ -320,34 +320,35 @@
 the union can be named 'max', as this would collide with the implicit
 enum.  The value for each branch can be of any type.
 
-A flat union definition specifies a struct as its base, and
-avoids nesting on the wire.  All branches of the union must be
-complex types, and the top-level members of the union dictionary on
-the wire will be combination of members from both the base type and the
-appropriate branch type (when merging two dictionaries, there must be
-no keys in common).  The 'discriminator' member must be the name of an
-enum-typed member of the base struct.
+A flat union definition avoids nesting on the wire, and specifies a
+set of common members that occur in all variants of the union.  The
+'base' key must specifiy either a type name (the type must be a
+struct, not a union), or a dictionary representing an anonymous type.
+All branches of the union must be complex types, and the top-level
+members of the union dictionary on the wire will be combination of
+members from both the base type and the appropriate branch type (when
+merging two dictionaries, there must be no keys in common).  The
+'discriminator' member must be the name of a non-optional enum-typed
+member of the base struct.
 
 The following example enhances the above simple union example by
-adding a common member 'readonly', renaming the discriminator to
-something more applicable, and reducing the number of {} required on
-the wire:
+adding an optional common member 'read-only', renaming the
+discriminator to something more applicable than the simple union's
+default of 'type', and reducing the number of {} required on the wire:
 
  { 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] }
- { 'struct': 'BlockdevCommonOptions',
-   'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
  { 'union': 'BlockdevOptions',
-   'base': 'BlockdevCommonOptions',
+   'base': { 'driver': 'BlockdevDriver', '*read-only': 'bool' },
    'discriminator': 'driver',
-   'data': { 'file': 'FileOptions',
-             'qcow2': 'Qcow2Options' } }
+   'data': { 'file': 'BlockdevOptionsFile',
+             'qcow2': 'BlockdevOptionsQcow2' } }
 
 Resulting in these JSON objects:
 
- { "driver": "file", "readonly": true,
+ { "driver": "file", "read-only": true,
    "filename": "/some/place/my-image" }
- { "driver": "qcow2", "readonly": false,
-   "backing-file": "/some/place/my-image", "lazy-refcounts": true }
+ { "driver": "qcow2", "read-only": false,
+   "backing": "/some/place/my-image", "lazy-refcounts": true }
 
 Notice that in a flat union, the discriminator name is controlled by
 the user, but because it must map to a base member with enum type, the
@@ -366,10 +367,9 @@
 is identical on the wire to:
 
  { 'enum': 'Enum', 'data': ['one', 'two'] }
- { 'struct': 'Base', 'data': { 'type': 'Enum' } }
  { 'struct': 'Branch1', 'data': { 'data': 'str' } }
  { 'struct': 'Branch2', 'data': { 'data': 'int' } }
- { 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
+ { 'union': 'Flat': 'base': { 'type': 'Enum' }, 'discriminator': 'type',
    'data': { 'one': 'Branch1', 'two': 'Branch2' } }
 
 
@@ -382,7 +382,7 @@
 array) on the wire.  The definition is similar to a simple union type,
 where each branch of the union names a QAPI type.  For example:
 
- { 'alternate': 'BlockRef',
+ { 'alternate': 'BlockdevRef',
    'data': { 'definition': 'BlockdevOptions',
              'reference': 'str' } }
 
@@ -403,7 +403,7 @@
 
  { "file": "my_existing_block_device_id" }
  { "file": { "driver": "file",
-             "readonly": false,
+             "read-only": false,
              "filename": "/tmp/mydisk.qcow2" } }
 
 
@@ -575,9 +575,9 @@
 Example: the SchemaInfo for command query-qmp-schema
 
     { "name": "query-qmp-schema", "meta-type": "command",
-      "arg-type": ":empty", "ret-type": "SchemaInfoList" }
+      "arg-type": "q_empty", "ret-type": "SchemaInfoList" }
 
-    Type ":empty" is an object type without members, and type
+    Type "q_empty" is an automatic object type without members, and type
     "SchemaInfoList" is the array of SchemaInfo type.
 
 The SchemaInfo for an event has meta-type "event", and variant member
@@ -594,9 +594,9 @@
 Example: the SchemaInfo for EVENT_C from section Events
 
     { "name": "EVENT_C", "meta-type": "event",
-      "arg-type": ":obj-EVENT_C-arg" }
+      "arg-type": "q_obj-EVENT_C-arg" }
 
-    Type ":obj-EVENT_C-arg" is an implicitly defined object type with
+    Type "q_obj-EVENT_C-arg" is an implicitly defined object type with
     the two members from the event's definition.
 
 The SchemaInfo for struct and union types has meta-type "object".
@@ -637,11 +637,11 @@
     { "name": "BlockdevOptions", "meta-type": "object",
       "members": [
           { "name": "driver", "type": "BlockdevDriver" },
-          { "name": "readonly", "type": "bool"} ],
+          { "name": "read-only", "type": "bool", "default": null } ],
       "tag": "driver",
       "variants": [
-          { "case": "file", "type": "FileOptions" },
-          { "case": "qcow2", "type": "Qcow2Options" } ] }
+          { "case": "file", "type": "BlockdevOptionsFile" },
+          { "case": "qcow2", "type": "BlockdevOptionsQcow2" } ] }
 
 Note that base types are "flattened": its members are included in the
 "members" array.
@@ -652,20 +652,20 @@
 A simple union implicitly defines an object type for each of its
 variants.
 
-Example: the SchemaInfo for simple union BlockdevOptions from section
+Example: the SchemaInfo for simple union BlockdevOptionsSimple from section
 Union types
 
-    { "name": "BlockdevOptions", "meta-type": "object",
+    { "name": "BlockdevOptionsSimple", "meta-type": "object",
       "members": [
-          { "name": "type", "type": "BlockdevOptionsKind" } ],
+          { "name": "type", "type": "BlockdevOptionsSimpleKind" } ],
       "tag": "type",
       "variants": [
-          { "case": "file", "type": ":obj-FileOptions-wrapper" },
-          { "case": "qcow2", "type": ":obj-Qcow2Options-wrapper" } ] }
+          { "case": "file", "type": "q_obj-BlockdevOptionsFile-wrapper" },
+          { "case": "qcow2", "type": "q_obj-BlockdevOptionsQcow2-wrapper" } ] }
 
-    Enumeration type "BlockdevOptionsKind" and the object types
-    ":obj-FileOptions-wrapper", ":obj-Qcow2Options-wrapper" are
-    implicitly defined.
+    Enumeration type "BlockdevOptionsSimpleKind" and the object types
+    "q_obj-BlockdevOptionsFile-wrapper", "q_obj-BlockdevOptionsQcow2-wrapper"
+    are implicitly defined.
 
 The SchemaInfo for an alternate type has meta-type "alternate", and
 variant member "members".  "members" is a JSON array.  Each element is
@@ -673,9 +673,9 @@
 alternate type conform to exactly one of its member types.  There is
 no guarantee on the order in which "members" will be listed.
 
-Example: the SchemaInfo for BlockRef from section Alternate types
+Example: the SchemaInfo for BlockdevRef from section Alternate types
 
-    { "name": "BlockRef", "meta-type": "alternate",
+    { "name": "BlockdevRef", "meta-type": "alternate",
       "members": [
           { "type": "BlockdevOptions" },
           { "type": "str" } ] }
diff --git a/hmp.c b/hmp.c
index 5b6084a..6ace227 100644
--- a/hmp.c
+++ b/hmp.c
@@ -857,7 +857,7 @@
 
         switch (ti->options->type) {
         case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH:
-            tpo = ti->options->u.passthrough;
+            tpo = ti->options->u.passthrough.data;
             monitor_printf(mon, "%s%s%s%s",
                            tpo->has_path ? ",path=" : "",
                            tpo->has_path ? tpo->path : "",
@@ -1753,14 +1753,14 @@
                 goto err_out;
             }
             keylist->value->type = KEY_VALUE_KIND_NUMBER;
-            keylist->value->u.number = value;
+            keylist->value->u.number.data = value;
         } else {
             int idx = index_from_key(keys, keyname_len);
             if (idx == Q_KEY_CODE__MAX) {
                 goto err_out;
             }
             keylist->value->type = KEY_VALUE_KIND_QCODE;
-            keylist->value->u.qcode = idx;
+            keylist->value->u.qcode.data = idx;
         }
 
         if (!separator) {
@@ -1977,7 +1977,7 @@
         if (value) {
             switch (value->type) {
             case MEMORY_DEVICE_INFO_KIND_DIMM:
-                di = value->u.dimm;
+                di = value->u.dimm.data;
 
                 monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
                                MemoryDeviceInfoKind_lookup[value->type],
diff --git a/hw/char/escc.c b/hw/char/escc.c
index c7a24ac..7bf09a0 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -845,7 +845,7 @@
     InputKeyEvent *key;
 
     assert(evt->type == INPUT_EVENT_KIND_KEY);
-    key = evt->u.key;
+    key = evt->u.key.data;
     qcode = qemu_input_key_value_to_qcode(key->key);
     trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
                                key->down);
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 41a9387..5912677 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -124,7 +124,7 @@
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel;
+        move = evt->u.rel.data;
         if (move->axis == INPUT_AXIS_X) {
             e->xdx += move->value;
         } else if (move->axis == INPUT_AXIS_Y) {
@@ -133,7 +133,7 @@
         break;
 
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs;
+        move = evt->u.abs.data;
         if (move->axis == INPUT_AXIS_X) {
             e->xdx = move->value;
         } else if (move->axis == INPUT_AXIS_Y) {
@@ -142,7 +142,7 @@
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn;
+        btn = evt->u.btn.data;
         if (btn->down) {
             e->buttons_state |= bmap[btn->button];
             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
@@ -228,7 +228,7 @@
     HIDState *hs = (HIDState *)dev;
     int scancodes[3], i, count;
     int slot;
-    InputKeyEvent *key = evt->u.key;
+    InputKeyEvent *key = evt->u.key.data;
 
     count = qemu_input_key_value_to_scancode(key->key,
                                              key->down,
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 86df1a0..58892d5 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -182,7 +182,7 @@
 {
     PS2KbdState *s = (PS2KbdState *)dev;
     int scancodes[3], i, count;
-    InputKeyEvent *key = evt->u.key;
+    InputKeyEvent *key = evt->u.key.data;
 
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
     count = qemu_input_key_value_to_scancode(key->key,
@@ -399,7 +399,7 @@
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel;
+        move = evt->u.rel.data;
         if (move->axis == INPUT_AXIS_X) {
             s->mouse_dx += move->value;
         } else if (move->axis == INPUT_AXIS_Y) {
@@ -408,7 +408,7 @@
         break;
 
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn;
+        btn = evt->u.btn.data;
         if (btn->down) {
             s->mouse_buttons |= bmap[btn->button];
             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index e5480c3..5d12157 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -197,7 +197,7 @@
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        key = evt->u.key;
+        key = evt->u.key.data;
         qcode = qemu_input_key_value_to_qcode(key->key);
         if (qcode && keymap_qcode[qcode]) {
             event.type  = cpu_to_le16(EV_KEY);
@@ -212,7 +212,7 @@
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn;
+        btn = evt->u.btn.data;
         if (keymap_button[btn->button]) {
             event.type  = cpu_to_le16(EV_KEY);
             event.code  = cpu_to_le16(keymap_button[btn->button]);
@@ -227,14 +227,14 @@
         }
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel;
+        move = evt->u.rel.data;
         event.type  = cpu_to_le16(EV_REL);
         event.code  = cpu_to_le16(axismap_rel[move->axis]);
         event.value = cpu_to_le32(move->value);
         virtio_input_send(vinput, &event);
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs;
+        move = evt->u.abs.data;
         event.type  = cpu_to_le16(EV_ABS);
         event.code  = cpu_to_le16(axismap_abs[move->axis]);
         event.value = cpu_to_le32(move->value);
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 973bf20..c4b4430 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -180,7 +180,7 @@
                                                NULL);
             di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
 
-            info->u.dimm = di;
+            info->u.dimm.data = di;
             elem->value = info;
             elem->next = NULL;
             **prev = elem;
diff --git a/net/dump.c b/net/dump.c
index 61dec9d..94ac32a 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -189,7 +189,7 @@
     DumpNetClient *dnc;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_DUMP);
-    dump = opts->u.dump;
+    dump = opts->u.dump.data;
 
     assert(peer);
 
diff --git a/net/hub.c b/net/hub.c
index b6d44fd..6d90c6e 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -288,7 +288,7 @@
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT);
     assert(!peer);
-    hubport = opts->u.hubport;
+    hubport = opts->u.hubport.data;
 
     net_hub_add_port(hubport->hubid, name);
     return 0;
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index 824161c..5c668f7 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -546,7 +546,7 @@
     s->header_mismatch = false;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3);
-    l2tpv3 = opts->u.l2tpv3;
+    l2tpv3 = opts->u.l2tpv3.data;
 
     if (l2tpv3->has_ipv6 && l2tpv3->ipv6) {
         s->ipv6 = l2tpv3->ipv6;
diff --git a/net/net.c b/net/net.c
index 73cefbc..1a78edf 100644
--- a/net/net.c
+++ b/net/net.c
@@ -893,7 +893,7 @@
     const NetLegacyNicOptions *nic;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_NIC);
-    nic = opts->u.nic;
+    nic = opts->u.nic.data;
 
     idx = nic_get_free_idx();
     if (idx == -1 || nb_nics >= MAX_NICS) {
@@ -1025,7 +1025,7 @@
 
         /* Do not add to a vlan if it's a nic with a netdev= parameter. */
         if (opts->type != NET_CLIENT_OPTIONS_KIND_NIC ||
-            !opts->u.nic->has_netdev) {
+            !opts->u.nic.data->has_netdev) {
             peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
         }
     }
diff --git a/net/netmap.c b/net/netmap.c
index 1b42728..6fa2c41 100644
--- a/net/netmap.c
+++ b/net/netmap.c
@@ -420,7 +420,7 @@
 int net_init_netmap(const NetClientOptions *opts,
                     const char *name, NetClientState *peer, Error **errp)
 {
-    const NetdevNetmapOptions *netmap_opts = opts->u.netmap;
+    const NetdevNetmapOptions *netmap_opts = opts->u.netmap.data;
     struct nm_desc *nmd;
     NetClientState *nc;
     Error *err = NULL;
diff --git a/net/slirp.c b/net/slirp.c
index 9954160..95239bc 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -814,7 +814,7 @@
     const char **dnssearch;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER);
-    user = opts->u.user;
+    user = opts->u.user.data;
 
     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 73dc49a..9826efb 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -704,7 +704,7 @@
     const NetdevSocketOptions *sock;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
-    sock = opts->u.socket;
+    sock = opts->u.socket.data;
 
     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 38bbac0..f1e142a 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -795,7 +795,7 @@
     const NetdevTapOptions *tap;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = opts->u.tap;
+    tap = opts->u.tap.data;
 
     if (!tap->has_ifname) {
         error_report("tap: no interface name");
diff --git a/net/tap.c b/net/tap.c
index cd7a7fc..8f790d1 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -565,7 +565,7 @@
     int fd, vnet_hdr;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE);
-    bridge = opts->u.bridge;
+    bridge = opts->u.bridge.data;
 
     helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
     br     = bridge->has_br     ? bridge->br     : DEFAULT_BRIDGE_INTERFACE;
@@ -728,7 +728,7 @@
     char ifname[128];
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = opts->u.tap;
+    tap = opts->u.tap.data;
     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 973faf5..9427eaa 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -116,7 +116,7 @@
     const NetdevVdeOptions *vde;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_VDE);
-    vde = opts->u.vde;
+    vde = opts->u.vde.data;
 
     /* 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 58b8dae..1b9e73a 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -306,7 +306,7 @@
     CharDriverState *chr;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
-    vhost_user_opts = opts->u.vhost_user;
+    vhost_user_opts = opts->u.vhost_user.data;
 
     chr = net_vhost_parse_chardev(vhost_user_opts, errp);
     if (!chr) {
diff --git a/numa.c b/numa.c
index da27bf8..572712c 100644
--- a/numa.c
+++ b/numa.c
@@ -228,7 +228,7 @@
 
     switch (object->type) {
     case NUMA_OPTIONS_KIND_NODE:
-        numa_node_parse(object->u.node, opts, &err);
+        numa_node_parse(object->u.node.data, opts, &err);
         if (err) {
             goto error;
         }
@@ -482,7 +482,7 @@
         if (value) {
             switch (value->type) {
             case MEMORY_DEVICE_INFO_KIND_DIMM:
-                node_mem[value->u.dimm->node] += value->u.dimm->size;
+                node_mem[value->u.dimm.data->node] += value->u.dimm.data->size;
                 break;
             default:
                 break;
diff --git a/qapi-schema.json b/qapi-schema.json
index f253a37..88f9b81 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -753,9 +753,9 @@
   'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }
 
 ##
-# @CpuInfoBase:
+# @CpuInfo:
 #
-# Common information about a virtual CPU
+# Information about a virtual CPU
 #
 # @CPU: the index of the virtual CPU
 #
@@ -776,18 +776,10 @@
 # Notes: @halted is a transient state that changes frequently.  By the time the
 #        data is sent to the client, the guest may no longer be halted.
 ##
-{ 'struct': 'CpuInfoBase',
-  'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
-           'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' } }
-
-##
-# @CpuInfo:
-#
-# Information about a virtual CPU
-#
-# Since: 0.14.0
-##
-{ 'union': 'CpuInfo', 'base': 'CpuInfoBase', 'discriminator': 'arch',
+{ 'union': 'CpuInfo',
+  'base': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
+           'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' },
+  'discriminator': 'arch',
   'data': { 'x86': 'CpuInfoX86',
             'sparc': 'CpuInfoSPARC',
             'ppc': 'CpuInfoPPC',
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 9bf1b22..b1cf77d 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1644,57 +1644,6 @@
             'vmdk', 'vpc', 'vvfat' ] }
 
 ##
-# @BlockdevOptionsBase
-#
-# Options that are available for all block devices, independent of the block
-# driver.
-#
-# @driver:        block driver name
-# @id:            #optional id by which the new block device can be referred to.
-#                 This option is only allowed on the top level of blockdev-add.
-#                 A BlockBackend will be created by blockdev-add if and only if
-#                 this option is given.
-# @node-name:     #optional the name of a block driver state node (Since 2.0).
-#                 This option is required on the top level of blockdev-add if
-#                 the @id option is not given there.
-# @discard:       #optional discard-related options (default: ignore)
-# @cache:         #optional cache-related options
-# @aio:           #optional AIO backend (default: threads)
-# @rerror:        #optional how to handle read errors on the device
-#                 (default: report)
-# @werror:        #optional how to handle write errors on the device
-#                 (default: enospc)
-# @read-only:     #optional whether the block device should be read-only
-#                 (default: false)
-# @stats-account-invalid: #optional whether to include invalid
-#                         operations when computing last access statistics
-#                         (default: true) (Since 2.5)
-# @stats-account-failed: #optional whether to include failed
-#                         operations when computing latency and last
-#                         access statistics (default: true) (Since 2.5)
-# @stats-intervals: #optional list of intervals for collecting I/O
-#                   statistics, in seconds (default: none) (Since 2.5)
-# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
-#                 (default: off)
-#
-# Since: 1.7
-##
-{ 'struct': 'BlockdevOptionsBase',
-  'data': { 'driver': 'BlockdevDriver',
-            '*id': 'str',
-            '*node-name': 'str',
-            '*discard': 'BlockdevDiscardOptions',
-            '*cache': 'BlockdevCacheOptions',
-            '*aio': 'BlockdevAioOptions',
-            '*rerror': 'BlockdevOnError',
-            '*werror': 'BlockdevOnError',
-            '*read-only': 'bool',
-            '*stats-account-invalid': 'bool',
-            '*stats-account-failed': 'bool',
-            '*stats-intervals': ['int'],
-            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
-
-##
 # @BlockdevOptionsFile
 #
 # Driver specific block device options for the file backend and similar
@@ -2070,12 +2019,55 @@
 ##
 # @BlockdevOptions
 #
-# Options for creating a block device.
+# Options for creating a block device.  Many options are available for all
+# block devices, independent of the block driver:
+#
+# @driver:        block driver name
+# @id:            #optional id by which the new block device can be referred to.
+#                 This option is only allowed on the top level of blockdev-add.
+#                 A BlockBackend will be created by blockdev-add if and only if
+#                 this option is given.
+# @node-name:     #optional the name of a block driver state node (Since 2.0).
+#                 This option is required on the top level of blockdev-add if
+#                 the @id option is not given there.
+# @discard:       #optional discard-related options (default: ignore)
+# @cache:         #optional cache-related options
+# @aio:           #optional AIO backend (default: threads)
+# @rerror:        #optional how to handle read errors on the device
+#                 (default: report)
+# @werror:        #optional how to handle write errors on the device
+#                 (default: enospc)
+# @read-only:     #optional whether the block device should be read-only
+#                 (default: false)
+# @stats-account-invalid: #optional whether to include invalid
+#                         operations when computing last access statistics
+#                         (default: true) (Since 2.5)
+# @stats-account-failed: #optional whether to include failed
+#                         operations when computing latency and last
+#                         access statistics (default: true) (Since 2.5)
+# @stats-intervals: #optional list of intervals for collecting I/O
+#                   statistics, in seconds (default: none) (Since 2.5)
+# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
+#                 (default: off)
+#
+# Remaining options are determined by the block driver.
 #
 # Since: 1.7
 ##
 { 'union': 'BlockdevOptions',
-  'base': 'BlockdevOptionsBase',
+  'base': { 'driver': 'BlockdevDriver',
+            '*id': 'str',
+            '*node-name': 'str',
+            '*discard': 'BlockdevDiscardOptions',
+            '*cache': 'BlockdevCacheOptions',
+            '*aio': 'BlockdevAioOptions',
+            '*rerror': 'BlockdevOnError',
+            '*werror': 'BlockdevOnError',
+            '*read-only': 'bool',
+            '*stats-account-invalid': 'bool',
+            '*stats-account-failed': 'bool',
+            '*stats-intervals': ['int'],
+            '*detect-zeroes': 'BlockdevDetectZeroesOptions' },
   'discriminator': 'driver',
   'data': {
       'archipelago':'BlockdevOptionsArchipelago',
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 9e9369e..3fd81fb 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -75,16 +75,6 @@
             'command', 'event' ] }
 
 ##
-# @SchemaInfoBase
-#
-# Members common to any @SchemaInfo.
-#
-# Since: 2.5
-##
-{ 'struct': 'SchemaInfoBase',
-  'data': { 'name': 'str', 'meta-type': 'SchemaMetaType' } }
-
-##
 # @SchemaInfo
 #
 # @name: the entity's name, inherited from @base.
@@ -103,7 +93,7 @@
 # Since: 2.5
 ##
 { 'union': 'SchemaInfo',
-  'base': 'SchemaInfoBase',
+  'base': { 'name': 'str', 'meta-type': 'SchemaMetaType' },
   'discriminator': 'meta-type',
   'data': {
       'builtin': 'SchemaInfoBuiltin',
diff --git a/qemu-char.c b/qemu-char.c
index bfcf80d..f90e4c1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -98,16 +98,18 @@
     switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
         return g_strdup_printf("%s%s:%s:%s%s", prefix,
-                               is_telnet ? "telnet" : "tcp", addr->u.inet->host,
-                               addr->u.inet->port, is_listen ? ",server" : "");
+                               is_telnet ? "telnet" : "tcp",
+                               addr->u.inet.data->host,
+                               addr->u.inet.data->port,
+                               is_listen ? ",server" : "");
         break;
     case SOCKET_ADDRESS_KIND_UNIX:
         return g_strdup_printf("%sunix:%s%s", prefix,
-                               addr->u.q_unix->path,
+                               addr->u.q_unix.data->path,
                                is_listen ? ",server" : "");
         break;
     case SOCKET_ADDRESS_KIND_FD:
-        return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd->str,
+        return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
                                is_listen ? ",server" : "");
         break;
     default:
@@ -488,7 +490,7 @@
                                            Error **errp)
 {
     CharDriverState *chr;
-    ChardevCommon *common = backend->u.null;
+    ChardevCommon *common = backend->u.null.data;
 
     chr = qemu_chr_alloc(common, errp);
     if (!chr) {
@@ -789,7 +791,7 @@
                                           ChardevBackend *backend,
                                           ChardevReturn *ret, Error **errp)
 {
-    ChardevMux *mux = backend->u.mux;
+    ChardevMux *mux = backend->u.mux.data;
     CharDriverState *chr, *drv;
     MuxDriver *d;
     ChardevCommon *common = qapi_ChardevMux_base(mux);
@@ -1106,7 +1108,7 @@
                                            ChardevReturn *ret,
                                            Error **errp)
 {
-    ChardevHostdev *opts = backend->u.pipe;
+    ChardevHostdev *opts = backend->u.pipe.data;
     int fd_in, fd_out;
     char *filename_in;
     char *filename_out;
@@ -1188,7 +1190,7 @@
                                             ChardevReturn *ret,
                                             Error **errp)
 {
-    ChardevStdio *opts = backend->u.stdio;
+    ChardevStdio *opts = backend->u.stdio.data;
     CharDriverState *chr;
     struct sigaction act;
     ChardevCommon *common = qapi_ChardevStdio_base(opts);
@@ -1434,7 +1436,7 @@
     PtyCharDriver *s;
     int master_fd, slave_fd;
     char pty_name[PATH_MAX];
-    ChardevCommon *common = backend->u.pty;
+    ChardevCommon *common = backend->u.pty.data;
 
     master_fd = qemu_openpty_raw(&slave_fd, pty_name);
     if (master_fd < 0) {
@@ -2205,7 +2207,7 @@
                                            ChardevReturn *ret,
                                            Error **errp)
 {
-    ChardevHostdev *opts = backend->u.pipe;
+    ChardevHostdev *opts = backend->u.pipe.data;
     const char *filename = opts->device;
     CharDriverState *chr;
     WinCharState *s;
@@ -2251,7 +2253,7 @@
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevCommon *common = backend->u.console;
+    ChardevCommon *common = backend->u.console.data;
     return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE),
                                   common, errp);
 }
@@ -2401,7 +2403,7 @@
     WinStdioCharState *stdio;
     DWORD              dwMode;
     int                is_console = 0;
-    ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio);
+    ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio.data);
 
     chr   = qemu_chr_alloc(common, errp);
     if (!chr) {
@@ -3042,7 +3044,7 @@
     } else {
         tioc = qio_channel_tls_new_client(
             s->ioc, s->tls_creds,
-            s->addr->u.inet->host,
+            s->addr->u.inet.data->host,
             &err);
     }
     if (tioc == NULL) {
@@ -3249,7 +3251,7 @@
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevRingbuf *opts = backend->u.ringbuf;
+    ChardevRingbuf *opts = backend->u.ringbuf.data;
     ChardevCommon *common = qapi_ChardevRingbuf_base(opts);
     CharDriverState *chr;
     RingBufCharDriver *d;
@@ -3546,7 +3548,7 @@
         error_setg(errp, "chardev: file: no filename given");
         return;
     }
-    file = backend->u.file = g_new0(ChardevFile, 1);
+    file = backend->u.file.data = g_new0(ChardevFile, 1);
     qemu_chr_parse_common(opts, qapi_ChardevFile_base(file));
     file->out = g_strdup(path);
 
@@ -3559,7 +3561,7 @@
 {
     ChardevStdio *stdio;
 
-    stdio = backend->u.stdio = g_new0(ChardevStdio, 1);
+    stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1);
     qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio));
     stdio->has_signal = true;
     stdio->signal = qemu_opt_get_bool(opts, "signal", true);
@@ -3576,7 +3578,7 @@
         error_setg(errp, "chardev: serial/tty: no device path given");
         return;
     }
-    serial = backend->u.serial = g_new0(ChardevHostdev, 1);
+    serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
     serial->device = g_strdup(device);
 }
@@ -3593,7 +3595,7 @@
         error_setg(errp, "chardev: parallel: no device path given");
         return;
     }
-    parallel = backend->u.parallel = g_new0(ChardevHostdev, 1);
+    parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
     parallel->device = g_strdup(device);
 }
@@ -3609,7 +3611,7 @@
         error_setg(errp, "chardev: pipe: no device path given");
         return;
     }
-    dev = backend->u.pipe = g_new0(ChardevHostdev, 1);
+    dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1);
     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
     dev->device = g_strdup(device);
 }
@@ -3620,7 +3622,7 @@
     int val;
     ChardevRingbuf *ringbuf;
 
-    ringbuf = backend->u.ringbuf = g_new0(ChardevRingbuf, 1);
+    ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1);
     qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf));
 
     val = qemu_opt_get_size(opts, "size", 0);
@@ -3640,7 +3642,7 @@
         error_setg(errp, "chardev: mux: no chardev given");
         return;
     }
-    mux = backend->u.mux = g_new0(ChardevMux, 1);
+    mux = backend->u.mux.data = g_new0(ChardevMux, 1);
     qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
     mux->chardev = g_strdup(chardev);
 }
@@ -3676,7 +3678,7 @@
         }
     }
 
-    sock = backend->u.socket = g_new0(ChardevSocket, 1);
+    sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
     qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
 
     sock->has_nodelay = true;
@@ -3695,12 +3697,12 @@
     if (path) {
         UnixSocketAddress *q_unix;
         addr->type = SOCKET_ADDRESS_KIND_UNIX;
-        q_unix = addr->u.q_unix = g_new0(UnixSocketAddress, 1);
+        q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
         q_unix->path = g_strdup(path);
     } else {
         addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet = g_new(InetSocketAddress, 1);
-        *addr->u.inet = (InetSocketAddress) {
+        addr->u.inet.data = g_new(InetSocketAddress, 1);
+        *addr->u.inet.data = (InetSocketAddress) {
             .host = g_strdup(host),
             .port = g_strdup(port),
             .has_to = qemu_opt_get(opts, "to"),
@@ -3743,13 +3745,13 @@
         has_local = true;
     }
 
-    udp = backend->u.udp = g_new0(ChardevUdp, 1);
+    udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
     qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
 
     addr = g_new0(SocketAddress, 1);
     addr->type = SOCKET_ADDRESS_KIND_INET;
-    addr->u.inet = g_new(InetSocketAddress, 1);
-    *addr->u.inet = (InetSocketAddress) {
+    addr->u.inet.data = g_new(InetSocketAddress, 1);
+    *addr->u.inet.data = (InetSocketAddress) {
         .host = g_strdup(host),
         .port = g_strdup(port),
         .has_ipv4 = qemu_opt_get(opts, "ipv4"),
@@ -3763,8 +3765,8 @@
         udp->has_local = true;
         addr = g_new0(SocketAddress, 1);
         addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet = g_new(InetSocketAddress, 1);
-        *addr->u.inet = (InetSocketAddress) {
+        addr->u.inet.data = g_new(InetSocketAddress, 1);
+        *addr->u.inet.data = (InetSocketAddress) {
             .host = g_strdup(localaddr),
             .port = g_strdup(localport),
         };
@@ -3851,7 +3853,7 @@
     } else {
         ChardevCommon *cc = g_new0(ChardevCommon, 1);
         qemu_chr_parse_common(opts, cc);
-        backend->u.null = cc; /* Any ChardevCommon member would work */
+        backend->u.null.data = cc; /* Any ChardevCommon member would work */
     }
 
     ret = qmp_chardev_add(bid ? bid : id, backend, errp);
@@ -3863,9 +3865,9 @@
         qapi_free_ChardevBackend(backend);
         qapi_free_ChardevReturn(ret);
         backend = g_new0(ChardevBackend, 1);
-        backend->u.mux = g_new0(ChardevMux, 1);
+        backend->u.mux.data = g_new0(ChardevMux, 1);
         backend->type = CHARDEV_BACKEND_KIND_MUX;
-        backend->u.mux->chardev = g_strdup(bid);
+        backend->u.mux.data->chardev = g_strdup(bid);
         ret = qmp_chardev_add(id, backend, errp);
         if (!ret) {
             chr = qemu_chr_find(bid);
@@ -4194,7 +4196,7 @@
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevFile *file = backend->u.file;
+    ChardevFile *file = backend->u.file.data;
     ChardevCommon *common = qapi_ChardevFile_base(file);
     HANDLE out;
 
@@ -4217,7 +4219,7 @@
                                                 ChardevReturn *ret,
                                                 Error **errp)
 {
-    ChardevHostdev *serial = backend->u.serial;
+    ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
     return qemu_chr_open_win_path(serial->device, common, errp);
 }
@@ -4241,7 +4243,7 @@
                                               ChardevReturn *ret,
                                               Error **errp)
 {
-    ChardevFile *file = backend->u.file;
+    ChardevFile *file = backend->u.file.data;
     ChardevCommon *common = qapi_ChardevFile_base(file);
     int flags, in = -1, out;
 
@@ -4275,7 +4277,7 @@
                                                 ChardevReturn *ret,
                                                 Error **errp)
 {
-    ChardevHostdev *serial = backend->u.serial;
+    ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
     int fd;
 
@@ -4294,7 +4296,7 @@
                                                   ChardevReturn *ret,
                                                   Error **errp)
 {
-    ChardevHostdev *parallel = backend->u.parallel;
+    ChardevHostdev *parallel = backend->u.parallel.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(parallel);
     int fd;
 
@@ -4335,7 +4337,7 @@
 {
     CharDriverState *chr;
     TCPCharDriver *s;
-    ChardevSocket *sock = backend->u.socket;
+    ChardevSocket *sock = backend->u.socket.data;
     SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
     bool is_listen      = sock->has_server  ? sock->server  : true;
@@ -4460,7 +4462,7 @@
                                              ChardevReturn *ret,
                                              Error **errp)
 {
-    ChardevUdp *udp = backend->u.udp;
+    ChardevUdp *udp = backend->u.udp.data;
     ChardevCommon *common = qapi_ChardevUdp_base(udp);
     QIOChannelSocket *sioc = qio_channel_socket_new();
 
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d5f8473..f3528c8 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -377,12 +377,12 @@
     saddr = g_new0(SocketAddress, 1);
     if (sockpath) {
         saddr->type = SOCKET_ADDRESS_KIND_UNIX;
-        saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
-        saddr->u.q_unix->path = g_strdup(sockpath);
+        saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+        saddr->u.q_unix.data->path = g_strdup(sockpath);
     } else {
         InetSocketAddress *inet;
         saddr->type = SOCKET_ADDRESS_KIND_INET;
-        inet = saddr->u.inet = g_new0(InetSocketAddress, 1);
+        inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
         inet->host = g_strdup(bindto);
         if (port) {
             inet->port = g_strdup(port);
diff --git a/replay/replay-input.c b/replay/replay-input.c
index c38af50..2d5d919 100644
--- a/replay/replay-input.c
+++ b/replay/replay-input.c
@@ -54,16 +54,16 @@
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        key = evt->u.key;
+        key = evt->u.key.data;
         replay_put_dword(key->key->type);
 
         switch (key->key->type) {
         case KEY_VALUE_KIND_NUMBER:
-            replay_put_qword(key->key->u.number);
+            replay_put_qword(key->key->u.number.data);
             replay_put_byte(key->down);
             break;
         case KEY_VALUE_KIND_QCODE:
-            replay_put_dword(key->key->u.qcode);
+            replay_put_dword(key->key->u.qcode.data);
             replay_put_byte(key->down);
             break;
         case KEY_VALUE_KIND__MAX:
@@ -72,17 +72,17 @@
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn;
+        btn = evt->u.btn.data;
         replay_put_dword(btn->button);
         replay_put_byte(btn->down);
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel;
+        move = evt->u.rel.data;
         replay_put_dword(move->axis);
         replay_put_qword(move->value);
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs;
+        move = evt->u.abs.data;
         replay_put_dword(move->axis);
         replay_put_qword(move->value);
         break;
@@ -105,17 +105,17 @@
     evt.type = replay_get_dword();
     switch (evt.type) {
     case INPUT_EVENT_KIND_KEY:
-        evt.u.key = &key;
-        evt.u.key->key->type = replay_get_dword();
+        evt.u.key.data = &key;
+        evt.u.key.data->key->type = replay_get_dword();
 
-        switch (evt.u.key->key->type) {
+        switch (evt.u.key.data->key->type) {
         case KEY_VALUE_KIND_NUMBER:
-            evt.u.key->key->u.number = replay_get_qword();
-            evt.u.key->down = replay_get_byte();
+            evt.u.key.data->key->u.number.data = replay_get_qword();
+            evt.u.key.data->down = replay_get_byte();
             break;
         case KEY_VALUE_KIND_QCODE:
-            evt.u.key->key->u.qcode = (QKeyCode)replay_get_dword();
-            evt.u.key->down = replay_get_byte();
+            evt.u.key.data->key->u.qcode.data = (QKeyCode)replay_get_dword();
+            evt.u.key.data->down = replay_get_byte();
             break;
         case KEY_VALUE_KIND__MAX:
             /* keep gcc happy */
@@ -123,19 +123,19 @@
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        evt.u.btn = &btn;
-        evt.u.btn->button = (InputButton)replay_get_dword();
-        evt.u.btn->down = replay_get_byte();
+        evt.u.btn.data = &btn;
+        evt.u.btn.data->button = (InputButton)replay_get_dword();
+        evt.u.btn.data->down = replay_get_byte();
         break;
     case INPUT_EVENT_KIND_REL:
-        evt.u.rel = &rel;
-        evt.u.rel->axis = (InputAxis)replay_get_dword();
-        evt.u.rel->value = replay_get_qword();
+        evt.u.rel.data = &rel;
+        evt.u.rel.data->axis = (InputAxis)replay_get_dword();
+        evt.u.rel.data->value = replay_get_qword();
         break;
     case INPUT_EVENT_KIND_ABS:
-        evt.u.abs = &abs;
-        evt.u.abs->axis = (InputAxis)replay_get_dword();
-        evt.u.abs->value = replay_get_qword();
+        evt.u.abs.data = &abs;
+        evt.u.abs.data->axis = (InputAxis)replay_get_dword();
+        evt.u.abs.data->value = replay_get_qword();
         break;
     case INPUT_EVENT_KIND__MAX:
         /* keep gcc happy */
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index f44e01f..b570069 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -2,7 +2,7 @@
 # QAPI command marshaller generator
 #
 # Copyright IBM, Corp. 2011
-# Copyright (C) 2014-2015 Red Hat, Inc.
+# Copyright (C) 2014-2016 Red Hat, Inc.
 #
 # Authors:
 #  Anthony Liguori <aliguori@us.ibm.com>
@@ -30,10 +30,11 @@
 
     argstr = ''
     if arg_type:
+        assert not arg_type.variants
         for memb in arg_type.members:
             if memb.optional:
-                argstr += 'has_%s, ' % c_name(memb.name)
-            argstr += '%s, ' % c_name(memb.name)
+                argstr += 'arg.has_%s, ' % c_name(memb.name)
+            argstr += 'arg.%s, ' % c_name(memb.name)
 
     lhs = ''
     if ret_type:
@@ -54,72 +55,6 @@
     return ret
 
 
-def gen_marshal_vars(arg_type, ret_type):
-    ret = mcgen('''
-    Error *err = NULL;
-''')
-
-    if ret_type:
-        ret += mcgen('''
-    %(c_type)s retval;
-''',
-                     c_type=ret_type.c_type())
-
-    if arg_type:
-        ret += mcgen('''
-    QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args));
-    QapiDeallocVisitor *qdv;
-    Visitor *v;
-''')
-
-        for memb in arg_type.members:
-            if memb.optional:
-                ret += mcgen('''
-    bool has_%(c_name)s = false;
-''',
-                             c_name=c_name(memb.name))
-            ret += mcgen('''
-    %(c_type)s %(c_name)s = %(c_null)s;
-''',
-                         c_name=c_name(memb.name),
-                         c_type=memb.type.c_type(),
-                         c_null=memb.type.c_null())
-        ret += '\n'
-    else:
-        ret += mcgen('''
-
-    (void)args;
-''')
-
-    return ret
-
-
-def gen_marshal_input_visit(arg_type, dealloc=False):
-    ret = ''
-
-    if not arg_type:
-        return ret
-
-    if dealloc:
-        ret += mcgen('''
-    qmp_input_visitor_cleanup(qiv);
-    qdv = qapi_dealloc_visitor_new();
-    v = qapi_dealloc_get_visitor(qdv);
-''')
-    else:
-        ret += mcgen('''
-    v = qmp_input_get_visitor(qiv);
-''')
-
-    ret += gen_visit_members(arg_type.members, skiperr=dealloc)
-
-    if dealloc:
-        ret += mcgen('''
-    qapi_dealloc_visitor_cleanup(qdv);
-''')
-    return ret
-
-
 def gen_marshal_output(ret_type):
     return mcgen('''
 
@@ -168,15 +103,40 @@
 
 %(proto)s
 {
+    Error *err = NULL;
 ''',
                 proto=gen_marshal_proto(name))
 
-    ret += gen_marshal_vars(arg_type, ret_type)
-    ret += gen_marshal_input_visit(arg_type)
+    if ret_type:
+        ret += mcgen('''
+    %(c_type)s retval;
+''',
+                     c_type=ret_type.c_type())
+
+    if arg_type and arg_type.members:
+        ret += mcgen('''
+    QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args));
+    QapiDeallocVisitor *qdv;
+    Visitor *v;
+    %(c_name)s arg = {0};
+
+    v = qmp_input_get_visitor(qiv);
+    visit_type_%(c_name)s_members(v, &arg, &err);
+    if (err) {
+        goto out;
+    }
+''',
+                     c_name=arg_type.c_name())
+
+    else:
+        ret += mcgen('''
+
+    (void)args;
+''')
+
     ret += gen_call(name, arg_type, ret_type)
 
-    # 'goto out' produced by gen_marshal_input_visit->gen_visit_members()
-    # for each arg_type member, and by gen_call() for ret_type
+    # 'goto out' produced above for arg_type, and by gen_call() for ret_type
     if (arg_type and arg_type.members) or ret_type:
         ret += mcgen('''
 
@@ -185,7 +145,16 @@
     ret += mcgen('''
     error_propagate(errp, err);
 ''')
-    ret += gen_marshal_input_visit(arg_type, dealloc=True)
+    if arg_type and arg_type.members:
+        ret += mcgen('''
+    qmp_input_visitor_cleanup(qiv);
+    qdv = qapi_dealloc_visitor_new();
+    v = qapi_dealloc_get_visitor(qdv);
+    visit_type_%(c_name)s_members(v, &arg, NULL);
+    qapi_dealloc_visitor_cleanup(qdv);
+''',
+                     c_name=arg_type.c_name())
+
     ret += mcgen('''
 }
 ''')
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index fb579dd..9b5c5b5 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -28,7 +28,37 @@
                  proto=gen_event_send_proto(name, arg_type))
 
 
+# Declare and initialize an object 'qapi' using parameters from gen_params()
+def gen_param_var(typ):
+    assert not typ.variants
+    ret = mcgen('''
+    %(c_name)s param = {
+''',
+                c_name=typ.c_name())
+    sep = '        '
+    for memb in typ.members:
+        ret += sep
+        sep = ', '
+        if memb.optional:
+            ret += 'has_' + c_name(memb.name) + sep
+        if memb.type.name == 'str':
+            # Cast away const added in gen_params()
+            ret += '(char *)'
+        ret += c_name(memb.name)
+    ret += mcgen('''
+
+    };
+''')
+    return ret
+
+
 def gen_event_send(name, arg_type):
+    # FIXME: Our declaration of local variables (and of 'errp' in the
+    # parameter list) can collide with exploded members of the event's
+    # data type passed in as parameters.  If this collision ever hits in
+    # practice, we can rename our local variables with a leading _ prefix,
+    # or split the code into a wrapper function that creates a boxed
+    # 'param' object then calls another to do the real work.
     ret = mcgen('''
 
 %(proto)s
@@ -43,11 +73,11 @@
         ret += mcgen('''
     QmpOutputVisitor *qov;
     Visitor *v;
-    QObject *obj;
-
 ''')
+        ret += gen_param_var(arg_type)
 
     ret += mcgen('''
+
     emit = qmp_event_get_func_emit();
     if (!emit) {
         return;
@@ -64,23 +94,18 @@
     v = qmp_output_get_visitor(qov);
 
     visit_start_struct(v, "%(name)s", NULL, 0, &err);
-''',
-                     name=name)
-        ret += gen_err_check()
-        ret += gen_visit_members(arg_type.members, need_cast=True,
-                                 label='out_obj')
-        ret += mcgen('''
-out_obj:
+    if (err) {
+        goto out;
+    }
+    visit_type_%(c_name)s_members(v, &param, &err);
     visit_end_struct(v, err ? NULL : &err);
     if (err) {
         goto out;
     }
 
-    obj = qmp_output_get_qobject(qov);
-    g_assert(obj);
-
-    qdict_put_obj(qmp, "data", obj);
-''')
+    qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
+''',
+                     name=name, c_name=arg_type.c_name())
 
     ret += mcgen('''
     emit(%(c_enum)s, qmp, &err);
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 0306a88..e09c875 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -61,8 +61,7 @@
     ret = ''
     if variants:
         for v in variants.variants:
-            if (isinstance(v.type, QAPISchemaObjectType) and
-                    not v.type.is_implicit()):
+            if isinstance(v.type, QAPISchemaObjectType):
                 ret += gen_object(v.type.name, v.type.base,
                                   v.type.local_members, v.type.variants)
 
@@ -73,12 +72,14 @@
                  c_name=c_name(name))
 
     if base:
-        ret += mcgen('''
+        if not base.is_implicit():
+            ret += mcgen('''
     /* Members inherited from %(c_name)s: */
 ''',
-                     c_name=base.c_name())
+                         c_name=base.c_name())
         ret += gen_struct_members(base.members)
-        ret += mcgen('''
+        if not base.is_implicit():
+            ret += mcgen('''
     /* Own members: */
 ''')
     ret += gen_struct_members(members)
@@ -122,13 +123,10 @@
                 c_name=c_name(variants.tag_member.name))
 
     for var in variants.variants:
-        # Ugly special case for simple union TODO get rid of it
-        simple_union_type = var.simple_union_type()
-        typ = simple_union_type or var.type
         ret += mcgen('''
         %(c_type)s %(c_name)s;
 ''',
-                     c_type=typ.c_type(is_unboxed=not simple_union_type),
+                     c_type=var.type.c_unboxed_type(),
                      c_name=c_name(var.name))
 
     ret += mcgen('''
@@ -177,6 +175,8 @@
         self._btin = None
 
     def visit_begin(self, schema):
+        # gen_object() is recursive, ensure it doesn't visit the empty type
+        objects_seen.add(schema.the_empty_object_type.name)
         self.decl = ''
         self.defn = ''
         self._fwdecl = ''
@@ -193,11 +193,6 @@
         self.decl = self._btin + self.decl
         self._btin = None
 
-    def visit_needed(self, entity):
-        # Visit everything except implicit objects
-        return not (entity.is_implicit() and
-                    isinstance(entity, QAPISchemaObjectType))
-
     def _gen_type_cleanup(self, name):
         self.decl += gen_type_cleanup_decl(name)
         self.defn += gen_type_cleanup(name)
@@ -226,11 +221,18 @@
             self._gen_type_cleanup(name)
 
     def visit_object_type(self, name, info, base, members, variants):
+        # Nothing to do for the special empty builtin
+        if name == 'q_empty':
+            return
         self._fwdecl += gen_fwd_object_or_array(name)
         self.decl += gen_object(name, base, members, variants)
-        if base:
+        if base and not base.is_implicit():
             self.decl += gen_upcast(name, base)
-        self._gen_type_cleanup(name)
+        # TODO Worth changing the visitor signature, so we could
+        # directly use rather than repeat type.is_implicit()?
+        if not name.startswith('q_'):
+            # implicit types won't be directly allocated/freed
+            self._gen_type_cleanup(name)
 
     def visit_alternate_type(self, name, info, variants):
         self._fwdecl += gen_fwd_object_or_array(name)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index a712e9a..c147990 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -51,7 +51,24 @@
                      c_type=base.c_name())
         ret += gen_err_check()
 
-    ret += gen_visit_members(members, prefix='obj->')
+    for memb in members:
+        if memb.optional:
+            ret += mcgen('''
+    if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
+''',
+                         name=memb.name, c_name=c_name(memb.name))
+            push_indent()
+        ret += mcgen('''
+    visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, &err);
+''',
+                     c_type=memb.type.c_name(), name=memb.name,
+                     c_name=c_name(memb.name))
+        ret += gen_err_check()
+        if memb.optional:
+            pop_indent()
+            ret += mcgen('''
+    }
+''')
 
     if variants:
         ret += mcgen('''
@@ -60,29 +77,15 @@
                      c_name=c_name(variants.tag_member.name))
 
         for var in variants.variants:
-            # TODO ugly special case for simple union
-            simple_union_type = var.simple_union_type()
             ret += mcgen('''
     case %(case)s:
+        visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err);
+        break;
 ''',
                          case=c_enum_const(variants.tag_member.type.name,
                                            var.name,
-                                           variants.tag_member.type.prefix))
-            if simple_union_type:
-                ret += mcgen('''
-        visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err);
-''',
-                             c_type=simple_union_type.c_name(),
-                             c_name=c_name(var.name))
-            else:
-                ret += mcgen('''
-        visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err);
-''',
-                             c_type=var.type.c_name(),
-                             c_name=c_name(var.name))
-            ret += mcgen('''
-        break;
-''')
+                                           variants.tag_member.type.prefix),
+                         c_type=var.type.c_name(), c_name=c_name(var.name))
 
         ret += mcgen('''
     default:
@@ -90,8 +93,8 @@
     }
 ''')
 
-    # 'goto out' produced for base, by gen_visit_members() for each member,
-    # and if variants were present
+    # 'goto out' produced for base, for each member, and if variants were
+    # present
     if base or members or variants:
         ret += mcgen('''
 
@@ -215,13 +218,11 @@
 
 
 def gen_visit_object(name, base, members, variants):
-    ret = gen_visit_object_members(name, base, members, variants)
-
     # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
     # *obj, but then visit_type_FOO_members() fails, we should clean up *obj
     # rather than leaving it non-NULL. As currently written, the caller must
     # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
-    ret += mcgen('''
+    return mcgen('''
 
 void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
 {
@@ -245,8 +246,6 @@
 ''',
                  c_name=c_name(name))
 
-    return ret
-
 
 class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
     def __init__(self):
@@ -268,11 +267,6 @@
         self.decl = self._btin + self.decl
         self._btin = None
 
-    def visit_needed(self, entity):
-        # Visit everything except implicit objects
-        return not (entity.is_implicit() and
-                    isinstance(entity, QAPISchemaObjectType))
-
     def visit_enum_type(self, name, info, values, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
@@ -296,9 +290,17 @@
             self.defn += defn
 
     def visit_object_type(self, name, info, base, members, variants):
+        # Nothing to do for the special empty builtin
+        if name == 'q_empty':
+            return
         self.decl += gen_visit_members_decl(name)
-        self.decl += gen_visit_decl(name)
-        self.defn += gen_visit_object(name, base, members, variants)
+        self.defn += gen_visit_object_members(name, base, members, variants)
+        # TODO Worth changing the visitor signature, so we could
+        # directly use rather than repeat type.is_implicit()?
+        if not name.startswith('q_'):
+            # only explicit types need an allocating visit
+            self.decl += gen_visit_decl(name)
+            self.defn += gen_visit_object(name, base, members, variants)
 
     def visit_alternate_type(self, name, info, variants):
         self.decl += gen_visit_decl(name)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6b2aa6e..b13ae47 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -63,12 +63,12 @@
 case_whitelist = [
     # From QMP:
     'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
-    'CpuInfoBase',          # CPU, visible through query-cpu
     'CpuInfoMIPS',          # PC, visible through query-cpu
     'CpuInfoTricore',       # PC, visible through query-cpu
     'QapiErrorClass',       # all members, visible through errors
     'UuidInfo',             # UUID, visible through query-uuid
     'X86CPURegister32',     # all members, visible indirectly through qom-get
+    'q_obj_CpuInfo-base',   # CPU, visible through query-cpu
 ]
 
 enum_types = []
@@ -327,6 +327,8 @@
 
 
 def find_base_members(base):
+    if isinstance(base, dict):
+        return base
     base_struct_define = find_struct(base)
     if not base_struct_define:
         return None
@@ -391,7 +393,8 @@
     # code always prefixes it with the enum name
     if enum_member and membername[0].isdigit():
         membername = 'D' + membername
-    # Reserve the entire 'q_' namespace for c_name()
+    # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
+    # and 'q_obj_*' implicit type names.
     if not valid_name.match(membername) or \
        c_name(membername, False).startswith('q_'):
         raise QAPIExprError(expr_info,
@@ -560,9 +563,10 @@
 
     # Else, it's a flat union.
     else:
-        # The object must have a string member 'base'.
+        # The object must have a string or dictionary 'base'.
         check_type(expr_info, "'base' for union '%s'" % name,
-                   base, allow_metas=['struct'])
+                   base, allow_dict=True, allow_optional=True,
+                   allow_metas=['struct'])
         if not base:
             raise QAPIExprError(expr_info,
                                 "Flat union '%s' must have a base"
@@ -822,11 +826,18 @@
 
 
 class QAPISchemaType(QAPISchemaEntity):
-    def c_type(self, is_param=False, is_unboxed=False):
-        return c_name(self.name) + pointer_suffix
+    # Return the C type for common use.
+    # For the types we commonly box, this is a pointer type.
+    def c_type(self):
+        pass
 
-    def c_null(self):
-        return 'NULL'
+    # Return the C type to be used in a parameter list.
+    def c_param_type(self):
+        return self.c_type()
+
+    # Return the C type to be used where we suppress boxing.
+    def c_unboxed_type(self):
+        return self.c_type()
 
     def json_type(self):
         pass
@@ -843,25 +854,24 @@
 
 
 class QAPISchemaBuiltinType(QAPISchemaType):
-    def __init__(self, name, json_type, c_type, c_null):
+    def __init__(self, name, json_type, c_type):
         QAPISchemaType.__init__(self, name, None)
         assert not c_type or isinstance(c_type, str)
         assert json_type in ('string', 'number', 'int', 'boolean', 'null',
                              'value')
         self._json_type_name = json_type
         self._c_type_name = c_type
-        self._c_null_val = c_null
 
     def c_name(self):
         return self.name
 
-    def c_type(self, is_param=False, is_unboxed=False):
-        if is_param and self.name == 'str':
-            return 'const ' + self._c_type_name
+    def c_type(self):
         return self._c_type_name
 
-    def c_null(self):
-        return self._c_null_val
+    def c_param_type(self):
+        if self.name == 'str':
+            return 'const ' + self._c_type_name
+        return self._c_type_name
 
     def json_type(self):
         return self._json_type_name
@@ -889,16 +899,12 @@
         # See QAPISchema._make_implicit_enum_type()
         return self.name.endswith('Kind')
 
-    def c_type(self, is_param=False, is_unboxed=False):
+    def c_type(self):
         return c_name(self.name)
 
     def member_names(self):
         return [v.name for v in self.values]
 
-    def c_null(self):
-        return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
-                            self.prefix)
-
     def json_type(self):
         return 'string'
 
@@ -921,6 +927,9 @@
     def is_implicit(self):
         return True
 
+    def c_type(self):
+        return c_name(self.name) + pointer_suffix
+
     def json_type(self):
         return 'array'
 
@@ -978,19 +987,20 @@
             m.check_clash(info, seen)
 
     def is_implicit(self):
-        # See QAPISchema._make_implicit_object_type()
-        return self.name[0] == ':'
+        # See QAPISchema._make_implicit_object_type(), as well as
+        # _def_predefineds()
+        return self.name.startswith('q_')
 
     def c_name(self):
-        assert not self.is_implicit()
         return QAPISchemaType.c_name(self)
 
-    def c_type(self, is_param=False, is_unboxed=False):
+    def c_type(self):
         assert not self.is_implicit()
-        if is_unboxed:
-            return c_name(self.name)
         return c_name(self.name) + pointer_suffix
 
+    def c_unboxed_type(self):
+        return c_name(self.name)
+
     def json_type(self):
         return 'object'
 
@@ -1026,12 +1036,14 @@
 
     def _pretty_owner(self):
         owner = self.owner
-        if owner.startswith(':obj-'):
+        if owner.startswith('q_obj_'):
             # See QAPISchema._make_implicit_object_type() - reverse the
             # mapping there to create a nice human-readable description
-            owner = owner[5:]
+            owner = owner[6:]
             if owner.endswith('-arg'):
                 return '(parameter of %s)' % owner[:-4]
+            elif owner.endswith('-base'):
+                return '(base of %s)' % owner[:-5]
             else:
                 assert owner.endswith('-wrapper')
                 # Unreachable and not implemented
@@ -1108,16 +1120,6 @@
     def __init__(self, name, typ):
         QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
 
-    # This function exists to support ugly simple union special cases
-    # TODO get rid of them, and drop the function
-    def simple_union_type(self):
-        if (self.type.is_implicit() and
-                isinstance(self.type, QAPISchemaObjectType)):
-            assert len(self.type.members) == 1
-            assert not self.type.variants
-            return self.type.members[0].type
-        return None
-
 
 class QAPISchemaAlternateType(QAPISchemaType):
     def __init__(self, name, info, variants):
@@ -1139,6 +1141,9 @@
         for v in self.variants.variants:
             v.check_clash(self.info, seen)
 
+    def c_type(self):
+        return c_name(self.name) + pointer_suffix
+
     def json_type(self):
         return 'value'
 
@@ -1219,9 +1224,8 @@
     def lookup_type(self, name):
         return self.lookup_entity(name, QAPISchemaType)
 
-    def _def_builtin_type(self, name, json_type, c_type, c_null):
-        self._def_entity(QAPISchemaBuiltinType(name, json_type,
-                                               c_type, c_null))
+    def _def_builtin_type(self, name, json_type, c_type):
+        self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
         # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
         # qapi-types.h from a single .c, all arrays of builtins must be
         # declared in the first file whether or not they are used.  Nicer
@@ -1230,23 +1234,23 @@
         self._make_array_type(name, None)
 
     def _def_predefineds(self):
-        for t in [('str',    'string',  'char' + pointer_suffix, 'NULL'),
-                  ('number', 'number',  'double',   '0'),
-                  ('int',    'int',     'int64_t',  '0'),
-                  ('int8',   'int',     'int8_t',   '0'),
-                  ('int16',  'int',     'int16_t',  '0'),
-                  ('int32',  'int',     'int32_t',  '0'),
-                  ('int64',  'int',     'int64_t',  '0'),
-                  ('uint8',  'int',     'uint8_t',  '0'),
-                  ('uint16', 'int',     'uint16_t', '0'),
-                  ('uint32', 'int',     'uint32_t', '0'),
-                  ('uint64', 'int',     'uint64_t', '0'),
-                  ('size',   'int',     'uint64_t', '0'),
-                  ('bool',   'boolean', 'bool',     'false'),
-                  ('any',    'value',   'QObject' + pointer_suffix, 'NULL')]:
+        for t in [('str',    'string',  'char' + pointer_suffix),
+                  ('number', 'number',  'double'),
+                  ('int',    'int',     'int64_t'),
+                  ('int8',   'int',     'int8_t'),
+                  ('int16',  'int',     'int16_t'),
+                  ('int32',  'int',     'int32_t'),
+                  ('int64',  'int',     'int64_t'),
+                  ('uint8',  'int',     'uint8_t'),
+                  ('uint16', 'int',     'uint16_t'),
+                  ('uint32', 'int',     'uint32_t'),
+                  ('uint64', 'int',     'uint64_t'),
+                  ('size',   'int',     'uint64_t'),
+                  ('bool',   'boolean', 'bool'),
+                  ('any',    'value',   'QObject' + pointer_suffix)]:
             self._def_builtin_type(*t)
-        self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
-                                                          [], None)
+        self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
+                                                          None, [], None)
         self._def_entity(self.the_empty_object_type)
         qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
                                                 'qstring', 'qdict', 'qlist',
@@ -1274,7 +1278,7 @@
         if not members:
             return None
         # See also QAPISchemaObjectTypeMember._pretty_owner()
-        name = ':obj-%s-%s' % (name, role)
+        name = 'q_obj_%s-%s' % (name, role)
         if not self.lookup_entity(name, QAPISchemaObjectType):
             self._def_entity(QAPISchemaObjectType(name, info, None,
                                                   members, None))
@@ -1326,6 +1330,9 @@
         base = expr.get('base')
         tag_name = expr.get('discriminator')
         tag_member = None
+        if isinstance(base, dict):
+            base = (self._make_implicit_object_type(
+                    name, info, 'base', self._make_members(base, info)))
         if tag_name:
             variants = [self._make_variant(key, value)
                         for (key, value) in data.iteritems()]
@@ -1630,60 +1637,18 @@
         sep = ', '
         if memb.optional:
             ret += 'bool has_%s, ' % c_name(memb.name)
-        ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
+        ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
     if extra:
         ret += sep + extra
     return ret
 
 
-def gen_err_check(label='out', skiperr=False):
-    if skiperr:
-        return ''
+def gen_err_check():
     return mcgen('''
     if (err) {
-        goto %(label)s;
-    }
-''',
-                 label=label)
-
-
-def gen_visit_members(members, prefix='', need_cast=False, skiperr=False,
-                      label='out'):
-    ret = ''
-    if skiperr:
-        errparg = 'NULL'
-    else:
-        errparg = '&err'
-
-    for memb in members:
-        if memb.optional:
-            ret += mcgen('''
-    if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
-''',
-                         prefix=prefix, c_name=c_name(memb.name),
-                         name=memb.name)
-            push_indent()
-
-        # Ugly: sometimes we need to cast away const
-        if need_cast and memb.type.name == 'str':
-            cast = '(char **)'
-        else:
-            cast = ''
-
-        ret += mcgen('''
-    visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
-''',
-                     c_type=memb.type.c_name(), prefix=prefix, cast=cast,
-                     c_name=c_name(memb.name), name=memb.name,
-                     errp=errparg)
-        ret += gen_err_check(skiperr=skiperr, label=label)
-
-        if memb.optional:
-            pop_indent()
-            ret += mcgen('''
+        goto out;
     }
 ''')
-    return ret
 
 
 #
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 21885c5..351fcaa 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -305,9 +305,10 @@
                                                 ChardevReturn *ret,
                                                 Error **errp)
 {
-    const char *type = backend->u.spicevmc->type;
+    ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
+    const char *type = spicevmc->type;
     const char **psubtype = spice_server_char_device_recognized_subtypes();
-    ChardevCommon *common = qapi_ChardevSpiceChannel_base(backend->u.spicevmc);
+    ChardevCommon *common = qapi_ChardevSpiceChannel_base(spicevmc);
 
     for (; *psubtype != NULL; ++psubtype) {
         if (strcmp(type, *psubtype) == 0) {
@@ -329,8 +330,9 @@
                                                  ChardevReturn *ret,
                                                  Error **errp)
 {
-    const char *name = backend->u.spiceport->fqdn;
-    ChardevCommon *common = qapi_ChardevSpicePort_base(backend->u.spiceport);
+    ChardevSpicePort *spiceport = backend->u.spiceport.data;
+    const char *name = spiceport->fqdn;
+    ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
     CharDriverState *chr;
     SpiceCharDriver *s;
 
@@ -372,7 +374,7 @@
         error_setg(errp, "chardev: spice channel: no name given");
         return;
     }
-    spicevmc = backend->u.spicevmc = g_new0(ChardevSpiceChannel, 1);
+    spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1);
     qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc));
     spicevmc->type = g_strdup(name);
 }
@@ -387,7 +389,7 @@
         error_setg(errp, "chardev: spice port: no name given");
         return;
     }
-    spiceport = backend->u.spiceport = g_new0(ChardevSpicePort, 1);
+    spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1);
     qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport));
     spiceport->fqdn = g_strdup(name);
 }
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 97be601..5d7c13c 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,4 +1,4 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
+object q_empty
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 6522940..8a5b034 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,3 +1,3 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
+object q_empty
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 6350d64..b6b4134 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,4 +1,4 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 event oops None
+object q_empty
diff --git a/tests/qapi-schema/flat-union-bad-base.err b/tests/qapi-schema/flat-union-bad-base.err
index 79b8a71..bee24a2 100644
--- a/tests/qapi-schema/flat-union-bad-base.err
+++ b/tests/qapi-schema/flat-union-bad-base.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-bad-base.json:9: 'base' for union 'TestUnion' should be a type name
+tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion)
diff --git a/tests/qapi-schema/flat-union-bad-base.json b/tests/qapi-schema/flat-union-bad-base.json
index e2e622b..74dd421 100644
--- a/tests/qapi-schema/flat-union-bad-base.json
+++ b/tests/qapi-schema/flat-union-bad-base.json
@@ -1,5 +1,4 @@
-# we require the base to be an existing struct
-# TODO: should we allow an anonymous inline base type?
+# we allow anonymous base, but enforce no duplicate keys
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
 { 'struct': 'TestTypeA',
@@ -7,7 +6,7 @@
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
 { 'union': 'TestUnion',
-  'base': { 'enum1': 'TestEnum', 'kind': 'str' },
+  'base': { 'enum1': 'TestEnum', 'string': 'str' },
   'discriminator': 'enum1',
   'data': { 'value1': 'TestTypeA',
             'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 453e0b2..382ce2f 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,7 +1,7 @@
-object :empty
-object :obj-fooA-arg
-    member bar1: str optional=False
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
-command fooA :obj-fooA-arg -> None
+command fooA q_obj_fooA-arg -> None
    gen=True success_response=True
+object q_empty
+object q_obj_fooA-arg
+    member bar1: str optional=False
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index 97be601..5d7c13c 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -1,4 +1,4 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
+object q_empty
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 97be601..5d7c13c 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,4 +1,4 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
+object q_empty
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 97be601..5d7c13c 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,4 +1,4 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
+object q_empty
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index ce37ff5..ae3293a 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,7 +1,7 @@
-object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 command eins None -> None
    gen=True success_response=True
+object q_empty
 command zwei None -> 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 728659e..f571e1b 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -18,6 +18,8 @@
 { 'struct': 'Empty1', 'data': { } }
 { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
 
+{ 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
+
 # for testing override of default naming heuristic
 { 'enum': 'QEnumTwo',
   'prefix': 'QENUM_TWO',
@@ -73,14 +75,10 @@
   'base': 'UserDefZero',
   'data': { 'string': 'str', 'enum1': 'EnumOne' } }
 
-{ 'struct': 'UserDefUnionBase2',
-  'base': 'UserDefZero',
-  'data': { 'string': 'str', 'enum1': 'QEnumTwo' } }
-
 # this variant of UserDefFlatUnion defaults to a union that uses members with
 # allocated types to test corner cases in the cleanup/dealloc visitor
 { 'union': 'UserDefFlatUnion2',
-  'base': 'UserDefUnionBase2',
+  'base': { '*integer': 'int', 'string': 'str', 'enum1': 'QEnumTwo' },
   'discriminator': 'enum1',
   'data': { 'value1' : 'UserDefC', # intentional forward reference
             'value2' : 'UserDefB' } }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index f5e2a73..19cd214 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,58 +1,3 @@
-object :empty
-object :obj-EVENT_C-arg
-    member a: int optional=True
-    member b: UserDefOne optional=True
-    member c: str optional=False
-object :obj-EVENT_D-arg
-    member a: EventStructOne optional=False
-    member b: str optional=False
-    member c: str optional=True
-    member enum3: EnumOne optional=True
-object :obj-__org.qemu_x-command-arg
-    member a: __org.qemu_x-EnumList optional=False
-    member b: __org.qemu_x-StructList optional=False
-    member c: __org.qemu_x-Union2 optional=False
-    member d: __org.qemu_x-Alt optional=False
-object :obj-anyList-wrapper
-    member data: anyList optional=False
-object :obj-boolList-wrapper
-    member data: boolList optional=False
-object :obj-guest-get-time-arg
-    member a: int optional=False
-    member b: int optional=True
-object :obj-guest-sync-arg
-    member arg: any optional=False
-object :obj-int16List-wrapper
-    member data: int16List optional=False
-object :obj-int32List-wrapper
-    member data: int32List optional=False
-object :obj-int64List-wrapper
-    member data: int64List optional=False
-object :obj-int8List-wrapper
-    member data: int8List optional=False
-object :obj-intList-wrapper
-    member data: intList optional=False
-object :obj-numberList-wrapper
-    member data: numberList optional=False
-object :obj-sizeList-wrapper
-    member data: sizeList optional=False
-object :obj-str-wrapper
-    member data: str optional=False
-object :obj-strList-wrapper
-    member data: strList optional=False
-object :obj-uint16List-wrapper
-    member data: uint16List optional=False
-object :obj-uint32List-wrapper
-    member data: uint32List optional=False
-object :obj-uint64List-wrapper
-    member data: uint64List optional=False
-object :obj-uint8List-wrapper
-    member data: uint8List optional=False
-object :obj-user_def_cmd1-arg
-    member ud1a: UserDefOne optional=False
-object :obj-user_def_cmd2-arg
-    member ud1a: UserDefOne optional=False
-    member ud1b: UserDefOne optional=True
 alternate AltIntNum
     case i: int
     case n: number
@@ -73,8 +18,8 @@
     case n: number
 event EVENT_A None
 event EVENT_B None
-event EVENT_C :obj-EVENT_C-arg
-event EVENT_D :obj-EVENT_D-arg
+event EVENT_C q_obj_EVENT_C-arg
+event EVENT_D q_obj_EVENT_D-arg
 object Empty1
 object Empty2
     base Empty1
@@ -121,26 +66,26 @@
     case value2: UserDefB
     case value3: UserDefB
 object UserDefFlatUnion2
-    base UserDefUnionBase2
+    base q_obj_UserDefFlatUnion2-base
     tag enum1
     case value1: UserDefC
     case value2: UserDefB
 object UserDefNativeListUnion
     member type: UserDefNativeListUnionKind optional=False
-    case integer: :obj-intList-wrapper
-    case s8: :obj-int8List-wrapper
-    case s16: :obj-int16List-wrapper
-    case s32: :obj-int32List-wrapper
-    case s64: :obj-int64List-wrapper
-    case u8: :obj-uint8List-wrapper
-    case u16: :obj-uint16List-wrapper
-    case u32: :obj-uint32List-wrapper
-    case u64: :obj-uint64List-wrapper
-    case number: :obj-numberList-wrapper
-    case boolean: :obj-boolList-wrapper
-    case string: :obj-strList-wrapper
-    case sizes: :obj-sizeList-wrapper
-    case any: :obj-anyList-wrapper
+    case integer: q_obj_intList-wrapper
+    case s8: q_obj_int8List-wrapper
+    case s16: q_obj_int16List-wrapper
+    case s32: q_obj_int32List-wrapper
+    case s64: q_obj_int64List-wrapper
+    case u8: q_obj_uint8List-wrapper
+    case u16: q_obj_uint16List-wrapper
+    case u32: q_obj_uint32List-wrapper
+    case u64: q_obj_uint64List-wrapper
+    case number: q_obj_numberList-wrapper
+    case boolean: q_obj_boolList-wrapper
+    case string: q_obj_strList-wrapper
+    case sizes: q_obj_sizeList-wrapper
+    case any: q_obj_anyList-wrapper
 enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
 object UserDefOne
     base UserDefZero
@@ -166,10 +111,6 @@
     base UserDefZero
     member string: str optional=False
     member enum1: EnumOne optional=False
-object UserDefUnionBase2
-    base UserDefZero
-    member string: str optional=False
-    member enum1: QEnumTwo optional=False
 object UserDefZero
     member integer: int optional=False
 object WrapAlternate
@@ -189,21 +130,82 @@
     member array: __org.qemu_x-Union1List optional=False
 object __org.qemu_x-Union1
     member type: __org.qemu_x-Union1Kind optional=False
-    case __org.qemu_x-branch: :obj-str-wrapper
+    case __org.qemu_x-branch: q_obj_str-wrapper
 enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
 object __org.qemu_x-Union2
     base __org.qemu_x-Base
     tag __org.qemu_x-member1
     case __org.qemu_x-value: __org.qemu_x-Struct2
-command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
+command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
    gen=True success_response=True
-command guest-get-time :obj-guest-get-time-arg -> int
+command guest-get-time q_obj_guest-get-time-arg -> int
    gen=True success_response=True
-command guest-sync :obj-guest-sync-arg -> any
+command guest-sync q_obj_guest-sync-arg -> any
    gen=True success_response=True
+object q_empty
+object q_obj_EVENT_C-arg
+    member a: int optional=True
+    member b: UserDefOne optional=True
+    member c: str optional=False
+object q_obj_EVENT_D-arg
+    member a: EventStructOne optional=False
+    member b: str optional=False
+    member c: str optional=True
+    member enum3: EnumOne optional=True
+object q_obj_UserDefFlatUnion2-base
+    member integer: int optional=True
+    member string: str optional=False
+    member enum1: QEnumTwo optional=False
+object q_obj___org.qemu_x-command-arg
+    member a: __org.qemu_x-EnumList optional=False
+    member b: __org.qemu_x-StructList optional=False
+    member c: __org.qemu_x-Union2 optional=False
+    member d: __org.qemu_x-Alt optional=False
+object q_obj_anyList-wrapper
+    member data: anyList optional=False
+object q_obj_boolList-wrapper
+    member data: boolList optional=False
+object q_obj_guest-get-time-arg
+    member a: int optional=False
+    member b: int optional=True
+object q_obj_guest-sync-arg
+    member arg: any optional=False
+object q_obj_int16List-wrapper
+    member data: int16List optional=False
+object q_obj_int32List-wrapper
+    member data: int32List optional=False
+object q_obj_int64List-wrapper
+    member data: int64List optional=False
+object q_obj_int8List-wrapper
+    member data: int8List optional=False
+object q_obj_intList-wrapper
+    member data: intList optional=False
+object q_obj_numberList-wrapper
+    member data: numberList optional=False
+object q_obj_sizeList-wrapper
+    member data: sizeList optional=False
+object q_obj_str-wrapper
+    member data: str optional=False
+object q_obj_strList-wrapper
+    member data: strList optional=False
+object q_obj_uint16List-wrapper
+    member data: uint16List optional=False
+object q_obj_uint32List-wrapper
+    member data: uint32List optional=False
+object q_obj_uint64List-wrapper
+    member data: uint64List optional=False
+object q_obj_uint8List-wrapper
+    member data: uint8List optional=False
+object q_obj_user_def_cmd1-arg
+    member ud1a: UserDefOne optional=False
+object q_obj_user_def_cmd2-arg
+    member ud1a: UserDefOne optional=False
+    member ud1b: UserDefOne optional=True
 command user_def_cmd None -> None
    gen=True success_response=True
-command user_def_cmd1 :obj-user_def_cmd1-arg -> None
+command user_def_cmd0 Empty2 -> Empty2
    gen=True success_response=True
-command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
+command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
+   gen=True success_response=True
+command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
    gen=True success_response=True
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index 87018ac..be0c300 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -131,8 +131,8 @@
         SocketAddress *laddr = qio_channel_socket_get_local_address(
             lioc, &error_abort);
 
-        g_free(connect_addr->u.inet->port);
-        connect_addr->u.inet->port = g_strdup(laddr->u.inet->port);
+        g_free(connect_addr->u.inet.data->port);
+        connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
 
         qapi_free_SocketAddress(laddr);
     }
@@ -193,8 +193,8 @@
         SocketAddress *laddr = qio_channel_socket_get_local_address(
             lioc, &error_abort);
 
-        g_free(connect_addr->u.inet->port);
-        connect_addr->u.inet->port = g_strdup(laddr->u.inet->port);
+        g_free(connect_addr->u.inet.data->port);
+        connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
 
         qapi_free_SocketAddress(laddr);
     }
@@ -296,15 +296,15 @@
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
     listen_addr->type = SOCKET_ADDRESS_KIND_INET;
-    listen_addr->u.inet = g_new(InetSocketAddress, 1);
-    *listen_addr->u.inet = (InetSocketAddress) {
+    listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
+    *listen_addr->u.inet.data = (InetSocketAddress) {
         .host = g_strdup("127.0.0.1"),
         .port = NULL, /* Auto-select */
     };
 
     connect_addr->type = SOCKET_ADDRESS_KIND_INET;
-    connect_addr->u.inet = g_new(InetSocketAddress, 1);
-    *connect_addr->u.inet = (InetSocketAddress) {
+    connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
+    *connect_addr->u.inet.data = (InetSocketAddress) {
         .host = g_strdup("127.0.0.1"),
         .port = NULL, /* Filled in later */
     };
@@ -334,15 +334,15 @@
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
     listen_addr->type = SOCKET_ADDRESS_KIND_INET;
-    listen_addr->u.inet = g_new(InetSocketAddress, 1);
-    *listen_addr->u.inet = (InetSocketAddress) {
+    listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
+    *listen_addr->u.inet.data = (InetSocketAddress) {
         .host = g_strdup("::1"),
         .port = NULL, /* Auto-select */
     };
 
     connect_addr->type = SOCKET_ADDRESS_KIND_INET;
-    connect_addr->u.inet = g_new(InetSocketAddress, 1);
-    *connect_addr->u.inet = (InetSocketAddress) {
+    connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
+    *connect_addr->u.inet.data = (InetSocketAddress) {
         .host = g_strdup("::1"),
         .port = NULL, /* Filled in later */
     };
@@ -374,12 +374,12 @@
 
 #define TEST_SOCKET "test-io-channel-socket.sock"
     listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    listen_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    listen_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+    listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
 
     connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    connect_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    connect_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+    connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
 
     test_io_channel(async, listen_addr, connect_addr, true);
 
@@ -423,12 +423,12 @@
     fdsend[2] = testfd;
 
     listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    listen_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    listen_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+    listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
 
     connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    connect_addr->u.q_unix = g_new0(UnixSocketAddress, 1);
-    connect_addr->u.q_unix->path = g_strdup(TEST_SOCKET);
+    connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+    connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
 
     test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
 
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index d6171f2..14a9ebb 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -13,6 +13,11 @@
 {
 }
 
+Empty2 *qmp_user_def_cmd0(Error **errp)
+{
+    return g_new0(Empty2, 1);
+}
+
 void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
 {
 }
@@ -64,7 +69,7 @@
     __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1);
 
     ret->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
-    ret->u.__org_qemu_x_branch = strdup("blah1");
+    ret->u.__org_qemu_x_branch.data = strdup("blah1");
 
     /* Also test that 'wchar-t' was munged to 'q_wchar_t' */
     if (b && b->value && !b->value->has_q_wchar_t) {
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index b05da5b..5941e90 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -477,63 +477,64 @@
     switch (kind) {
     case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
         intList *elem = NULL;
-        for (i = 0, elem = cvalue->u.integer; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.integer.data;
+             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->u.s8; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s8.data; 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->u.s16; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s16.data; 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->u.s32; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s32.data; 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->u.s64; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.s64.data; 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->u.u8; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u8.data; 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->u.u16; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u16.data; 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->u.u32; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u32.data; 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->u.u64; elem; elem = elem->next, i++) {
+        for (i = 0, elem = cvalue->u.u64.data; elem; elem = elem->next, i++) {
             g_assert_cmpint(elem->value, ==, i);
         }
         break;
@@ -635,7 +636,7 @@
     g_assert(cvalue != NULL);
     g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN);
 
-    for (i = 0, elem = cvalue->u.boolean; elem; elem = elem->next, i++) {
+    for (i = 0, elem = cvalue->u.boolean.data; elem; elem = elem->next, i++) {
         g_assert_cmpint(elem->value, ==, (i % 3 == 0) ? 1 : 0);
     }
 
@@ -668,7 +669,7 @@
     g_assert(cvalue != NULL);
     g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING);
 
-    for (i = 0, elem = cvalue->u.string; elem; elem = elem->next, i++) {
+    for (i = 0, elem = cvalue->u.string.data; elem; elem = elem->next, i++) {
         gchar str[8];
         sprintf(str, "%d", i);
         g_assert_cmpstr(elem->value, ==, str);
@@ -705,7 +706,7 @@
     g_assert(cvalue != NULL);
     g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER);
 
-    for (i = 0, elem = cvalue->u.number; elem; elem = elem->next, i++) {
+    for (i = 0, elem = cvalue->u.number.data; 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 a7f8b45..dc35752 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -493,7 +493,7 @@
     int i;
     switch (cvalue->type) {
     case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
-        intList **list = &cvalue->u.integer;
+        intList **list = &cvalue->u.integer.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(intList, 1);
             (*list)->value = i;
@@ -503,7 +503,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S8: {
-        int8List **list = &cvalue->u.s8;
+        int8List **list = &cvalue->u.s8.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int8List, 1);
             (*list)->value = i;
@@ -513,7 +513,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S16: {
-        int16List **list = &cvalue->u.s16;
+        int16List **list = &cvalue->u.s16.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int16List, 1);
             (*list)->value = i;
@@ -523,7 +523,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S32: {
-        int32List **list = &cvalue->u.s32;
+        int32List **list = &cvalue->u.s32.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int32List, 1);
             (*list)->value = i;
@@ -533,7 +533,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_S64: {
-        int64List **list = &cvalue->u.s64;
+        int64List **list = &cvalue->u.s64.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(int64List, 1);
             (*list)->value = i;
@@ -543,7 +543,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U8: {
-        uint8List **list = &cvalue->u.u8;
+        uint8List **list = &cvalue->u.u8.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint8List, 1);
             (*list)->value = i;
@@ -553,7 +553,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U16: {
-        uint16List **list = &cvalue->u.u16;
+        uint16List **list = &cvalue->u.u16.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint16List, 1);
             (*list)->value = i;
@@ -563,7 +563,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U32: {
-        uint32List **list = &cvalue->u.u32;
+        uint32List **list = &cvalue->u.u32.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint32List, 1);
             (*list)->value = i;
@@ -573,7 +573,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_U64: {
-        uint64List **list = &cvalue->u.u64;
+        uint64List **list = &cvalue->u.u64.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(uint64List, 1);
             (*list)->value = i;
@@ -583,7 +583,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: {
-        boolList **list = &cvalue->u.boolean;
+        boolList **list = &cvalue->u.boolean.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(boolList, 1);
             (*list)->value = (i % 3 == 0);
@@ -593,7 +593,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: {
-        strList **list = &cvalue->u.string;
+        strList **list = &cvalue->u.string.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(strList, 1);
             (*list)->value = g_strdup_printf("%d", i);
@@ -603,7 +603,7 @@
         break;
     }
     case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: {
-        numberList **list = &cvalue->u.number;
+        numberList **list = &cvalue->u.number.data;
         for (i = 0; i < 32; i++) {
             *list = g_new0(numberList, 1);
             (*list)->value = (double)i / 3;
diff --git a/tpm.c b/tpm.c
index 9ed708e..9a7c711 100644
--- a/tpm.c
+++ b/tpm.c
@@ -262,7 +262,7 @@
     case TPM_TYPE_PASSTHROUGH:
         res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
         tpo = g_new0(TPMPassthroughOptions, 1);
-        res->options->u.passthrough = tpo;
+        res->options->u.passthrough.data = tpo;
         if (drv->path) {
             tpo->path = g_strdup(drv->path);
             tpo->has_path = true;
diff --git a/ui/console.c b/ui/console.c
index 8027ba7..1fd4ea4 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2069,7 +2069,7 @@
 static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
                                 ChardevReturn *ret, Error **errp)
 {
-    return vc_handler(backend->u.vc, errp);
+    return vc_handler(backend->u.vc.data, errp);
 }
 
 void register_vc_handler(VcHandler *handler)
@@ -2111,7 +2111,7 @@
     int val;
     ChardevVC *vc;
 
-    vc = backend->u.vc = g_new0(ChardevVC, 1);
+    vc = backend->u.vc.data = g_new0(ChardevVC, 1);
     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
 
     val = qemu_opt_get_number(opts, "width", 0);
diff --git a/ui/input-keymap.c b/ui/input-keymap.c
index fd2c09d..f1e700d 100644
--- a/ui/input-keymap.c
+++ b/ui/input-keymap.c
@@ -141,10 +141,10 @@
 int qemu_input_key_value_to_number(const KeyValue *value)
 {
     if (value->type == KEY_VALUE_KIND_QCODE) {
-        return qcode_to_number[value->u.qcode];
+        return qcode_to_number[value->u.qcode.data];
     } else {
         assert(value->type == KEY_VALUE_KIND_NUMBER);
-        return value->u.number;
+        return value->u.number.data;
     }
 }
 
@@ -168,10 +168,10 @@
 int qemu_input_key_value_to_qcode(const KeyValue *value)
 {
     if (value->type == KEY_VALUE_KIND_QCODE) {
-        return value->u.qcode;
+        return value->u.qcode.data;
     } else {
         assert(value->type == KEY_VALUE_KIND_NUMBER);
-        return qemu_input_key_number_to_qcode(value->u.number);
+        return qemu_input_key_number_to_qcode(value->u.number.data);
     }
 }
 
@@ -182,7 +182,7 @@
     int count = 0;
 
     if (value->type == KEY_VALUE_KIND_QCODE &&
-        value->u.qcode == Q_KEY_CODE_PAUSE) {
+        value->u.qcode.data == 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 f1c5cb4a..7159747 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -110,7 +110,7 @@
 {
     QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev;
     int scancodes[3], i, count;
-    InputKeyEvent *key = evt->u.key;
+    InputKeyEvent *key = evt->u.key.data;
 
     if (!entry || !entry->put_kbd) {
         return;
@@ -156,7 +156,7 @@
 
     switch (evt->type) {
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn;
+        btn = evt->u.btn.data;
         if (btn->down) {
             s->buttons |= bmap[btn->button];
         } else {
@@ -178,11 +178,11 @@
         }
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs;
+        move = evt->u.abs.data;
         s->axis[move->axis] = move->value;
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel;
+        move = evt->u.rel.data;
         s->axis[move->axis] += move->value;
         break;
     default:
diff --git a/ui/input.c b/ui/input.c
index b035f86..ed88cda 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -166,7 +166,7 @@
 
 static void qemu_input_transform_abs_rotate(InputEvent *evt)
 {
-    InputMoveEvent *move = evt->u.abs;
+    InputMoveEvent *move = evt->u.abs.data;
     switch (graphic_rotate) {
     case 90:
         if (move->axis == INPUT_AXIS_X) {
@@ -203,16 +203,16 @@
     }
     switch (evt->type) {
     case INPUT_EVENT_KIND_KEY:
-        key = evt->u.key;
+        key = evt->u.key.data;
         switch (key->key->type) {
         case KEY_VALUE_KIND_NUMBER:
-            qcode = qemu_input_key_number_to_qcode(key->key->u.number);
+            qcode = qemu_input_key_number_to_qcode(key->key->u.number.data);
             name = QKeyCode_lookup[qcode];
-            trace_input_event_key_number(idx, key->key->u.number,
+            trace_input_event_key_number(idx, key->key->u.number.data,
                                          name, key->down);
             break;
         case KEY_VALUE_KIND_QCODE:
-            name = QKeyCode_lookup[key->key->u.qcode];
+            name = QKeyCode_lookup[key->key->u.qcode.data];
             trace_input_event_key_qcode(idx, name, key->down);
             break;
         case KEY_VALUE_KIND__MAX:
@@ -221,17 +221,17 @@
         }
         break;
     case INPUT_EVENT_KIND_BTN:
-        btn = evt->u.btn;
+        btn = evt->u.btn.data;
         name = InputButton_lookup[btn->button];
         trace_input_event_btn(idx, name, btn->down);
         break;
     case INPUT_EVENT_KIND_REL:
-        move = evt->u.rel;
+        move = evt->u.rel.data;
         name = InputAxis_lookup[move->axis];
         trace_input_event_rel(idx, name, move->value);
         break;
     case INPUT_EVENT_KIND_ABS:
-        move = evt->u.abs;
+        move = evt->u.abs.data;
         name = InputAxis_lookup[move->axis];
         trace_input_event_abs(idx, name, move->value);
         break;
@@ -366,10 +366,10 @@
 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
 {
     InputEvent *evt = g_new0(InputEvent, 1);
-    evt->u.key = g_new0(InputKeyEvent, 1);
+    evt->u.key.data = g_new0(InputKeyEvent, 1);
     evt->type = INPUT_EVENT_KIND_KEY;
-    evt->u.key->key = key;
-    evt->u.key->down = down;
+    evt->u.key.data->key = key;
+    evt->u.key.data->down = down;
     return evt;
 }
 
@@ -391,7 +391,7 @@
 {
     KeyValue *key = g_new0(KeyValue, 1);
     key->type = KEY_VALUE_KIND_NUMBER;
-    key->u.number = num;
+    key->u.number.data = num;
     qemu_input_event_send_key(src, key, down);
 }
 
@@ -399,7 +399,7 @@
 {
     KeyValue *key = g_new0(KeyValue, 1);
     key->type = KEY_VALUE_KIND_QCODE;
-    key->u.qcode = q;
+    key->u.qcode.data = q;
     qemu_input_event_send_key(src, key, down);
 }
 
@@ -416,10 +416,10 @@
 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
 {
     InputEvent *evt = g_new0(InputEvent, 1);
-    evt->u.btn = g_new0(InputBtnEvent, 1);
+    evt->u.btn.data = g_new0(InputBtnEvent, 1);
     evt->type = INPUT_EVENT_KIND_BTN;
-    evt->u.btn->button = btn;
-    evt->u.btn->down = down;
+    evt->u.btn.data->button = btn;
+    evt->u.btn.data->down = down;
     return evt;
 }
 
@@ -470,7 +470,7 @@
     InputMoveEvent *move = g_new0(InputMoveEvent, 1);
 
     evt->type = kind;
-    evt->u.rel = move; /* evt->u.rel is the same as evt->u.abs */
+    evt->u.rel.data = move; /* evt->u.rel is the same as evt->u.abs */
     move->axis = axis;
     move->value = value;
     return evt;
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 13a59f5..56e45e3 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -513,7 +513,8 @@
         error_setg(errp, "Not an inet socket type");
         return NULL;
     }
-    ret = g_strdup_printf("%s;%s", addr->u.inet->host, addr->u.inet->port);
+    ret = g_strdup_printf("%s;%s", addr->u.inet.data->host,
+                          addr->u.inet.data->port);
     qapi_free_SocketAddress(addr);
     return ret;
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index 9494a19..6d39ddd 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -112,9 +112,9 @@
 {
     switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        info->host = g_strdup(addr->u.inet->host);
-        info->service = g_strdup(addr->u.inet->port);
-        if (addr->u.inet->ipv6) {
+        info->host = g_strdup(addr->u.inet.data->host);
+        info->service = g_strdup(addr->u.inet.data->port);
+        if (addr->u.inet.data->ipv6) {
             info->family = NETWORK_ADDRESS_FAMILY_IPV6;
         } else {
             info->family = NETWORK_ADDRESS_FAMILY_IPV4;
@@ -123,7 +123,7 @@
 
     case SOCKET_ADDRESS_KIND_UNIX:
         info->host = g_strdup("");
-        info->service = g_strdup(addr->u.q_unix->path);
+        info->service = g_strdup(addr->u.q_unix.data->path);
         info->family = NETWORK_ADDRESS_FAMILY_UNIX;
         break;
 
@@ -385,9 +385,9 @@
 
         switch (addr->type) {
         case SOCKET_ADDRESS_KIND_INET:
-            info->host = g_strdup(addr->u.inet->host);
-            info->service = g_strdup(addr->u.inet->port);
-            if (addr->u.inet->ipv6) {
+            info->host = g_strdup(addr->u.inet.data->host);
+            info->service = g_strdup(addr->u.inet.data->port);
+            if (addr->u.inet.data->ipv6) {
                 info->family = NETWORK_ADDRESS_FAMILY_IPV6;
             } else {
                 info->family = NETWORK_ADDRESS_FAMILY_IPV4;
@@ -396,7 +396,7 @@
 
         case SOCKET_ADDRESS_KIND_UNIX:
             info->host = g_strdup("");
-            info->service = g_strdup(addr->u.q_unix->path);
+            info->service = g_strdup(addr->u.q_unix.data->path);
             info->family = NETWORK_ADDRESS_FAMILY_UNIX;
             break;
 
@@ -3192,7 +3192,8 @@
         qapi_free_SocketAddress(addr);
         return NULL;
     }
-    ret = g_strdup_printf("%s;%s", addr->u.inet->host, addr->u.inet->port);
+    ret = g_strdup_printf("%s;%s", addr->u.inet.data->host,
+                          addr->u.inet.data->port);
     qapi_free_SocketAddress(addr);
 
     return ret;
@@ -3524,8 +3525,8 @@
 
         if (strncmp(vnc, "unix:", 5) == 0) {
             saddr->type = SOCKET_ADDRESS_KIND_UNIX;
-            saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
-            saddr->u.q_unix->path = g_strdup(vnc + 5);
+            saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+            saddr->u.q_unix.data->path = g_strdup(vnc + 5);
 
             if (vs->ws_enabled) {
                 error_setg(errp, "UNIX sockets not supported with websock");
@@ -3535,7 +3536,7 @@
             unsigned long long baseport;
             InetSocketAddress *inet;
             saddr->type = SOCKET_ADDRESS_KIND_INET;
-            inet = saddr->u.inet = g_new0(InetSocketAddress, 1);
+            inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
             if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
                 inet->host = g_strndup(vnc + 1, hlen - 2);
             } else {
@@ -3564,8 +3565,8 @@
 
             if (vs->ws_enabled) {
                 wsaddr->type = SOCKET_ADDRESS_KIND_INET;
-                inet = wsaddr->u.inet = g_new0(InetSocketAddress, 1);
-                inet->host = g_strdup(saddr->u.inet->host);
+                inet = wsaddr->u.inet.data = g_new0(InetSocketAddress, 1);
+                inet->host = g_strdup(saddr->u.inet.data->host);
                 inet->port = g_strdup(websocket);
 
                 if (to) {
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index fd37ac2..540649a 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -901,8 +901,8 @@
             goto fail;
         } else {
             addr->type = SOCKET_ADDRESS_KIND_UNIX;
-            addr->u.q_unix = g_new(UnixSocketAddress, 1);
-            addr->u.q_unix->path = g_strdup(str + 5);
+            addr->u.q_unix.data = g_new(UnixSocketAddress, 1);
+            addr->u.q_unix.data->path = g_strdup(str + 5);
         }
     } else if (strstart(str, "fd:", NULL)) {
         if (str[3] == '\0') {
@@ -910,13 +910,13 @@
             goto fail;
         } else {
             addr->type = SOCKET_ADDRESS_KIND_FD;
-            addr->u.fd = g_new(String, 1);
-            addr->u.fd->str = g_strdup(str + 3);
+            addr->u.fd.data = g_new(String, 1);
+            addr->u.fd.data->str = g_strdup(str + 3);
         }
     } else {
         addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet = inet_parse(str, errp);
-        if (addr->u.inet == NULL) {
+        addr->u.inet.data = inet_parse(str, errp);
+        if (addr->u.inet.data == NULL) {
             goto fail;
         }
     }
@@ -934,15 +934,15 @@
 
     switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        fd = inet_connect_saddr(addr->u.inet, errp, callback, opaque);
+        fd = inet_connect_saddr(addr->u.inet.data, errp, callback, opaque);
         break;
 
     case SOCKET_ADDRESS_KIND_UNIX:
-        fd = unix_connect_saddr(addr->u.q_unix, errp, callback, opaque);
+        fd = unix_connect_saddr(addr->u.q_unix.data, errp, callback, opaque);
         break;
 
     case SOCKET_ADDRESS_KIND_FD:
-        fd = monitor_get_fd(cur_mon, addr->u.fd->str, errp);
+        fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp);
         if (fd >= 0 && callback) {
             qemu_set_nonblock(fd);
             callback(fd, NULL, opaque);
@@ -961,15 +961,15 @@
 
     switch (addr->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        fd = inet_listen_saddr(addr->u.inet, 0, false, errp);
+        fd = inet_listen_saddr(addr->u.inet.data, 0, false, errp);
         break;
 
     case SOCKET_ADDRESS_KIND_UNIX:
-        fd = unix_listen_saddr(addr->u.q_unix, false, errp);
+        fd = unix_listen_saddr(addr->u.q_unix.data, false, errp);
         break;
 
     case SOCKET_ADDRESS_KIND_FD:
-        fd = monitor_get_fd(cur_mon, addr->u.fd->str, errp);
+        fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp);
         break;
 
     default:
@@ -984,7 +984,8 @@
 
     switch (remote->type) {
     case SOCKET_ADDRESS_KIND_INET:
-        fd = inet_dgram_saddr(remote->u.inet, local ? local->u.inet : NULL, errp);
+        fd = inet_dgram_saddr(remote->u.inet.data,
+                              local ? local->u.inet.data : NULL, errp);
         break;
 
     default:
@@ -1018,7 +1019,7 @@
 
     addr = g_new0(SocketAddress, 1);
     addr->type = SOCKET_ADDRESS_KIND_INET;
-    inet = addr->u.inet = g_new0(InetSocketAddress, 1);
+    inet = addr->u.inet.data = g_new0(InetSocketAddress, 1);
     inet->host = g_strdup(host);
     inet->port = g_strdup(serv);
     if (sa->ss_family == AF_INET) {
@@ -1042,10 +1043,10 @@
 
     addr = g_new0(SocketAddress, 1);
     addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    addr->u.q_unix = g_new0(UnixSocketAddress, 1);
+    addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
     if (su->sun_path[0]) {
-        addr->u.q_unix->path = g_strndup(su->sun_path,
-                                         sizeof(su->sun_path));
+        addr->u.q_unix.data->path = g_strndup(su->sun_path,
+                                              sizeof(su->sun_path));
     }
 
     return addr;