diff --git a/src/lib.rs b/src/lib.rs index 9233b5b25c..0a5cae5627 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3462,12 +3462,20 @@ safety_comment! { ); unsafe_impl!(T => FromZeros for Option>); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...)); + unsafe_impl_for_power_set!( + A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...); + |c: Maybe| pointer::is_zeroed(c) + ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...)); + unsafe_impl_for_power_set!( + A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...); + |c: Maybe| pointer::is_zeroed(c) + ); } safety_comment! { /// SAFETY: - /// TODO + /// TODO(#896): Write this safety proof before the next stable release. unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => NoCell for opt_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => NoCell for opt_extern_c_fn!(...)); } @@ -8040,6 +8048,27 @@ mod tests { fn with_failing_test_cases(_f: F) {} } + macro_rules! impl_try_from_bytes_testable_for_null_pointer_optimization { + ($($tys:ty),*) => { + $( + impl TryFromBytesTestable for Option<$tys> { + fn with_passing_test_cases(f: F) { + // Test with a zeroed value. + f(&None); + } + + fn with_failing_test_cases(f: F) { + for pos in 0..mem::size_of::() { + let mut bytes = [0u8; mem::size_of::()]; + bytes[pos] = 0x01; + f(&mut bytes[..]); + } + } + } + )* + }; + } + // Implements `TryFromBytesTestable`. macro_rules! impl_try_from_bytes_testable { // Base case for recursion (when the list of types has run out). @@ -8081,6 +8110,17 @@ mod tests { }; } + impl_try_from_bytes_testable_for_null_pointer_optimization!( + Box>, + &'static UnsafeCell, + &'static mut UnsafeCell, + NonNull>, + fn(), + FnManyArgs, + extern "C" fn(), + ECFnManyArgs + ); + // Note that these impls are only for types which are not `FromBytes`. // `FromBytes` types are covered by a preceding blanket impl. impl_try_from_bytes_testable!( @@ -8121,18 +8161,6 @@ mod tests { Wrapping => @success Wrapping(false), Wrapping(true), @failure 2u8, 0xFFu8; - Option>> - => @success None, - @failure [0x01; mem::size_of::>>>()]; - Option<&'static UnsafeCell> - => @success None, - @failure [0x01; mem::size_of::>>()]; - Option<&'static mut UnsafeCell> - => @success None, - @failure [0x01; mem::size_of::>>()]; - Option>> - => @success None, - @failure [0x01; mem::size_of::>>>()]; *const NotZerocopy => @success ptr::null::(), @failure [0x01; mem::size_of::<*const NotZerocopy>()]; @@ -8512,10 +8540,10 @@ mod tests { assert_impls!(Option<&'static mut [UnsafeCell]>: KnownLayout, NoCell, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option>>: KnownLayout, TryFromBytes, FromZeros, NoCell, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option]>>: KnownLayout, NoCell, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); - assert_impls!(Option: KnownLayout, NoCell, FromZeros, !TryFromBytes, !FromBytes, !IntoBytes, !Unaligned); - assert_impls!(Option: KnownLayout, NoCell, FromZeros, !TryFromBytes, !FromBytes, !IntoBytes, !Unaligned); - assert_impls!(Option: KnownLayout, NoCell, FromZeros, !TryFromBytes, !FromBytes, !IntoBytes, !Unaligned); - assert_impls!(Option: KnownLayout, NoCell, FromZeros, !TryFromBytes, !FromBytes, !IntoBytes, !Unaligned); + assert_impls!(Option: KnownLayout, NoCell, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); + assert_impls!(Option: KnownLayout, NoCell, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); + assert_impls!(Option: KnownLayout, NoCell, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); + assert_impls!(Option: KnownLayout, NoCell, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(PhantomData: KnownLayout, NoCell, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_impls!(PhantomData>: KnownLayout, NoCell, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); diff --git a/src/macros.rs b/src/macros.rs index 7acbeec02b..77b1b7aa4b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -213,18 +213,36 @@ macro_rules! unsafe_impl { /// unsafe impl Foo for type!(A, B) { ... } /// ``` macro_rules! unsafe_impl_for_power_set { - ($first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => { - unsafe_impl_for_power_set!($($rest),* $(-> $ret)? => $trait for $macro!(...)); - unsafe_impl_for_power_set!(@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...)); + ( + $first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) + $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + unsafe_impl_for_power_set!( + $($rest),* $(-> $ret)? => $trait for $macro!(...) + $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? + ); + unsafe_impl_for_power_set!( + @impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...) + $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? + ); }; - ($(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => { - unsafe_impl_for_power_set!(@impl $(-> $ret)? => $trait for $macro!(...)); + ( + $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) + $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + unsafe_impl_for_power_set!( + @impl $(-> $ret)? => $trait for $macro!(...) + $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? + ); }; - (@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => { - unsafe impl<$($vars,)* $($ret)?> $trait for $macro!($($vars),* $(-> $ret)?) { - #[allow(clippy::missing_inline_in_public_items)] - fn only_derive_is_allowed_to_implement_this_trait() {} - } + ( + @impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) + $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + ) => { + unsafe_impl!( + $($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?) + $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? + ); }; }