diff --git a/src/lib.rs b/src/lib.rs index 439044b6256..39b08a3c476 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -304,6 +304,10 @@ use core::{ ops::{Deref, DerefMut}, ptr::{self, NonNull}, slice, + sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32, + AtomicU8, AtomicUsize, + }, }; use crate::pointer::invariant; @@ -1096,7 +1100,9 @@ impl_known_layout!( u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64, bool, char, NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, - NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize + NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, + AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU8, AtomicUsize ); #[rustfmt::skip] impl_known_layout!( @@ -1106,6 +1112,7 @@ impl_known_layout!( T => MaybeUninit, T: ?Sized => *const T, T: ?Sized => *mut T, + T => AtomicPtr ); impl_known_layout!(const N: usize, T => [T; N]); @@ -3892,6 +3899,33 @@ safety_comment! { unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => NoCell for opt_extern_c_fn!(...)); } +macro_rules! impl_traits_for_atomics { + ($($atomics:ident [$inners:ident]),* $(,)?) => { + $( + impl_for_transparent_wrapper!(TryFromBytes for $atomics [UnsafeCell<$inners>]); + impl_for_transparent_wrapper!(FromZeros for $atomics [UnsafeCell<$inners>]); + impl_for_transparent_wrapper!(FromBytes for $atomics [UnsafeCell<$inners>]); + impl_for_transparent_wrapper!(IntoBytes for $atomics [UnsafeCell<$inners>]); + )* + }; +} + +#[rustfmt::skip] +impl_traits_for_atomics!( + AtomicBool [bool], + AtomicI16 [i16], AtomicI32 [i32], AtomicI8 [i8], AtomicIsize [isize], + AtomicU16 [u16], AtomicU32 [u32], AtomicU8 [u8], AtomicUsize [usize], +); + +safety_comment! { + /// SAFETY: + /// TODO + unsafe_impl!(AtomicBool: Unaligned); + unsafe_impl!(AtomicU8: Unaligned); + unsafe_impl!(AtomicI8: Unaligned); + assert_unaligned!(AtomicBool, AtomicU8, AtomicI8); +} + safety_comment! { /// SAFETY: /// Per reference [1]: diff --git a/src/macros.rs b/src/macros.rs index 4431e1fb239..6c7730f98dd 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -241,11 +241,42 @@ macro_rules! impl_for_transparent_wrapper { impl_for_transparent_wrapper!( @is_bit_valid - $tyvar: $($(? $optbound +)* $($bound +)*)? - => $trait for $ty + <$tyvar: $($(? $optbound +)* $($bound +)*)?> + $trait for $ty ); } }; + ( + $(#[$attr:meta])* + for $ty:ty [$inner:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => {}; + ( + $(#[$attr:meta])* + $trait:ident $(, $traits:ident)* for $ty:ty [$inner:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + impl_for_transparent_wrapper!( + $(#[$attr])* + $($traits),* for $ty [$inner] $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid:expr)? + ); + + $(#[$attr])* + #[allow(non_local_definitions)] + // SAFETY: TODO + unsafe impl $trait for $ty { + #[allow(dead_code, clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() { + use crate::{pointer::invariant::Invariants, util::*}; + + impl_for_transparent_wrapper!(@is_transparent_wrapper $trait); + + fn f() { + is_transparent_wrapper::(); + } + } + + impl_for_transparent_wrapper!(@is_bit_valid $trait for $ty); + } + }; (@is_transparent_wrapper NoCell) => { // SAFETY: `W: TransparentWrapper` // requires that `W` has `UnsafeCell`s at the same byte offsets as @@ -299,8 +330,8 @@ macro_rules! impl_for_transparent_wrapper { }; ( @is_bit_valid - $tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? - => TryFromBytes for $ty:ty + $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? + TryFromBytes for $ty:ty ) => { // SAFETY: See safety comment in `(@is_transparent_wrapper // TryFromBytes)` macro arm for an explanation of why this is a sound @@ -312,8 +343,8 @@ macro_rules! impl_for_transparent_wrapper { }; ( @is_bit_valid - $tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? - => $trait:ident for $ty:ty + $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? + $trait:ident for $ty:ty ) => { // Trait other than `TryFromBytes`; no `is_bit_valid` impl. }; @@ -553,15 +584,14 @@ macro_rules! unsafe_impl_known_layout { /// Note that `align_of` requires `T: Sized`, so this macro doesn't work for /// unsized types. macro_rules! assert_unaligned { - ($ty:ty) => { - // We only compile this assertion under `cfg(test)` to avoid taking an - // extra non-dev dependency (and making this crate more expensive to - // compile for our dependents). - #[cfg(test)] - static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1); - }; - ($($ty:ty),*) => { - $(assert_unaligned!($ty);)* + ($($tys:ty),*) => { + $( + // We only compile this assertion under `cfg(test)` to avoid taking + // an extra non-dev dependency (and making this crate more expensive + // to compile for our dependents). + #[cfg(test)] + static_assertions::const_assert_eq!(core::mem::align_of::<$tys>(), 1); + )* }; }