Skip to content

Commit 9499d41

Browse files
committed
Simplify try_transmute! (and friends) internals
gherrit-pr-id: G5520d1263ed335298ddd307e45c38b41ff28aa90
1 parent fb1eaa5 commit 9499d41

1 file changed

Lines changed: 36 additions & 90 deletions

File tree

src/util/macro_util.rs

Lines changed: 36 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ use core::{
2828
};
2929

3030
use crate::{
31-
pointer::{
32-
cast::{CastSized, IdCast},
33-
invariant::{self, BecauseExclusive, BecauseImmutable, Invariants},
34-
BecauseInvariantsEq, Read, TryTransmuteFromPtr,
35-
},
31+
pointer::{cast::CastSized, invariant, BecauseInvariantsEq},
3632
FromBytes, Immutable, IntoBytes, KnownLayout, Ptr, ReadOnly, TryFromBytes, ValidityError,
3733
};
3834

@@ -600,63 +596,6 @@ pub const fn hash_name(name: &str) -> i128 {
600596
i128::from_ne_bytes(hash.to_ne_bytes())
601597
}
602598

603-
/// Is a given source a valid instance of `Dst`?
604-
///
605-
/// If so, returns `src` casted to a `Ptr<Dst, _>`. Otherwise returns `None`.
606-
///
607-
/// # Safety
608-
///
609-
/// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Ok`,
610-
/// `*src` is a bit-valid instance of `Dst`, and that the size of `Src` is
611-
/// greater than or equal to the size of `Dst`.
612-
///
613-
/// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Err`, the
614-
/// encapsulated `Ptr` value is the original `src`. `try_cast_or_pme` cannot
615-
/// guarantee that the referent has not been modified, as it calls user-defined
616-
/// code (`TryFromBytes::is_bit_valid`).
617-
///
618-
/// # Panics
619-
///
620-
/// `try_cast_or_pme` may either produce a post-monomorphization error or a
621-
/// panic if `Dst` not the same size as `Src`. Otherwise, `try_cast_or_pme`
622-
/// panics under the same circumstances as [`is_bit_valid`].
623-
///
624-
/// [`is_bit_valid`]: TryFromBytes::is_bit_valid
625-
#[doc(hidden)]
626-
#[inline]
627-
fn try_cast_or_pme<Src, Dst, I, R, S>(
628-
src: Ptr<'_, Src, I>,
629-
) -> Result<
630-
Ptr<'_, Dst, (I::Aliasing, invariant::Unaligned, invariant::Valid)>,
631-
ValidityError<Ptr<'_, Src, I>, Dst>,
632-
>
633-
where
634-
// FIXME(#2226): There should be a `Src: FromBytes` bound here, but doing so
635-
// requires deeper surgery.
636-
Src: invariant::Read<I::Aliasing, R>,
637-
Dst: TryFromBytes
638-
+ invariant::Read<I::Aliasing, R>
639-
+ TryTransmuteFromPtr<Dst, I::Aliasing, invariant::Initialized, invariant::Valid, IdCast, S>,
640-
ReadOnly<Dst>: Read<I::Aliasing, R>,
641-
I: Invariants<Validity = invariant::Initialized>,
642-
I::Aliasing: invariant::Reference,
643-
{
644-
let c_ptr = src.cast::<_, CastSized, _>();
645-
match c_ptr.try_into_valid() {
646-
Ok(ptr) => Ok(ptr),
647-
Err(err) => {
648-
// Re-cast `Ptr<Dst>` to `Ptr<Src>`.
649-
let ptr = err.into_src();
650-
let ptr = ptr.cast::<_, CastSized, _>();
651-
// SAFETY: `ptr` is `src`, and has the same alignment invariant.
652-
let ptr = unsafe { ptr.assume_alignment::<I::Alignment>() };
653-
// SAFETY: `ptr` is `src` and has the same validity invariant.
654-
let ptr = unsafe { ptr.assume_validity::<I::Validity>() };
655-
Err(ValidityError::new(ptr.unify_invariants()))
656-
}
657-
}
658-
}
659-
660599
/// Attempts to transmute `Src` into `Dst`.
661600
///
662601
/// A helper for `try_transmute!`.
@@ -677,32 +616,28 @@ where
677616
static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>());
678617

679618
let mu_src = mem::MaybeUninit::new(src);
680-
// SAFETY: By invariant on `&`, the following are satisfied:
681-
// - `&mu_src` is valid for reads
682-
// - `&mu_src` is properly aligned
683-
// - `&mu_src`'s referent is bit-valid
684-
let mu_src_copy = unsafe { core::ptr::read(&mu_src) };
685-
// SAFETY: `MaybeUninit` has no validity constraints.
619+
// SAFETY: `MaybeUninit` has no validity requirements.
686620
let mu_dst: mem::MaybeUninit<ReadOnly<Dst>> =
687-
unsafe { crate::util::transmute_unchecked(mu_src_copy) };
621+
unsafe { crate::util::transmute_unchecked(mu_src) };
688622

689623
let ptr = Ptr::from_ref(&mu_dst);
690624

691625
// SAFETY: Since `Src: IntoBytes`, and since `size_of::<Src>() ==
692626
// size_of::<Dst>()` by the preceding assertion, all of `mu_dst`'s bytes are
693-
// initialized.
627+
// initialized. `MaybeUninit` has no validity requirements, so even if
628+
// `ptr` is used to mutate its referent (which it actually can't be - it's
629+
// a shared `ReadOnly` pointer), that won't violate its referent's validity.
694630
let ptr = unsafe { ptr.assume_validity::<invariant::Initialized>() };
695-
696-
let ptr: Ptr<'_, ReadOnly<Dst>, _> = ptr.cast::<_, crate::pointer::cast::CastSized, _>();
697-
698-
if Dst::is_bit_valid(ptr.transmute::<_, _, BecauseImmutable>().forget_aligned()) {
631+
if Dst::is_bit_valid(ptr.cast::<_, CastSized, _>()) {
699632
// SAFETY: Since `Dst::is_bit_valid`, we know that `ptr`'s referent is
700633
// bit-valid for `Dst`. `ptr` points to `mu_dst`, and no intervening
701634
// operations have mutated it, so it is a bit-valid `Dst`.
702635
Ok(ReadOnly::into_inner(unsafe { mu_dst.assume_init() }))
703636
} else {
704-
// SAFETY: `mu_src` was constructed from `src` and never modified, so it
705-
// is still bit-valid.
637+
// SAFETY: `MaybeUninit` has no validity requirements.
638+
let mu_src: mem::MaybeUninit<Src> = unsafe { crate::util::transmute_unchecked(mu_dst) };
639+
// SAFETY: `mu_dst`/`mu_src` was constructed from `src` and never
640+
// modified, so it is still bit-valid.
706641
Err(ValidityError::new(unsafe { mu_src.assume_init() }))
707642
}
708643
}
@@ -727,7 +662,8 @@ where
727662
{
728663
let ptr = Ptr::from_ref(src);
729664
let ptr = ptr.recall_validity::<invariant::Initialized, _>();
730-
match try_cast_or_pme::<Src, Dst, _, BecauseImmutable, _>(ptr) {
665+
let ptr = ptr.cast::<_, CastSized, _>();
666+
match ptr.try_into_valid() {
731667
Ok(ptr) => {
732668
static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>());
733669
// SAFETY: We have checked that `Dst` does not have a stricter
@@ -736,13 +672,17 @@ where
736672
Ok(ptr.as_ref())
737673
}
738674
Err(err) => Err(err.map_src(|ptr| {
675+
let ptr = ptr.cast::<_, CastSized, _>();
676+
// SAFETY: `ptr` has the same address as `src: &Src`, which is
677+
// aligned by invariant on `&Src`.
678+
let ptr = unsafe { ptr.assume_alignment::<invariant::Aligned>() };
739679
// SAFETY: Because `Src: Immutable` and we create a `Ptr` via
740680
// `Ptr::from_ref`, the resulting `Ptr` is a shared-and-`Immutable`
741681
// `Ptr`, which does not permit mutation of its referent. Therefore,
742682
// no mutation could have happened during the call to
743-
// `try_cast_or_pme` (any such mutation would be unsound).
683+
// `try_into_valid` (any such mutation would be unsound).
744684
//
745-
// `try_cast_or_pme` promises to return its original argument, and
685+
// `try_into_valid` promises to return its original argument, and
746686
// so we know that we are getting back the same `ptr` that we
747687
// originally passed, and that `ptr` was a bit-valid `Src`.
748688
let ptr = unsafe { ptr.assume_valid() };
@@ -771,7 +711,8 @@ where
771711
{
772712
let ptr = Ptr::from_mut(src);
773713
let ptr = ptr.recall_validity::<invariant::Initialized, (_, (_, _))>();
774-
match try_cast_or_pme::<Src, Dst, _, BecauseExclusive, _>(ptr) {
714+
let ptr = ptr.cast::<_, CastSized, _>();
715+
match ptr.try_into_valid() {
775716
Ok(ptr) => {
776717
static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>());
777718
// SAFETY: We have checked that `Dst` does not have a stricter
@@ -780,7 +721,13 @@ where
780721
Ok(ptr.as_mut())
781722
}
782723
Err(err) => {
783-
Err(err.map_src(|ptr| ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut()))
724+
Err(err.map_src(|ptr| {
725+
let ptr = ptr.cast::<_, CastSized, _>();
726+
// SAFETY: `ptr` has the same address as `src: &mut Src`, which
727+
// is aligned by invariant on `&mut Src`.
728+
let ptr = unsafe { ptr.assume_alignment::<invariant::Aligned>() };
729+
ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut()
730+
}))
784731
}
785732
}
786733
}
@@ -895,15 +842,15 @@ where
895842

896843
#[inline(always)]
897844
fn transmute_ref(self) -> &'a Dst {
898-
static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
899-
Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
900-
}, "cannot transmute reference when destination type has higher alignment than source type");
901-
902845
let ptr = Ptr::from_ref(self.0)
903846
.recall_validity::<invariant::Initialized, _>()
904847
.transmute_with::<Dst, invariant::Initialized, crate::layout::CastFrom<Dst>, (crate::pointer::BecauseMutationCompatible, _)>()
905848
.recall_validity::<invariant::Valid, _>();
906849

850+
static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
851+
Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
852+
}, "cannot transmute reference when destination type has higher alignment than source type");
853+
907854
// SAFETY: The preceding `static_assert!` ensures that
908855
// `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is
909856
// validly-aligned for `Src`, it is also validly-aligned for `Dst`.
@@ -928,16 +875,15 @@ where
928875

929876
#[inline(always)]
930877
fn transmute_mut(self) -> &'a mut Dst {
931-
static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
932-
Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
933-
}, "cannot transmute reference when destination type has higher alignment than source type");
934-
935878
let ptr = Ptr::from_mut(self.0)
936879
.recall_validity::<invariant::Initialized, (_, (_, _))>()
937880
.transmute_with::<Dst, invariant::Initialized, crate::layout::CastFrom<Dst>, _>()
938881
.recall_validity::<invariant::Valid, (_, (_, _))>();
939882

940-
#[allow(unused_unsafe)]
883+
static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
884+
Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
885+
}, "cannot transmute reference when destination type has higher alignment than source type");
886+
941887
// SAFETY: The preceding `static_assert!` ensures that
942888
// `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is
943889
// validly-aligned for `Src`, it is also validly-aligned for `Dst`.

0 commit comments

Comments
 (0)