diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2025-05-07 16:10:59 -0400 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2025-05-07 16:10:59 -0400 |
commit | c5f122fdcc280a82e7c5f31de890f985aa7ba773 (patch) | |
tree | 42152238b23d212a5bc1ac75397eb6dba035d791 /rust/qemu-api/src | |
parent | 57b6f8d07f1478375f85a4593a207e936c63ff59 (diff) | |
parent | e6b9b79c3076777b791f72ebdbc9d37ad8005fe9 (diff) | |
download | qemu-c5f122fdcc280a82e7c5f31de890f985aa7ba773.zip qemu-c5f122fdcc280a82e7c5f31de890f985aa7ba773.tar.gz qemu-c5f122fdcc280a82e7c5f31de890f985aa7ba773.tar.bz2 |
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* ci: enable RISC-V cross jobs
* rust: bump minimum supported version to 1.77
* rust: enable uninlined_format_args lint
* initial Emscripten support
* small fixes
# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmgaFq8UHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroOxAAf/YPKw5KAoE5SwUqJ0oSOMHrU0w4jc
# A2Qiw1uziA6kDmUMUXwWR7Qbd8V7jtihGrgTrIPopeavgWWQeNsBHjN4WxHRI7aq
# +429rjzFo9V9tSfgp6UcLQSk/9kC4ygEwPnesHpKd27fS6z9Wg4AQkj1iFipR179
# wC3fqwOqqWZSjfUd7wjo7McFYZgL5j/cxmFXePh8+fdT+6PUKdG9nRW86KUPDZ+A
# 8HxcuOW7GZd+LhnYUhi7vlLFo/RgVsGQWj0Q4BDJvUkKa13t9UUCGff7uQP2AC3v
# ny0gWDcmbWY1L/QXyNzhgd44X4LAjCmpnonlYnrdZizEmhv3aByd+fANgw==
# =uIJK
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 06 May 2025 10:03:27 EDT
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (30 commits)
gitlab: Enable CI for wasm build
tests: Add Dockerfile containing dependencies for Emscripten build
meson: Add wasm build in build scripts
util: Add coroutine backend for emscripten
util: exclude mmap-alloc.c from compilation target on Emscripten
Disable options unsupported on Emscripten
include/qemu/osdep.h: Add Emscripten-specific OS dependencies
block: Fix type conflict of the copy_file_range stub
block: Add including of ioctl header for Emscripten build
util/cacheflush.c: Update cache flushing mechanism for Emscripten
include/glib-compat.h: Poison g_list_sort and g_slist_sort
target/s390x: Fix type conflict of GLib function pointers
target/ppc: Fix type conflict of GLib function pointers
target/i386/cpu.c: Fix type conflict of GLib function pointers
target/arm/helper.c: Fix type conflict of GLib function pointers
docs: build-system: fix typo
ci: run RISC-V cross jobs by default
rust: clippy: enable uninlined_format_args lint
target/i386/emulate: fix target_ulong format strings
docs: rust: update for newer minimum supported version
...
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api/src')
-rw-r--r-- | rust/qemu-api/src/c_str.rs | 61 | ||||
-rw-r--r-- | rust/qemu-api/src/cell.rs | 6 | ||||
-rw-r--r-- | rust/qemu-api/src/chardev.rs | 5 | ||||
-rw-r--r-- | rust/qemu-api/src/irq.rs | 6 | ||||
-rw-r--r-- | rust/qemu-api/src/lib.rs | 7 | ||||
-rw-r--r-- | rust/qemu-api/src/memory.rs | 3 | ||||
-rw-r--r-- | rust/qemu-api/src/offset_of.rs | 168 | ||||
-rw-r--r-- | rust/qemu-api/src/qdev.rs | 9 | ||||
-rw-r--r-- | rust/qemu-api/src/qom.rs | 14 | ||||
-rw-r--r-- | rust/qemu-api/src/timer.rs | 4 | ||||
-rw-r--r-- | rust/qemu-api/src/vmstate.rs | 14 | ||||
-rw-r--r-- | rust/qemu-api/src/zeroable.rs | 106 |
12 files changed, 49 insertions, 354 deletions
diff --git a/rust/qemu-api/src/c_str.rs b/rust/qemu-api/src/c_str.rs deleted file mode 100644 index 3fa61b5..0000000 --- a/rust/qemu-api/src/c_str.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2024 Red Hat, Inc. -// Author(s): Paolo Bonzini <pbonzini@redhat.com> -// SPDX-License-Identifier: GPL-2.0-or-later - -#![doc(hidden)] -//! This module provides a macro to define a constant of type -//! [`CStr`](std::ffi::CStr), for compatibility with versions of -//! Rust that lack `c""` literals. -//! -//! Documentation is hidden because it only exposes macros, which -//! are exported directly from `qemu_api`. - -#[macro_export] -/// Given a string constant _without_ embedded or trailing NULs, return -/// a `CStr`. -/// -/// Needed for compatibility with Rust <1.77. -macro_rules! c_str { - ($str:expr) => {{ - const STRING: &str = concat!($str, "\0"); - const BYTES: &[u8] = STRING.as_bytes(); - - // "for" is not allowed in const context... oh well, - // everybody loves some lisp. This could be turned into - // a procedural macro if this is a problem; alternatively - // Rust 1.72 makes CStr::from_bytes_with_nul a const function. - const fn f(b: &[u8], i: usize) { - if i == b.len() - 1 { - } else if b[i] == 0 { - panic!("c_str argument contains NUL") - } else { - f(b, i + 1) - } - } - f(BYTES, 0); - - // SAFETY: absence of NULs apart from the final byte was checked above - unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(BYTES) } - }}; -} - -#[cfg(test)] -mod tests { - use std::ffi::CStr; - - use crate::c_str; - - #[test] - fn test_cstr_macro() { - let good = c_str!("🦀"); - let good_bytes = b"\xf0\x9f\xa6\x80\0"; - assert_eq!(good.to_bytes_with_nul(), good_bytes); - } - - #[test] - fn test_cstr_macro_const() { - const GOOD: &CStr = c_str!("🦀"); - const GOOD_BYTES: &[u8] = b"\xf0\x9f\xa6\x80\0"; - assert_eq!(GOOD.to_bytes_with_nul(), GOOD_BYTES); - } -} diff --git a/rust/qemu-api/src/cell.rs b/rust/qemu-api/src/cell.rs index ab0785a..05ce09f 100644 --- a/rust/qemu-api/src/cell.rs +++ b/rust/qemu-api/src/cell.rs @@ -77,13 +77,13 @@ //! //! ``` //! # use qemu_api::prelude::*; -//! # use qemu_api::{c_str, cell::BqlRefCell, irq::InterruptSource, irq::IRQState}; +//! # use qemu_api::{cell::BqlRefCell, irq::InterruptSource, irq::IRQState}; //! # use qemu_api::{sysbus::SysBusDevice, qom::Owned, qom::ParentField}; //! # const N_GPIOS: usize = 8; //! # struct PL061Registers { /* ... */ } //! # unsafe impl ObjectType for PL061State { //! # type Class = <SysBusDevice as ObjectType>::Class; -//! # const TYPE_NAME: &'static std::ffi::CStr = c_str!("pl061"); +//! # const TYPE_NAME: &'static std::ffi::CStr = c"pl061"; //! # } //! struct PL061State { //! parent_obj: ParentField<SysBusDevice>, @@ -1016,7 +1016,7 @@ impl<T> Opaque<T> { /// Returns a raw pointer to the opaque data. pub const fn as_ptr(&self) -> *const T { - self.as_mut_ptr() as *const _ + self.as_mut_ptr().cast_const() } /// Returns a raw pointer to the opaque data that can be passed to a diff --git a/rust/qemu-api/src/chardev.rs b/rust/qemu-api/src/chardev.rs index 11e6c45..6e0590d 100644 --- a/rust/qemu-api/src/chardev.rs +++ b/rust/qemu-api/src/chardev.rs @@ -10,11 +10,10 @@ //! called. use std::{ - ffi::CStr, + ffi::{c_int, c_void, CStr}, fmt::{self, Debug}, io::{self, ErrorKind, Write}, marker::PhantomPinned, - os::raw::{c_int, c_void}, ptr::addr_of_mut, slice, }; @@ -161,7 +160,7 @@ impl CharBackend { receive_cb, event_cb, None, - (owner as *const T as *mut T).cast::<c_void>(), + (owner as *const T).cast_mut().cast::<c_void>(), core::ptr::null_mut(), true, ); diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs index 1222d4f..1526e6f 100644 --- a/rust/qemu-api/src/irq.rs +++ b/rust/qemu-api/src/irq.rs @@ -4,7 +4,11 @@ //! Bindings for interrupt sources -use std::{ffi::CStr, marker::PhantomData, os::raw::c_int, ptr}; +use std::{ + ffi::{c_int, CStr}, + marker::PhantomData, + ptr, +}; use crate::{ bindings::{self, qemu_set_irq}, diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 05f38b5..234a94e 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -15,7 +15,6 @@ pub mod prelude; pub mod assertions; pub mod bitops; -pub mod c_str; pub mod callbacks; pub mod cell; pub mod chardev; @@ -23,7 +22,6 @@ pub mod errno; pub mod irq; pub mod memory; pub mod module; -pub mod offset_of; pub mod qdev; pub mod qom; pub mod sysbus; @@ -33,7 +31,7 @@ pub mod zeroable; use std::{ alloc::{GlobalAlloc, Layout}, - os::raw::c_void, + ffi::c_void, }; #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)] @@ -165,6 +163,3 @@ unsafe impl GlobalAlloc for QemuAllocator { } } } - -#[cfg(has_offset_of)] -pub use core::mem::offset_of; diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs index fdb1ea1..9ef2694 100644 --- a/rust/qemu-api/src/memory.rs +++ b/rust/qemu-api/src/memory.rs @@ -5,9 +5,8 @@ //! Bindings for `MemoryRegion`, `MemoryRegionOps` and `MemTxAttrs` use std::{ - ffi::{CStr, CString}, + ffi::{c_uint, c_void, CStr, CString}, marker::PhantomData, - os::raw::{c_uint, c_void}, }; pub use bindings::{hwaddr, MemTxAttrs}; diff --git a/rust/qemu-api/src/offset_of.rs b/rust/qemu-api/src/offset_of.rs deleted file mode 100644 index 373229b..0000000 --- a/rust/qemu-api/src/offset_of.rs +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: MIT - -#![doc(hidden)] -//! This module provides macros that emulate the functionality of -//! `core::mem::offset_of` on older versions of Rust. -//! -//! Documentation is hidden because it only exposes macros, which -//! are exported directly from `qemu_api`. - -/// This macro provides the same functionality as `core::mem::offset_of`, -/// except that only one level of field access is supported. The declaration -/// of the struct must be wrapped with `with_offsets! { }`. -/// -/// It is needed because `offset_of!` was only stabilized in Rust 1.77. -#[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 { - // This method to generate field offset constants comes from: - // - // 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 - ( - $(#[$struct_meta:meta])* - $struct_vis:vis - struct $StructName:ident { - $( - $(#[$field_meta:meta])* - $field_vis:vis - $field_name:ident : $field_ty:ty - ),* - $(,)? - } - ) => ( - #[cfg(not(has_offset_of))] - const _: () = { - struct StructOffsetsHelper<T>(std::marker::PhantomData<T>); - const END_OF_PREV_FIELD: usize = 0; - - // populate StructOffsetsHelper<T> with associated consts, - // one for each field - $crate::with_offsets! { - @struct $StructName - @names [ $($field_name)* ] - @tys [ $($field_ty ,)*] - } - - // now turn StructOffsetsHelper<T>'s consts into a single struct, - // applying field visibility. This provides better error messages - // than if offset_of! used StructOffsetsHelper::<T> directly. - pub - struct StructOffsets { - $( - $field_vis - $field_name: usize, - )* - } - impl $StructName { - pub - const OFFSET_TO__: StructOffsets = StructOffsets { - $( - $field_name: StructOffsetsHelper::<$StructName>::$field_name, - )* - }; - } - }; - ); - - ( - @struct $StructName:ident - @names [] - @tys [] - ) => (); - - ( - @struct $StructName:ident - @names [$field_name:ident $($other_names:tt)*] - @tys [$field_ty:ty , $($other_tys:tt)*] - ) => ( - #[allow(non_local_definitions)] - #[allow(clippy::modulo_one)] - impl StructOffsetsHelper<$StructName> { - #[allow(nonstandard_style)] - const $field_name: usize = { - const ALIGN: usize = std::mem::align_of::<$field_ty>(); - const TRAIL: usize = END_OF_PREV_FIELD % ALIGN; - END_OF_PREV_FIELD + (if TRAIL == 0 { 0usize } else { ALIGN - TRAIL }) - }; - } - const _: () = { - const END_OF_PREV_FIELD: usize = - StructOffsetsHelper::<$StructName>::$field_name + - std::mem::size_of::<$field_ty>() - ; - $crate::with_offsets! { - @struct $StructName - @names [$($other_names)*] - @tys [$($other_tys)*] - } - }; - ); -} - -#[cfg(test)] -mod tests { - use crate::offset_of; - - #[repr(C)] - struct Foo { - a: u16, - b: u32, - c: u64, - d: u16, - } - - #[repr(C)] - struct Bar { - pub a: u16, - pub b: u64, - c: Foo, - d: u64, - } - - crate::with_offsets! { - #[repr(C)] - struct Bar { - pub a: u16, - pub b: u64, - c: Foo, - d: u64, - } - } - - #[repr(C)] - pub struct Baz { - b: u32, - a: u8, - } - crate::with_offsets! { - #[repr(C)] - pub struct Baz { - b: u32, - a: u8, - } - } - - #[test] - fn test_offset_of() { - const OFFSET_TO_C: usize = offset_of!(Bar, c); - - assert_eq!(offset_of!(Bar, a), 0); - assert_eq!(offset_of!(Bar, b), 8); - assert_eq!(OFFSET_TO_C, 16); - assert_eq!(offset_of!(Bar, d), 40); - - assert_eq!(offset_of!(Baz, b), 0); - assert_eq!(offset_of!(Baz, a), 4); - } -} diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 18b4a9b..1279d7a 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -5,8 +5,7 @@ //! Bindings to create devices and access device functionality from Rust. use std::{ - ffi::{CStr, CString}, - os::raw::{c_int, c_void}, + ffi::{c_int, c_void, CStr, CString}, ptr::NonNull, }; @@ -191,7 +190,7 @@ macro_rules! define_property { // use associated function syntax for type checking name: ::std::ffi::CStr::as_ptr($name), info: $prop, - offset: $crate::offset_of!($state, $field) as isize, + offset: ::std::mem::offset_of!($state, $field) as isize, bitnr: $bitnr, set_default: true, defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, @@ -203,7 +202,7 @@ macro_rules! define_property { // use associated function syntax for type checking name: ::std::ffi::CStr::as_ptr($name), info: $prop, - offset: $crate::offset_of!($state, $field) as isize, + offset: ::std::mem::offset_of!($state, $field) as isize, set_default: true, defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, ..$crate::zeroable::Zeroable::ZERO @@ -214,7 +213,7 @@ macro_rules! define_property { // use associated function syntax for type checking name: ::std::ffi::CStr::as_ptr($name), info: $prop, - offset: $crate::offset_of!($state, $field) as isize, + offset: ::std::mem::offset_of!($state, $field) as isize, set_default: false, ..$crate::zeroable::Zeroable::ZERO } diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index f1b4022..41e5a5e 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -93,11 +93,10 @@ //! without incurring into violations of orphan rules for traits. use std::{ - ffi::CStr, + ffi::{c_void, CStr}, fmt, mem::ManuallyDrop, ops::{Deref, DerefMut}, - os::raw::c_void, ptr::NonNull, }; @@ -389,7 +388,7 @@ where { #[allow(clippy::as_ptr_cast_mut)] { - self.as_ptr::<U>() as *mut _ + self.as_ptr::<U>().cast_mut() } } } @@ -535,9 +534,10 @@ pub trait ObjectImpl: ObjectType + IsA<Object> { /// While `klass`'s parent class is initialized on entry, the other fields /// are all zero; it is therefore assumed that all fields in `T` can be /// zeroed, otherwise it would not be possible to provide the class as a - /// `&mut T`. TODO: add a bound of [`Zeroable`](crate::zeroable::Zeroable) - /// to T; this is more easily done once Zeroable does not require a manual - /// implementation (Rust 1.75.0). + /// `&mut T`. TODO: it may be possible to add an unsafe trait that checks + /// that all fields *after the parent class* (but not the parent class + /// itself) are Zeroable. This unsafe trait can be added via a derive + /// macro. const CLASS_INIT: fn(&mut Self::Class); } @@ -638,7 +638,7 @@ impl<T: ObjectType> Owned<T> { // SAFETY NOTE: while NonNull requires a mutable pointer, only // Deref is implemented so the pointer passed to from_raw // remains const - Owned(NonNull::new(ptr as *mut T).unwrap()) + Owned(NonNull::new(ptr.cast_mut()).unwrap()) } /// Obtain a raw C pointer from a reference. `src` is consumed diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs index e769f8b..868bd88 100644 --- a/rust/qemu-api/src/timer.rs +++ b/rust/qemu-api/src/timer.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later use std::{ - os::raw::{c_int, c_void}, + ffi::{c_int, c_void}, pin::Pin, }; @@ -81,7 +81,7 @@ impl Timer { scale as c_int, attributes as c_int, Some(timer_cb), - (opaque as *const T).cast::<c_void>() as *mut c_void, + (opaque as *const T).cast::<c_void>().cast_mut(), ) } } diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 9ae97c3..9c8b239 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -25,7 +25,7 @@ //! functionality that is missing from `vmstate_of!`. use core::{marker::PhantomData, mem, ptr::NonNull}; -use std::os::raw::{c_int, c_void}; +use std::ffi::{c_int, c_void}; pub use crate::bindings::{VMStateDescription, VMStateField}; use crate::{ @@ -205,8 +205,8 @@ macro_rules! vmstate_of { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() .as_ptr() as *const ::std::os::raw::c_char, - offset: $crate::offset_of!($struct_name, $field_name), - $(num_offset: $crate::offset_of!($struct_name, $num),)? + offset: ::std::mem::offset_of!($struct_name, $field_name), + $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? // The calls to `call_func_with_field!` are the magic that // computes most of the VMStateField from the type of the field. @@ -427,7 +427,7 @@ unsafe impl<T: VMState, const N: usize> VMState for [T; N] { macro_rules! vmstate_unused { ($size:expr) => {{ $crate::bindings::VMStateField { - name: $crate::c_str!("unused").as_ptr(), + name: c"unused".as_ptr(), size: $size, info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) }, flags: $crate::bindings::VMStateFlags::VMS_BUFFER, @@ -483,10 +483,10 @@ macro_rules! vmstate_struct { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() .as_ptr() as *const ::std::os::raw::c_char, - $(num_offset: $crate::offset_of!($struct_name, $num),)? + $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? offset: { $crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?); - $crate::offset_of!($struct_name, $field_name) + ::std::mem::offset_of!($struct_name, $field_name) }, size: ::core::mem::size_of::<$type>(), flags: $crate::bindings::VMStateFlags::VMS_STRUCT, @@ -518,7 +518,7 @@ macro_rules! vmstate_clock { $field_name, $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)? ); - $crate::offset_of!($struct_name, $field_name) + ::std::mem::offset_of!($struct_name, $field_name) }, size: ::core::mem::size_of::<*const $crate::qdev::Clock>(), flags: $crate::bindings::VMStateFlags( diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs index a3415a2..d8239d0 100644 --- a/rust/qemu-api/src/zeroable.rs +++ b/rust/qemu-api/src/zeroable.rs @@ -4,89 +4,17 @@ /// Encapsulates the requirement that /// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause undefined -/// behavior. This trait in principle could be implemented as just: -/// -/// ``` -/// pub unsafe trait Zeroable: Default { -/// const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() }; -/// } -/// ``` -/// -/// The need for a manual implementation is only because `zeroed()` cannot -/// be used as a `const fn` prior to Rust 1.75.0. Once we can assume a new -/// enough version of the compiler, we could provide a `#[derive(Zeroable)]` -/// macro to check at compile-time that all struct fields are Zeroable, and -/// use the above blanket implementation of the `ZERO` constant. +/// behavior. /// /// # Safety /// -/// Because the implementation of `ZERO` is manual, it does not make -/// any assumption on the safety of `zeroed()`. However, other users of the -/// trait could use it that way. Do not add this trait to a type unless -/// all-zeroes is a valid value for the type. In particular, remember that -/// raw pointers can be zero, but references and `NonNull<T>` cannot +/// Do not add this trait to a type unless all-zeroes is a valid value for the +/// type. In particular, raw pointers can be zero, but references and +/// `NonNull<T>` cannot. pub unsafe trait Zeroable: Default { - const ZERO: Self; -} - -/// A macro that acts similarly to [`core::mem::zeroed()`], only is const -/// -/// ## Safety -/// -/// Similar to `core::mem::zeroed()`, except this zeroes padding bits. Zeroed -/// padding usually isn't relevant to safety, but might be if a C union is used. -/// -/// Just like for `core::mem::zeroed()`, an all zero byte pattern might not -/// be a valid value for a type, as is the case for references `&T` and `&mut -/// T`. Reference types trigger a (denied by default) lint and cause immediate -/// undefined behavior if the lint is ignored -/// -/// ```rust compile_fail -/// use const_zero::const_zero; -/// // error: any use of this value will cause an error -/// // note: `#[deny(const_err)]` on by default -/// const STR: &str = unsafe{const_zero!(&'static str)}; -/// ``` -/// -/// `const_zero` does not work on unsized types: -/// -/// ```rust compile_fail -/// use const_zero::const_zero; -/// // error[E0277]: the size for values of type `[u8]` cannot be known at compilation time -/// const BYTES: [u8] = unsafe{const_zero!([u8])}; -/// ``` -/// ## Differences with `core::mem::zeroed` -/// -/// `const_zero` zeroes padding bits, while `core::mem::zeroed` doesn't -#[macro_export] -macro_rules! const_zero { - // This macro to produce a type-generic zero constant is taken from the - // const_zero crate (v0.1.1): - // - // https://docs.rs/const-zero/latest/src/const_zero/lib.rs.html - // - // and used under MIT license - ($type_:ty) => {{ - const TYPE_SIZE: ::core::primitive::usize = ::core::mem::size_of::<$type_>(); - union TypeAsBytes { - bytes: [::core::primitive::u8; TYPE_SIZE], - inner: ::core::mem::ManuallyDrop<$type_>, - } - const ZERO_BYTES: TypeAsBytes = TypeAsBytes { - bytes: [0; TYPE_SIZE], - }; - ::core::mem::ManuallyDrop::<$type_>::into_inner(ZERO_BYTES.inner) - }}; -} - -/// A wrapper to implement the `Zeroable` trait through the `const_zero` macro. -#[macro_export] -macro_rules! impl_zeroable { - ($type:ty) => { - unsafe impl $crate::zeroable::Zeroable for $type { - const ZERO: Self = unsafe { $crate::const_zero!($type) }; - } - }; + /// Return a value of Self whose memory representation consists of all + /// zeroes, with the possible exclusion of padding bytes. + const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() }; } // bindgen does not derive Default here @@ -97,13 +25,13 @@ impl Default for crate::bindings::VMStateFlags { } } -impl_zeroable!(crate::bindings::Property__bindgen_ty_1); -impl_zeroable!(crate::bindings::Property); -impl_zeroable!(crate::bindings::VMStateFlags); -impl_zeroable!(crate::bindings::VMStateField); -impl_zeroable!(crate::bindings::VMStateDescription); -impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1); -impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2); -impl_zeroable!(crate::bindings::MemoryRegionOps); -impl_zeroable!(crate::bindings::MemTxAttrs); -impl_zeroable!(crate::bindings::CharBackend); +unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {} +unsafe impl Zeroable for crate::bindings::Property {} +unsafe impl Zeroable for crate::bindings::VMStateFlags {} +unsafe impl Zeroable for crate::bindings::VMStateField {} +unsafe impl Zeroable for crate::bindings::VMStateDescription {} +unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {} +unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {} +unsafe impl Zeroable for crate::bindings::MemoryRegionOps {} +unsafe impl Zeroable for crate::bindings::MemTxAttrs {} +unsafe impl Zeroable for crate::bindings::CharBackend {} |