@@ -12,3 +12,6 @@ cstr = { version = "=0.2.10" }
[dev-dependencies]
matches = ">=0"
+
+[build-dependencies]
+version_check = { version = "~0.9" }
new file mode 100644
@@ -0,0 +1,5 @@
+fn main() {
+ if let Some(true) = version_check::is_min_version("1.77.0") {
+ println!("cargo:rustc-cfg=has_offset_of");
+ }
+}
@@ -111,7 +111,7 @@ macro_rules! qdev_prop {
$kind,
$name,
(<$crate::conf_type!($type) as ConstDefault>::DEFAULT).$field,
- <$type as $crate::DeviceTypeImpl>::CONF_OFFSET + std::mem::offset_of!($crate::conf_type!($type), $field)
+ <$type as $crate::DeviceTypeImpl>::CONF_OFFSET + $crate::offset_of!($crate::conf_type!($type), $field)
)
};
}
@@ -126,7 +126,7 @@ macro_rules! qdev_define_type {
@extends $super $(,$supers)*, $crate::Object);
unsafe impl $crate::DeviceTypeImpl for $struct {
- const CONF_OFFSET: usize = std::mem::offset_of!($struct, conf);
+ const CONF_OFFSET: usize = $crate::offset_of!($struct, conf);
fn properties() -> *const $crate::Property {
static mut PROPERTIES: &'static [$crate::Property] = &[$($props),+];
@@ -31,3 +31,7 @@ pub use util::foreign::IntoNative;
pub use util::foreign::OwnedPointer;
pub use util::zeroed::Zeroed;
pub type Result<T> = std::result::Result<T, Error>;
+
+// with_offsets is exported directly from util::offset_of
+#[cfg(has_offset_of)]
+pub use std::mem::offset_of;
@@ -95,11 +95,14 @@ unsafe fn rust_type_register<T: TypeImpl + ObjectImpl>() {
#[macro_export]
macro_rules! qom_define_type {
($name:expr, $struct:ident, $conf_ty:ty, $state_ty:ty; @extends $super:ty $(,$supers:ty)*) => {
- struct $struct {
- // self.base dropped by call to superclass instance_finalize
- base: std::mem::ManuallyDrop<$super>,
- conf: $conf_ty,
- state: $state_ty,
+ $crate::with_offsets! {
+ #[repr(C)]
+ struct $struct {
+ // self.base dropped by call to superclass instance_finalize
+ base: std::mem::ManuallyDrop<$super>,
+ conf: $conf_ty,
+ state: $state_ty,
+ }
}
// Define IsA markers for the struct itself and all the superclasses
@@ -1,3 +1,4 @@
pub mod error;
pub mod foreign;
+pub mod offset_of;
pub mod zeroed;
new file mode 100644
@@ -0,0 +1,99 @@
+#[cfg(not(has_offset_of))]
+#[macro_export]
+macro_rules! offset_of {
+ ($Container:ty, $field:ident) => {
+ <$Container>::offset_to.$field
+ };
+}
+
+/// A wrapper for struct declarations, that allows using `offset_of!` in
+/// versions of Rust prior to 1.77
+#[macro_export]
+macro_rules! with_offsets {
+ // source: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10a22a9b8393abd7b541d8fc844bc0df
+ // used under MIT license with permission of Yandros aka Daniel Henry-Mantilla
+ (
+ #[repr(C)]
+ $(#[$struct_meta:meta])*
+ $struct_vis:vis
+ struct $StructName:ident {
+ $(
+ $(#[$field_meta:meta])*
+ $field_vis:vis
+ $field_name:ident : $field_ty:ty
+ ),*
+ $(,)?
+ }
+ ) => (
+ #[repr(C)]
+ $(#[$struct_meta])*
+ $struct_vis
+ struct $StructName {
+ $(
+ $(#[$field_meta])*
+ $field_vis
+ $field_name : $field_ty ,
+ )*
+ }
+
+ #[cfg(not(has_offset_of))]
+ #[allow(nonstandard_style)]
+ const _: () = {
+ pub
+ struct StructOffsets {
+ $(
+ $field_vis
+ $field_name: usize,
+ )*
+ }
+ struct Helper;
+ impl $StructName {
+ pub
+ const offset_to: StructOffsets = StructOffsets {
+ $(
+ $field_name: Helper::$field_name,
+ )*
+ };
+ }
+ const END_OF_PREV_FIELD: usize = 0;
+ $crate::with_offsets! {
+ @names [ $($field_name)* ]
+ @tys [ $($field_ty ,)*]
+ }
+ };
+ );
+
+ (
+ @names []
+ @tys []
+ ) => ();
+
+ (
+ @names [$field_name:ident $($other_names:tt)*]
+ @tys [$field_ty:ty , $($other_tys:tt)*]
+ ) => (
+ impl Helper {
+ const $field_name: usize = {
+ let align =
+ std::mem::align_of::<$field_ty>()
+ ;
+ let trail =
+ END_OF_PREV_FIELD % align
+ ;
+ 0 + END_OF_PREV_FIELD
+ + (align - trail)
+ * [1, 0][(trail == 0) as usize]
+ };
+ }
+ const _: () = {
+ const END_OF_PREV_FIELD: usize =
+ Helper::$field_name +
+ std::mem::size_of::<$field_ty>()
+ ;
+ $crate::with_offsets! {
+ @names [$($other_names)*]
+ @tys [$($other_tys)*]
+ }
+ };
+ );
+}
@@ -14,11 +14,16 @@ use qemu::DeviceState;
use qemu::Result;
+use qemu::with_offsets;
+
use std::cell::RefCell;
-#[derive(Default, ConstDefault)]
-struct TestConf {
- foo: bool,
+with_offsets! {
+ #[repr(C)]
+ #[derive(Default, ConstDefault)]
+ struct TestConf {
+ foo: bool,
+ }
}
#[derive(Default)]
Allow working with Rust versions prior to 1.77. The code was taken from Rust's Discourse platform and is used with permission of the author. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> --- qemu/Cargo.toml | 3 + qemu/build.rs | 5 ++ qemu/src/hw/core/device_impl.rs | 4 +- qemu/src/lib.rs | 4 ++ qemu/src/qom/object_impl.rs | 13 +++-- qemu/src/util/mod.rs | 1 + qemu/src/util/offset_of.rs | 99 +++++++++++++++++++++++++++++++++ qemu/tests/main.rs | 11 +++- 9 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 qemu/build.rs create mode 100644 qemu/src/util/offset_of.rs