rust: migration: extract vmstate_fields_ref

This is useful when building a VMState for generic structs, because you have
to avoid nested statics.  Using vmstate_fields! will fail in the likely case
where the _FIELDS static uses Self from an outer item, because that is
forbidden.

The separate macros are needed because you cannot just do

                 .fields(vmstate_fields_ref! {
                      vmstate_of!(PL011State, clock),
                 })

The value returned by vmstate_fields_ref! is not promoted to static, which is
unfortunate but intentional (https://github.com/rust-lang/rust/issues/60502):

error[E0716]: temporary value dropped while borrowed
   --> rust/hw/char/pl011/libpl011.rlib.p/structured/device.rs:743:17
    |
738 | /      VMStateDescriptionBuilder::<PL011State>::new()
739 | |          .name(c"pl011/clock")
740 | |          .version_id(1)
741 | |          .minimum_version_id(1)
742 | |          .needed(&PL011State::clock_needed)
743 | |          .fields(vmstate_fields_ref! {
    | | _________________^
744 | ||              vmstate_of!(PL011State, clock),
745 | ||         })
    | ||_________^- argument requires that borrow lasts for `'static`
    |  |_________|
    |            creates a temporary value which is freed while still in use
746 |            .build();
    |                   - temporary value is freed at the end of this statement

Thus it is necessary to use the "static", whether explicitly or hidden by
vmstate_fields.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2025-09-17 12:37:59 +02:00
parent 5b4fa97807
commit 8999ca00a4

View file

@ -412,19 +412,30 @@ macro_rules! vmstate_exist_fn {
}};
}
/// Add a terminator to the fields in the arguments, and return
/// a reference to the resulting array of values.
#[macro_export]
macro_rules! vmstate_fields_ref {
($($field:expr),*$(,)*) => {
&[
$($field),*,
$crate::bindings::VMStateField {
flags: $crate::bindings::VMStateFlags::VMS_END,
..::common::zeroable::Zeroable::ZERO
}
]
}
}
/// Helper macro to declare a list of
/// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
/// a pointer to the array of values it created.
#[macro_export]
macro_rules! vmstate_fields {
($($field:expr),*$(,)*) => {{
static _FIELDS: &[$crate::bindings::VMStateField] = &[
static _FIELDS: &[$crate::bindings::VMStateField] = $crate::vmstate_fields_ref!(
$($field),*,
$crate::bindings::VMStateField {
flags: $crate::bindings::VMStateFlags::VMS_END,
..::common::zeroable::Zeroable::ZERO
}
];
);
_FIELDS
}}
}