qapi: Emit structs used as variants in topological order

Right now, we emit the branches of union types as a boxed pointer,
and it suffices to have a forward declaration of the type. However,
a future patch will swap things to directly use the branch type,
instead of hiding it behind a pointer. For this to work, the
compiler needs the full definition of the type, not just a forward
declaration, prior to the union that is including the branch type.
This patch just adds topological sorting to hoist all types
mentioned in a branch of a union to be fully declared before the
union itself. The sort is always possible, because we do not
allow circular union types that include themselves as a direct
branch (it is, however, still possible to include a branch type
that itself has a pointer to the union, for a type that can
indirectly recursively nest itself - that remains safe, because
that the member of the branch type will remain a pointer, and the
QMP representation of such a type adds another {} for each recurring
layer of the union type).

Backports commit 1de5d4ca0752138034305f3d4e8fe17ef6503569 from qemu
This commit is contained in:
Eric Blake 2018-02-20 16:02:25 -05:00 committed by Lioncash
parent f5c93aa7ab
commit b513481b9a
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -2,7 +2,7 @@
# QAPI types generator
#
# Copyright IBM, Corp. 2011
# Copyright (c) 2013-2015 Red Hat Inc.
# Copyright (c) 2013-2016 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
@ -13,6 +13,10 @@
from qapi import *
# variants must be emitted before their container; track what has already
# been output
objects_seen = set()
def gen_fwd_object_or_array(name):
return mcgen('''
@ -51,7 +55,19 @@ def gen_struct_fields(members):
def gen_object(name, base, members, variants):
ret = mcgen('''
if name in objects_seen:
return ''
objects_seen.add(name)
ret = ''
if variants:
for v in variants.variants:
if (isinstance(v.type, QAPISchemaObjectType) and
not v.type.is_implicit()):
ret += gen_object(v.type.name, v.type.base,
v.type.local_members, v.type.variants)
ret += mcgen('''
struct %(c_name)s {
''',