diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index b31e317b6d..48cd06b3c1 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -29,12 +29,9 @@ use core::{ use crate::{ pointer::{ - cast::{CastSized, IdCast}, - invariant::{ - Aligned, BecauseExclusive, BecauseImmutable, Initialized, Invariants, Read, Reference, - Unaligned, Valid, - }, - BecauseInvariantsEq, TryTransmuteFromPtr, + cast::CastSized, + invariant::{Aligned, Initialized, Valid}, + BecauseInvariantsEq, }, FromBytes, Immutable, IntoBytes, KnownLayout, Ptr, ReadOnly, TryFromBytes, ValidityError, }; @@ -603,60 +600,6 @@ pub const fn hash_name(name: &str) -> i128 { i128::from_ne_bytes(hash.to_ne_bytes()) } -/// Is a given source a valid instance of `Dst`? -/// -/// If so, returns `src` casted to a `Ptr`. Otherwise returns `None`. -/// -/// # Safety -/// -/// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Ok`, -/// `*src` is a bit-valid instance of `Dst`, and that the size of `Src` is -/// greater than or equal to the size of `Dst`. -/// -/// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Err`, the -/// encapsulated `Ptr` value is the original `src`. `try_cast_or_pme` cannot -/// guarantee that the referent has not been modified, as it calls user-defined -/// code (`TryFromBytes::is_bit_valid`). -/// -/// # Panics -/// -/// `try_cast_or_pme` may either produce a post-monomorphization error or a -/// panic if `Dst` not the same size as `Src`. Otherwise, `try_cast_or_pme` -/// panics under the same circumstances as [`is_bit_valid`]. -/// -/// [`is_bit_valid`]: TryFromBytes::is_bit_valid -#[doc(hidden)] -#[inline] -fn try_cast_or_pme( - src: Ptr<'_, Src, I>, -) -> Result, ValidityError, Dst>> -where - // FIXME(#2226): There should be a `Src: FromBytes` bound here, but doing so - // requires deeper surgery. - Src: Read, - Dst: TryFromBytes - + Read - + TryTransmuteFromPtr, - ReadOnly: Read, - I: Invariants, - I::Aliasing: Reference, -{ - let c_ptr = src.cast::<_, CastSized, _>(); - match c_ptr.try_into_valid() { - Ok(ptr) => Ok(ptr), - Err(err) => { - // Re-cast `Ptr` to `Ptr`. - let ptr = err.into_src(); - let ptr = ptr.cast::<_, CastSized, _>(); - // SAFETY: `ptr` is `src`, and has the same alignment invariant. - let ptr = unsafe { ptr.assume_alignment::() }; - // SAFETY: `ptr` is `src` and has the same validity invariant. - let ptr = unsafe { ptr.assume_validity::() }; - Err(ValidityError::new(ptr.unify_invariants())) - } - } -} - /// Attempts to transmute `Src` into `Dst`. /// /// A helper for `try_transmute!`. @@ -677,32 +620,28 @@ where static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); let mu_src = mem::MaybeUninit::new(src); - // SAFETY: By invariant on `&`, the following are satisfied: - // - `&mu_src` is valid for reads - // - `&mu_src` is properly aligned - // - `&mu_src`'s referent is bit-valid - let mu_src_copy = unsafe { core::ptr::read(&mu_src) }; - // SAFETY: `MaybeUninit` has no validity constraints. + // SAFETY: `MaybeUninit` has no validity requirements. let mu_dst: mem::MaybeUninit> = - unsafe { crate::util::transmute_unchecked(mu_src_copy) }; + unsafe { crate::util::transmute_unchecked(mu_src) }; let ptr = Ptr::from_ref(&mu_dst); // SAFETY: Since `Src: IntoBytes`, and since `size_of::() == // size_of::()` by the preceding assertion, all of `mu_dst`'s bytes are - // initialized. + // initialized. `MaybeUninit` has no validity requirements, so even if + // `ptr` is used to mutate its referent (which it actually can't be - it's + // a shared `ReadOnly` pointer), that won't violate its referent's validity. let ptr = unsafe { ptr.assume_validity::() }; - - let ptr: Ptr<'_, ReadOnly, _> = ptr.cast::<_, crate::pointer::cast::CastSized, _>(); - - if Dst::is_bit_valid(ptr.transmute::<_, _, BecauseImmutable>().forget_aligned()) { + if Dst::is_bit_valid(ptr.cast::<_, CastSized, _>()) { // SAFETY: Since `Dst::is_bit_valid`, we know that `ptr`'s referent is // bit-valid for `Dst`. `ptr` points to `mu_dst`, and no intervening // operations have mutated it, so it is a bit-valid `Dst`. Ok(ReadOnly::into_inner(unsafe { mu_dst.assume_init() })) } else { - // SAFETY: `mu_src` was constructed from `src` and never modified, so it - // is still bit-valid. + // SAFETY: `MaybeUninit` has no validity requirements. + let mu_src: mem::MaybeUninit = unsafe { crate::util::transmute_unchecked(mu_dst) }; + // SAFETY: `mu_dst`/`mu_src` was constructed from `src` and never + // modified, so it is still bit-valid. Err(ValidityError::new(unsafe { mu_src.assume_init() })) } } @@ -727,7 +666,8 @@ where { let ptr = Ptr::from_ref(src); let ptr = ptr.recall_validity::(); - match try_cast_or_pme::(ptr) { + let ptr = ptr.cast::<_, CastSized, _>(); + match ptr.try_into_valid() { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter @@ -736,13 +676,17 @@ where Ok(ptr.as_ref()) } Err(err) => Err(err.map_src(|ptr| { + let ptr = ptr.cast::<_, CastSized, _>(); + // SAFETY: `ptr` has the same address as `src: &Src`, which is + // aligned by invariant on `&Src`. + let ptr = unsafe { ptr.assume_alignment::() }; // SAFETY: Because `Src: Immutable` and we create a `Ptr` via // `Ptr::from_ref`, the resulting `Ptr` is a shared-and-`Immutable` // `Ptr`, which does not permit mutation of its referent. Therefore, // no mutation could have happened during the call to - // `try_cast_or_pme` (any such mutation would be unsound). + // `try_into_valid` (any such mutation would be unsound). // - // `try_cast_or_pme` promises to return its original argument, and + // `try_into_valid` promises to return its original argument, and // so we know that we are getting back the same `ptr` that we // originally passed, and that `ptr` was a bit-valid `Src`. let ptr = unsafe { ptr.assume_valid() }; @@ -771,7 +715,8 @@ where { let ptr = Ptr::from_mut(src); let ptr = ptr.recall_validity::(); - match try_cast_or_pme::(ptr) { + let ptr = ptr.cast::<_, CastSized, _>(); + match ptr.try_into_valid() { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter @@ -780,7 +725,13 @@ where Ok(ptr.as_mut()) } Err(err) => { - Err(err.map_src(|ptr| ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut())) + Err(err.map_src(|ptr| { + let ptr = ptr.cast::<_, CastSized, _>(); + // SAFETY: `ptr` has the same address as `src: &mut Src`, which + // is aligned by invariant on `&mut Src`. + let ptr = unsafe { ptr.assume_alignment::() }; + ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut() + })) } } } @@ -895,15 +846,15 @@ where #[inline(always)] fn transmute_ref(self) -> &'a Dst { - static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { - Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() - }, "cannot transmute reference when destination type has higher alignment than source type"); - let ptr = Ptr::from_ref(self.0) .recall_validity::() .transmute_with::, (crate::pointer::BecauseMutationCompatible, _)>() .recall_validity::(); + static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { + Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() + }, "cannot transmute reference when destination type has higher alignment than source type"); + // SAFETY: The preceding `static_assert!` ensures that // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is // validly-aligned for `Src`, it is also validly-aligned for `Dst`. @@ -928,16 +879,15 @@ where #[inline(always)] fn transmute_mut(self) -> &'a mut Dst { - static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { - Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() - }, "cannot transmute reference when destination type has higher alignment than source type"); - let ptr = Ptr::from_mut(self.0) .recall_validity::() .transmute_with::, _>() .recall_validity::(); - #[allow(unused_unsafe)] + static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { + Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() + }, "cannot transmute reference when destination type has higher alignment than source type"); + // SAFETY: The preceding `static_assert!` ensures that // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is // validly-aligned for `Src`, it is also validly-aligned for `Dst`. diff --git a/zerocopy-derive/tests/ui-nightly/enum.stderr b/zerocopy-derive/tests/ui-nightly/enum.stderr index c98d56f538..5d6f4a92cb 100644 --- a/zerocopy-derive/tests/ui-nightly/enum.stderr +++ b/zerocopy-derive/tests/ui-nightly/enum.stderr @@ -482,7 +482,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -504,7 +504,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -526,7 +526,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index 09048d0194..30fcb20fb1 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -325,7 +325,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -347,7 +347,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -405,7 +405,7 @@ help: the trait `DynamicPaddingFree` is not implemented for `( but trait `DynamicPaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 86 | impl DynamicPaddingFree for () {} + 83 | impl DynamicPaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -427,7 +427,7 @@ help: the trait `DynamicPaddingFree` is not implemented for `( but trait `DynamicPaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 86 | impl DynamicPaddingFree for () {} + 83 | impl DynamicPaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -449,7 +449,7 @@ help: the trait `DynamicPaddingFree` is not implemented for `( but trait `DynamicPaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 86 | impl DynamicPaddingFree for () {} + 83 | impl DynamicPaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/enum.stderr b/zerocopy-derive/tests/ui-stable/enum.stderr index 3a7ad04a94..24d0c42799 100644 --- a/zerocopy-derive/tests/ui-stable/enum.stderr +++ b/zerocopy-derive/tests/ui-stable/enum.stderr @@ -439,7 +439,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -457,7 +457,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -475,7 +475,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index 6f45e48c6c..4adff4acef 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -293,7 +293,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -311,7 +311,7 @@ help: the trait `PaddingFree` is not implemented for `()` but trait `PaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 68 | impl PaddingFree for () {} + 65 | impl PaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -365,7 +365,7 @@ help: the trait `DynamicPaddingFree` is not implemented for `( but trait `DynamicPaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 86 | impl DynamicPaddingFree for () {} + 83 | impl DynamicPaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -383,7 +383,7 @@ help: the trait `DynamicPaddingFree` is not implemented for `( but trait `DynamicPaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 86 | impl DynamicPaddingFree for () {} + 83 | impl DynamicPaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -401,7 +401,7 @@ help: the trait `DynamicPaddingFree` is not implemented for `( but trait `DynamicPaddingFree` is implemented for it --> $WORKSPACE/src/util/macro_util.rs | - 86 | impl DynamicPaddingFree for () {} + 83 | impl DynamicPaddingFree for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)