qapi: Change data type of the FOO_lookup generated for enum FOO

Currently, a FOO_lookup is an array of strings terminated by a NULL
sentinel.

A future patch will generate enums with "holes".  NULL-termination
will cease to work then.

To prepare for that, store the length in the FOO_lookup by wrapping it
in a struct and adding a member for the length.

The sentinel will be dropped next.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20170822132255.23945-13-marcandre.lureau@redhat.com>
[Basically redone]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1503564371-26090-16-git-send-email-armbru@redhat.com>
[Rebased]
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 06e8898..217cff6 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -395,7 +395,7 @@
         host_memory_backend_set_host_nodes,
         NULL, NULL, &error_abort);
     object_class_property_add_enum(oc, "policy", "HostMemPolicy",
-        HostMemPolicy_lookup,
+        &HostMemPolicy_lookup,
         host_memory_backend_get_policy,
         host_memory_backend_set_policy, &error_abort);
     object_class_property_add_str(oc, "id", get_id, set_id, &error_abort);
diff --git a/block.c b/block.c
index 845eff8..b749bd6 100644
--- a/block.c
+++ b/block.c
@@ -1332,7 +1332,7 @@
     detect_zeroes = qemu_opt_get(opts, "detect-zeroes");
     if (detect_zeroes) {
         BlockdevDetectZeroesOptions value =
-            qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
+            qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup,
                             detect_zeroes,
                             BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                             &local_err);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index b370fce..8e385ac 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -169,7 +169,7 @@
         error_setg(errp, "Missing event name for rule");
         return -1;
     }
-    event = qapi_enum_parse(BlkdebugEvent_lookup, event_name, -1, errp);
+    event = qapi_enum_parse(&BlkdebugEvent_lookup, event_name, -1, errp);
     if (event < 0) {
         return -1;
     }
@@ -732,7 +732,7 @@
     struct BlkdebugRule *rule;
     int blkdebug_event;
 
-    blkdebug_event = qapi_enum_parse(BlkdebugEvent_lookup, event, -1, NULL);
+    blkdebug_event = qapi_enum_parse(&BlkdebugEvent_lookup, event, -1, NULL);
     if (blkdebug_event < 0) {
         return -ENOENT;
     }
diff --git a/block/file-posix.c b/block/file-posix.c
index bfef91d..6acbd56 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -437,7 +437,8 @@
     aio_default = (bdrv_flags & BDRV_O_NATIVE_AIO)
                   ? BLOCKDEV_AIO_OPTIONS_NATIVE
                   : BLOCKDEV_AIO_OPTIONS_THREADS;
-    aio = qapi_enum_parse(BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"),
+    aio = qapi_enum_parse(&BlockdevAioOptions_lookup,
+                          qemu_opt_get(opts, "aio"),
                           aio_default, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
@@ -446,7 +447,8 @@
     }
     s->use_linux_aio = (aio == BLOCKDEV_AIO_OPTIONS_NATIVE);
 
-    locking = qapi_enum_parse(OnOffAuto_lookup, qemu_opt_get(opts, "locking"),
+    locking = qapi_enum_parse(&OnOffAuto_lookup,
+                              qemu_opt_get(opts, "locking"),
                               ON_OFF_AUTO_AUTO, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
@@ -1973,7 +1975,7 @@
                           BDRV_SECTOR_SIZE);
     nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
     buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
+    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
                                PREALLOC_MODE_OFF, &local_err);
     g_free(buf);
     if (local_err) {
diff --git a/block/file-win32.c b/block/file-win32.c
index f2a1830..9e02214 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -302,7 +302,7 @@
 
     aio_default = (flags & BDRV_O_NATIVE_AIO) ? BLOCKDEV_AIO_OPTIONS_NATIVE
                                               : BLOCKDEV_AIO_OPTIONS_THREADS;
-    aio = qapi_enum_parse(BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"),
+    aio = qapi_enum_parse(&BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"),
                           aio_default, errp);
 
     switch (aio) {
diff --git a/block/gluster.c b/block/gluster.c
index 29f9427..0f4265a 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -543,7 +543,7 @@
         if (!strcmp(ptr, "tcp")) {
             ptr = "inet";       /* accept legacy "tcp" */
         }
-        type = qapi_enum_parse(SocketAddressType_lookup, ptr, -1, NULL);
+        type = qapi_enum_parse(&SocketAddressType_lookup, ptr, -1, NULL);
         if (type != SOCKET_ADDRESS_TYPE_INET
             && type != SOCKET_ADDRESS_TYPE_UNIX) {
             error_setg(&local_err,
@@ -1000,7 +1000,7 @@
                           BDRV_SECTOR_SIZE);
 
     tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(PreallocMode_lookup, tmp, PREALLOC_MODE_OFF,
+    prealloc = qapi_enum_parse(&PreallocMode_lookup, tmp, PREALLOC_MODE_OFF,
                                &local_err);
     g_free(tmp);
     if (local_err) {
diff --git a/block/parallels.c b/block/parallels.c
index d812210..cce7336 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -68,13 +68,15 @@
     PRL_PREALLOC_MODE__MAX = 2,
 } ParallelsPreallocMode;
 
-static const char *prealloc_mode_lookup[] = {
-    "falloc",
-    "truncate",
-    NULL,
+static QEnumLookup prealloc_mode_lookup = {
+    .array = (const char *const[]) {
+        "falloc",
+        "truncate",
+        NULL,
+    },
+    .size = PRL_PREALLOC_MODE__MAX
 };
 
-
 typedef struct BDRVParallelsState {
     /** Locking is conservative, the lock protects
      *   - image file extending (truncate, fallocate)
@@ -695,7 +697,7 @@
         qemu_opt_get_size_del(opts, PARALLELS_OPT_PREALLOC_SIZE, 0);
     s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS);
     buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE);
-    s->prealloc_mode = qapi_enum_parse(prealloc_mode_lookup, buf,
+    s->prealloc_mode = qapi_enum_parse(&prealloc_mode_lookup, buf,
                                        PRL_PREALLOC_MODE_FALLOCATE,
                                        &local_err);
     g_free(buf);
diff --git a/block/qcow2.c b/block/qcow2.c
index cbe9681..2ec3996 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2915,7 +2915,7 @@
         goto finish;
     }
     buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
+    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
                                PREALLOC_MODE_OFF, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
@@ -3605,7 +3605,7 @@
     }
 
     optstr = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(PreallocMode_lookup, optstr,
+    prealloc = qapi_enum_parse(&PreallocMode_lookup, optstr,
                                PREALLOC_MODE_OFF, &local_err);
     g_free(optstr);
     if (local_err) {
diff --git a/block/quorum.c b/block/quorum.c
index 8d1c9f6..272f9a5 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -912,7 +912,7 @@
     if (!pattern_str) {
         ret = QUORUM_READ_PATTERN_QUORUM;
     } else {
-        ret = qapi_enum_parse(QuorumReadPattern_lookup, pattern_str,
+        ret = qapi_enum_parse(&QuorumReadPattern_lookup, pattern_str,
                               -EINVAL, NULL);
     }
     if (ret < 0) {
diff --git a/blockdev.c b/blockdev.c
index bfb2a95..796beae 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -437,7 +437,7 @@
 
     if (detect_zeroes) {
         *detect_zeroes =
-            qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
+            qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup,
                             qemu_opt_get(opts, "detect-zeroes"),
                             BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                             &local_error);
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 4e82895..36bc856 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -264,7 +264,7 @@
 /* XXX replace with qapi_enum_parse() in future, when we can
  * make that function emit a more friendly error message */
 static int qcrypto_block_luks_name_lookup(const char *name,
-                                          const char *const *map,
+                                          const QEnumLookup *map,
                                           const char *type,
                                           Error **errp)
 {
@@ -279,19 +279,19 @@
 
 #define qcrypto_block_luks_cipher_mode_lookup(name, errp)               \
     qcrypto_block_luks_name_lookup(name,                                \
-                                   QCryptoCipherMode_lookup,            \
+                                   &QCryptoCipherMode_lookup,           \
                                    "Cipher mode",                       \
                                    errp)
 
 #define qcrypto_block_luks_hash_name_lookup(name, errp)                 \
     qcrypto_block_luks_name_lookup(name,                                \
-                                   QCryptoHashAlgorithm_lookup,         \
+                                   &QCryptoHashAlgorithm_lookup,        \
                                    "Hash algorithm",                    \
                                    errp)
 
 #define qcrypto_block_luks_ivgen_name_lookup(name, errp)                \
     qcrypto_block_luks_name_lookup(name,                                \
-                                   QCryptoIVGenAlgorithm_lookup,        \
+                                   &QCryptoIVGenAlgorithm_lookup,       \
                                    "IV generator",                      \
                                    errp)
 
diff --git a/crypto/secret.c b/crypto/secret.c
index 285ab7a..388abd7 100644
--- a/crypto/secret.c
+++ b/crypto/secret.c
@@ -378,7 +378,7 @@
                                    NULL);
     object_class_property_add_enum(oc, "format",
                                    "QCryptoSecretFormat",
-                                   QCryptoSecretFormat_lookup,
+                                   &QCryptoSecretFormat_lookup,
                                    qcrypto_secret_prop_get_format,
                                    qcrypto_secret_prop_set_format,
                                    NULL);
diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
index a896553..3cd4103 100644
--- a/crypto/tlscreds.c
+++ b/crypto/tlscreds.c
@@ -233,7 +233,7 @@
                                   NULL);
     object_class_property_add_enum(oc, "endpoint",
                                    "QCryptoTLSCredsEndpoint",
-                                   QCryptoTLSCredsEndpoint_lookup,
+                                   &QCryptoTLSCredsEndpoint_lookup,
                                    qcrypto_tls_creds_prop_get_endpoint,
                                    qcrypto_tls_creds_prop_set_endpoint,
                                    NULL);
diff --git a/hmp.c b/hmp.c
index 30819fe..cd046c6 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1528,7 +1528,7 @@
     MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
     int val;
 
-    val = qapi_enum_parse(MigrationCapability_lookup, cap, -1, &err);
+    val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
     if (val < 0) {
         goto end;
     }
@@ -1557,7 +1557,7 @@
     Error *err = NULL;
     int val, ret;
 
-    val = qapi_enum_parse(MigrationParameter_lookup, param, -1, &err);
+    val = qapi_enum_parse(&MigrationParameter_lookup, param, -1, &err);
     if (val < 0) {
         goto cleanup;
     }
@@ -1735,7 +1735,7 @@
     } else {
         if (read_only) {
             read_only_mode =
-                qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup,
+                qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
                                 read_only,
                                 BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
             if (err) {
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 7512bd4..1dc80fc 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -587,7 +587,7 @@
 const PropertyInfo qdev_prop_on_off_auto = {
     .name = "OnOffAuto",
     .description = "on/off/auto",
-    .enum_table = OnOffAuto_lookup,
+    .enum_table = &OnOffAuto_lookup,
     .get = get_enum,
     .set = set_enum,
     .set_default_value = set_default_value_enum,
@@ -599,7 +599,7 @@
 
 const PropertyInfo qdev_prop_losttickpolicy = {
     .name  = "LostTickPolicy",
-    .enum_table  = LostTickPolicy_lookup,
+    .enum_table  = &LostTickPolicy_lookup,
     .get   = get_enum,
     .set   = set_enum,
     .set_default_value = set_default_value_enum,
@@ -613,7 +613,7 @@
     .name = "BlockdevOnError",
     .description = "Error handling policy, "
                    "report/ignore/enospc/stop/auto",
-    .enum_table = BlockdevOnError_lookup,
+    .enum_table = &BlockdevOnError_lookup,
     .get = get_enum,
     .set = set_enum,
     .set_default_value = set_default_value_enum,
@@ -627,7 +627,7 @@
     .name = "BiosAtaTranslation",
     .description = "Logical CHS translation algorithm, "
                    "auto/none/lba/large/rechs",
-    .enum_table = BiosAtaTranslation_lookup,
+    .enum_table = &BiosAtaTranslation_lookup,
     .get = get_enum,
     .set = set_enum,
     .set_default_value = set_default_value_enum,
@@ -639,7 +639,7 @@
     .name = "FdcDriveType",
     .description = "FDC drive type, "
                    "144/288/120/none/auto",
-    .enum_table = FloppyDriveType_lookup,
+    .enum_table = &FloppyDriveType_lookup,
     .get = get_enum,
     .set = set_enum,
     .set_default_value = set_default_value_enum,
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index ae31728..0891461 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -249,7 +249,7 @@
 struct PropertyInfo {
     const char *name;
     const char *description;
-    const char * const *enum_table;
+    const QEnumLookup *enum_table;
     int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
     void (*set_default_value)(Object *obj, const Property *prop);
     void (*create)(Object *obj, Property *prop, Error **errp);
diff --git a/include/qapi/util.h b/include/qapi/util.h
index 5e50d0c..a7c3c64 100644
--- a/include/qapi/util.h
+++ b/include/qapi/util.h
@@ -11,8 +11,13 @@
 #ifndef QAPI_UTIL_H
 #define QAPI_UTIL_H
 
-const char *qapi_enum_lookup(const char *const lookup[], int val);
-int qapi_enum_parse(const char * const lookup[], const char *buf,
+typedef struct QEnumLookup {
+    const char *const *array;
+    int size;
+} QEnumLookup;
+
+const char *qapi_enum_lookup(const QEnumLookup *lookup, int val);
+int qapi_enum_parse(const QEnumLookup *lookup, const char *buf,
                     int def, Error **errp);
 
 int parse_qapi_name(const char *name, bool complete);
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 0f3b8cb..62a51a5 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -469,7 +469,7 @@
  * that visit_type_str() must have no unwelcome side effects.
  */
 void visit_type_enum(Visitor *v, const char *name, int *obj,
-                     const char *const strings[], Error **errp);
+                     const QEnumLookup *lookup, Error **errp);
 
 /*
  * Check if visitor is an input visitor.
diff --git a/include/qom/object.h b/include/qom/object.h
index 1b82899..f3e5cff 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1415,14 +1415,14 @@
  */
 void object_property_add_enum(Object *obj, const char *name,
                               const char *typename,
-                              const char * const *strings,
+                              const QEnumLookup *lookup,
                               int (*get)(Object *, Error **),
                               void (*set)(Object *, int, Error **),
                               Error **errp);
 
 void object_class_property_add_enum(ObjectClass *klass, const char *name,
                                     const char *typename,
-                                    const char * const *strings,
+                                    const QEnumLookup *lookup,
                                     int (*get)(Object *, Error **),
                                     void (*set)(Object *, int, Error **),
                                     Error **errp);
diff --git a/migration/global_state.c b/migration/global_state.c
index 8db2f19..dfdaf63 100644
--- a/migration/global_state.c
+++ b/migration/global_state.c
@@ -88,7 +88,7 @@
     s->received = true;
     trace_migrate_global_state_post_load(runstate);
 
-    r = qapi_enum_parse(RunState_lookup, runstate, -1, &local_err);
+    r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
 
     if (r == -1) {
         if (local_err) {
diff --git a/net/filter.c b/net/filter.c
index 1dfd2ca..2fd7d7d 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -179,7 +179,7 @@
                             netfilter_get_netdev_id, netfilter_set_netdev_id,
                             NULL);
     object_property_add_enum(obj, "queue", "NetFilterDirection",
-                             NetFilterDirection_lookup,
+                             &NetFilterDirection_lookup,
                              netfilter_get_direction, netfilter_set_direction,
                              NULL);
     object_property_add_str(obj, "status",
diff --git a/qapi/qapi-util.c b/qapi/qapi-util.c
index 7af2f04..e9b266b 100644
--- a/qapi/qapi-util.c
+++ b/qapi/qapi-util.c
@@ -14,14 +14,14 @@
 #include "qapi/error.h"
 #include "qemu-common.h"
 
-const char *qapi_enum_lookup(const char *const lookup[], int val)
+const char *qapi_enum_lookup(const QEnumLookup *lookup, int val)
 {
-    assert(val >= 0);
+    assert(val >= 0 && val < lookup->size);
 
-    return lookup[val];
+    return lookup->array[val];
 }
 
-int qapi_enum_parse(const char * const lookup[], const char *buf,
+int qapi_enum_parse(const QEnumLookup *lookup, const char *buf,
                     int def, Error **errp)
 {
     int i;
@@ -30,8 +30,8 @@
         return def;
     }
 
-    for (i = 0; lookup[i]; i++) {
-        if (!strcmp(buf, lookup[i])) {
+    for (i = 0; i < lookup->size; i++) {
+        if (!strcmp(buf, lookup->array[i])) {
             return i;
         }
     }
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 30dc85b..3dcb968 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -333,24 +333,26 @@
 }
 
 static void output_type_enum(Visitor *v, const char *name, int *obj,
-                             const char *const strings[], Error **errp)
+                             const QEnumLookup *lookup, Error **errp)
 {
-    int i = 0;
     int value = *obj;
     char *enum_str;
 
-    while (strings[i++] != NULL);
-    if (value < 0 || value >= i - 1) {
+    /*
+     * TODO why is this an error, not an assertion?  If assertion:
+     * delete, and rely on qapi_enum_lookup()
+     */
+    if (value < 0 || value >= lookup->size) {
         error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null");
         return;
     }
 
-    enum_str = (char *)qapi_enum_lookup(strings, value);
+    enum_str = (char *)qapi_enum_lookup(lookup, value);
     visit_type_str(v, name, &enum_str, errp);
 }
 
 static void input_type_enum(Visitor *v, const char *name, int *obj,
-                            const char *const strings[], Error **errp)
+                            const QEnumLookup *lookup, Error **errp)
 {
     Error *local_err = NULL;
     int64_t value;
@@ -362,7 +364,7 @@
         return;
     }
 
-    value = qapi_enum_parse(strings, enum_str, -1, NULL);
+    value = qapi_enum_parse(lookup, enum_str, -1, NULL);
     if (value < 0) {
         error_setg(errp, QERR_INVALID_PARAMETER, enum_str);
         g_free(enum_str);
@@ -374,16 +376,16 @@
 }
 
 void visit_type_enum(Visitor *v, const char *name, int *obj,
-                     const char *const strings[], Error **errp)
+                     const QEnumLookup *lookup, Error **errp)
 {
-    assert(obj && strings);
+    assert(obj && lookup);
     trace_visit_type_enum(v, name, obj);
     switch (v->type) {
     case VISITOR_INPUT:
-        input_type_enum(v, name, obj, strings, errp);
+        input_type_enum(v, name, obj, lookup, errp);
         break;
     case VISITOR_OUTPUT:
-        output_type_enum(v, name, obj, strings, errp);
+        output_type_enum(v, name, obj, lookup, errp);
         break;
     case VISITOR_CLONE:
         /* nothing further to do, scalar value was already copied by
diff --git a/qemu-img.c b/qemu-img.c
index a72a2e3..df984b1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3489,7 +3489,7 @@
             image_opts = true;
             break;
         case OPTION_PREALLOCATION:
-            prealloc = qapi_enum_parse(PreallocMode_lookup, optarg,
+            prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
                                        PREALLOC_MODE__MAX, NULL);
             if (prealloc == PREALLOC_MODE__MAX) {
                 error_report("Invalid preallocation mode '%s'", optarg);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index a97f3f4..d75ca51 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -638,7 +638,7 @@
             break;
         case QEMU_NBD_OPT_DETECT_ZEROES:
             detect_zeroes =
-                qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
+                qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup,
                                 optarg,
                                 BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                                 &local_err);
diff --git a/qom/object.c b/qom/object.c
index fe6e744..3e18537 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1246,7 +1246,7 @@
 }
 
 typedef struct EnumProperty {
-    const char * const *strings;
+    const QEnumLookup *lookup;
     int (*get)(Object *, Error **);
     void (*set)(Object *, int, Error **);
 } EnumProperty;
@@ -1284,7 +1284,7 @@
     visit_complete(v, &str);
     visit_free(v);
     v = string_input_visitor_new(str);
-    visit_type_enum(v, name, &ret, enumprop->strings, errp);
+    visit_type_enum(v, name, &ret, enumprop->lookup, errp);
 
     g_free(str);
     visit_free(v);
@@ -1950,7 +1950,7 @@
         return;
     }
 
-    visit_type_enum(v, name, &value, prop->strings, errp);
+    visit_type_enum(v, name, &value, prop->lookup, errp);
 }
 
 static void property_set_enum(Object *obj, Visitor *v, const char *name,
@@ -1960,7 +1960,7 @@
     int value;
     Error *err = NULL;
 
-    visit_type_enum(v, name, &value, prop->strings, &err);
+    visit_type_enum(v, name, &value, prop->lookup, &err);
     if (err) {
         error_propagate(errp, err);
         return;
@@ -1977,7 +1977,7 @@
 
 void object_property_add_enum(Object *obj, const char *name,
                               const char *typename,
-                              const char * const *strings,
+                              const QEnumLookup *lookup,
                               int (*get)(Object *, Error **),
                               void (*set)(Object *, int, Error **),
                               Error **errp)
@@ -1985,7 +1985,7 @@
     Error *local_err = NULL;
     EnumProperty *prop = g_malloc(sizeof(*prop));
 
-    prop->strings = strings;
+    prop->lookup = lookup;
     prop->get = get;
     prop->set = set;
 
@@ -2002,7 +2002,7 @@
 
 void object_class_property_add_enum(ObjectClass *klass, const char *name,
                                     const char *typename,
-                                    const char * const *strings,
+                                    const QEnumLookup *lookup,
                                     int (*get)(Object *, Error **),
                                     void (*set)(Object *, int, Error **),
                                     Error **errp)
@@ -2010,7 +2010,7 @@
     Error *local_err = NULL;
     EnumProperty *prop = g_malloc(sizeof(*prop));
 
-    prop->strings = strings;
+    prop->lookup = lookup;
     prop->get = get;
     prop->set = set;
 
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index bd0b742..7e1cfc1 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -153,7 +153,7 @@
 void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error **errp)
 {
     int value = *obj;
-    visit_type_enum(v, name, &value, %(c_name)s_lookup, errp);
+    visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp);
     *obj = value;
 }
 ''',
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8736b9c..39a6727 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1849,19 +1849,22 @@
 def gen_enum_lookup(name, values, prefix=None):
     ret = mcgen('''
 
-const char *const %(c_name)s_lookup[] = {
+const QEnumLookup %(c_name)s_lookup = {
+    .array = (const char *const[]) {
 ''',
                 c_name=c_name(name))
     for value in values:
         index = c_enum_const(name, value, prefix)
         ret += mcgen('''
-    [%(index)s] = "%(value)s",
+        [%(index)s] = "%(value)s",
 ''',
                      index=index, value=value)
 
     max_index = c_enum_const(name, '_MAX', prefix)
     ret += mcgen('''
-    [%(max_index)s] = NULL,
+        [%(max_index)s] = NULL,
+    },
+    .size = %(max_index)s
 };
 ''',
                  max_index=max_index)
@@ -1895,9 +1898,9 @@
     ret += mcgen('''
 
 #define %(c_name)s_str(val) \\
-    qapi_enum_lookup(%(c_name)s_lookup, (val))
+    qapi_enum_lookup(&%(c_name)s_lookup, (val))
 
-extern const char *const %(c_name)s_lookup[];
+extern const QEnumLookup %(c_name)s_lookup;
 ''',
                  c_name=c_name(name))
     return ret
diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c
index c51e6e7..07e351f 100644
--- a/tests/check-qom-proplist.c
+++ b/tests/check-qom-proplist.c
@@ -46,11 +46,14 @@
     DUMMY_LAST,
 };
 
-static const char *const dummy_animal_map[DUMMY_LAST + 1] = {
-    [DUMMY_FROG] = "frog",
-    [DUMMY_ALLIGATOR] = "alligator",
-    [DUMMY_PLATYPUS] = "platypus",
-    [DUMMY_LAST] = NULL,
+const QEnumLookup dummy_animal_map = {
+    .array = (const char *const[]) {
+        [DUMMY_FROG] = "frog",
+        [DUMMY_ALLIGATOR] = "alligator",
+        [DUMMY_PLATYPUS] = "platypus",
+        [DUMMY_LAST] = NULL,
+    },
+    .size = DUMMY_LAST
 };
 
 struct DummyObject {
@@ -142,7 +145,7 @@
                                   NULL);
     object_class_property_add_enum(cls, "av",
                                    "DummyAnimal",
-                                   dummy_animal_map,
+                                   &dummy_animal_map,
                                    dummy_get_av,
                                    dummy_set_av,
                                    NULL);
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index b5f21df..c5a5c10 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -181,7 +181,7 @@
         g_assert(qdict_haskey(resp, "return"));
     } else {
         g_assert(error);
-        g_assert_cmpint(qapi_enum_parse(QapiErrorClass_lookup, error_class,
+        g_assert_cmpint(qapi_enum_parse(&QapiErrorClass_lookup, error_class,
                                         -1, &error_abort),
                         ==, expected_error_class);
     }
diff --git a/tests/test-qapi-util.c b/tests/test-qapi-util.c
index 0992bdb..4b5e4f8 100644
--- a/tests/test-qapi-util.c
+++ b/tests/test-qapi-util.c
@@ -19,19 +19,19 @@
     Error *err = NULL;
     int ret;
 
-    ret = qapi_enum_parse(QType_lookup, NULL, QTYPE_NONE, &error_abort);
+    ret = qapi_enum_parse(&QType_lookup, NULL, QTYPE_NONE, &error_abort);
     g_assert_cmpint(ret, ==, QTYPE_NONE);
 
-    ret = qapi_enum_parse(QType_lookup, "junk", -1, NULL);
+    ret = qapi_enum_parse(&QType_lookup, "junk", -1, NULL);
     g_assert_cmpint(ret, ==, -1);
 
-    ret = qapi_enum_parse(QType_lookup, "junk", -1, &err);
+    ret = qapi_enum_parse(&QType_lookup, "junk", -1, &err);
     error_free_or_abort(&err);
 
-    ret = qapi_enum_parse(QType_lookup, "none", -1, &error_abort);
+    ret = qapi_enum_parse(&QType_lookup, "none", -1, &error_abort);
     g_assert_cmpint(ret, ==, QTYPE_NONE);
 
-    ret = qapi_enum_parse(QType_lookup, QType_str(QTYPE__MAX - 1),
+    ret = qapi_enum_parse(&QType_lookup, QType_str(QTYPE__MAX - 1),
                           QTYPE__MAX - 1, &error_abort);
     g_assert_cmpint(ret, ==, QTYPE__MAX - 1);
 }
diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c
index f8720aa..fe59181 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -1110,7 +1110,7 @@
     error_free_or_abort(&err);
     visit_optional(v, "optional", &present);
     g_assert(!present);
-    visit_type_enum(v, "enum", &en, EnumOne_lookup, &err);
+    visit_type_enum(v, "enum", &en, &EnumOne_lookup, &err);
     error_free_or_abort(&err);
     visit_type_int(v, "i64", &i64, &err);
     error_free_or_abort(&err);
diff --git a/tpm.c b/tpm.c
index 111f1ca..2d830d0 100644
--- a/tpm.c
+++ b/tpm.c
@@ -33,7 +33,7 @@
 
 const TPMDriverOps *tpm_get_backend_driver(const char *type)
 {
-    int i = qapi_enum_parse(TpmType_lookup, type, -1, NULL);
+    int i = qapi_enum_parse(&TpmType_lookup, type, -1, NULL);
 
     return i >= 0 ? be_drivers[i] : NULL;
 }