Skip to content

Commit 6151c97

Browse files
committed
[pointer][WIP] Transmute
gherrit-pr-id: Iad14813bc6d933312bc8d7a1ddcf1aafc7126938
1 parent daf3a21 commit 6151c97

File tree

11 files changed

+678
-726
lines changed

11 files changed

+678
-726
lines changed

src/impls.rs

Lines changed: 84 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -417,13 +417,14 @@ mod atomics {
417417
use super::*;
418418

419419
macro_rules! impl_traits_for_atomics {
420-
($($atomics:ident),* $(,)?) => {
420+
($($atomics:ident [$primitives:ident]),* $(,)?) => {
421421
$(
422+
impl_size_eq!($atomics, $primitives);
422423
impl_known_layout!($atomics);
423-
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
424-
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
425-
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
426-
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
424+
impl_for_transmute_from!(=> TryFromBytes for $atomics [UnsafeCell<$primitives>]);
425+
impl_for_transparent_wrapper!(=> FromZeros for $atomics [UnsafeCell<$primitives>]);
426+
impl_for_transparent_wrapper!(=> FromBytes for $atomics [UnsafeCell<$primitives>]);
427+
impl_for_transparent_wrapper!(=> IntoBytes for $atomics [UnsafeCell<$primitives>]);
427428
)*
428429
};
429430
}
@@ -435,13 +436,14 @@ mod atomics {
435436

436437
use super::*;
437438

438-
impl_traits_for_atomics!(AtomicU8, AtomicI8);
439+
impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);
439440

441+
impl_size_eq!(AtomicBool, bool);
440442
impl_known_layout!(AtomicBool);
441443

442-
impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
443-
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
444-
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
444+
impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell<bool>]);
445+
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool [UnsafeCell<bool>]);
446+
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool [UnsafeCell<bool>]);
445447

446448
safety_comment! {
447449
/// SAFETY:
@@ -468,10 +470,8 @@ mod atomics {
468470
unsafe_impl!(AtomicI8: Unaligned);
469471
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
470472

471-
/// SAFETY:
472-
/// All of these pass an atomic type and that type's native equivalent, as
473-
/// required by the macro safety preconditions.
474-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
473+
/// SAFETY: TODO
474+
unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
475475
}
476476
}
477477

@@ -482,13 +482,11 @@ mod atomics {
482482

483483
use super::*;
484484

485-
impl_traits_for_atomics!(AtomicU16, AtomicI16);
485+
impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]);
486486

487487
safety_comment! {
488-
/// SAFETY:
489-
/// All of these pass an atomic type and that type's native equivalent, as
490-
/// required by the macro safety preconditions.
491-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
488+
/// SAFETY: TODO
489+
unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
492490
}
493491
}
494492

@@ -499,13 +497,11 @@ mod atomics {
499497

500498
use super::*;
501499

502-
impl_traits_for_atomics!(AtomicU32, AtomicI32);
500+
impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
503501

504502
safety_comment! {
505-
/// SAFETY:
506-
/// All of these pass an atomic type and that type's native equivalent, as
507-
/// required by the macro safety preconditions.
508-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
503+
/// SAFETY: TODO
504+
unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
509505
}
510506
}
511507

@@ -516,13 +512,11 @@ mod atomics {
516512

517513
use super::*;
518514

519-
impl_traits_for_atomics!(AtomicU64, AtomicI64);
515+
impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
520516

521517
safety_comment! {
522-
/// SAFETY:
523-
/// All of these pass an atomic type and that type's native equivalent, as
524-
/// required by the macro safety preconditions.
525-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
518+
/// SAFETY: TODO
519+
unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
526520
}
527521
}
528522

@@ -533,21 +527,27 @@ mod atomics {
533527

534528
use super::*;
535529

536-
impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
530+
impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
537531

538532
impl_known_layout!(T => AtomicPtr<T>);
539533

534+
// SAFETY: `AtomicPtr<T>` and `*mut T` have the same size [1].
535+
//
536+
// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html:
537+
//
538+
// This type has the same size and bit validity as a `*mut T`.
539+
unsafe impl<T> crate::pointer::SizeEq<*mut T> for AtomicPtr<T> {}
540+
// SAFETY: See previous safety comment.
541+
unsafe impl<T> crate::pointer::SizeEq<AtomicPtr<T>> for *mut T {}
542+
540543
// TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement
541544
// those traits for `*mut T`.
542-
impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr<T>);
543-
impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T>);
545+
impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T> [UnsafeCell<*mut T>]);
544546

545547
safety_comment! {
546-
/// SAFETY:
547-
/// This passes an atomic type and that type's native equivalent, as
548-
/// required by the macro safety preconditions.
549-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
550-
unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
548+
/// SAFETY: TODO
549+
unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
550+
unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]);
551551
}
552552
}
553553
}
@@ -577,12 +577,12 @@ safety_comment! {
577577
assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
578578
}
579579

580-
impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping<T>);
581-
impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping<T>);
582-
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>);
583-
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>);
584-
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>);
585-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping<T>);
580+
unsafe_impl!(T: Immutable => Immutable for Wrapping<T>);
581+
impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
582+
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>[T]);
583+
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>[T]);
584+
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
585+
unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>);
586586
assert_unaligned!(Wrapping<()>, Wrapping<u8>);
587587

588588
safety_comment! {
@@ -594,22 +594,52 @@ safety_comment! {
594594
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
595595
}
596596

597-
impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit<T>);
598-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
597+
unsafe_impl!(T: Immutable => Immutable for CoreMaybeUninit<T>);
598+
unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
599599
assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<u8>);
600600

601-
impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
602-
impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>);
603-
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>);
604-
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
605-
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>);
606-
impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
601+
unsafe_impl!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
602+
603+
// SAFETY: See inline safety comment justifying that the implementation of
604+
// `is_bit_valid`is sound.
605+
unsafe impl<T: ?Sized + TryFromBytes> TryFromBytes for ManuallyDrop<T> {
606+
#[allow(clippy::missing_inline_in_public_items)]
607+
fn only_derive_is_allowed_to_implement_this_trait() {}
608+
609+
#[inline(always)]
610+
fn is_bit_valid<A: crate::pointer::invariant::Reference>(
611+
candidate: Maybe<'_, Self, A>,
612+
) -> bool {
613+
// SAFETY: `ManuallyDrop<T>` and `T` have the same size [1], so this
614+
// cast preserves size. It also preserves provenance.
615+
//
616+
// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
617+
//
618+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
619+
// validity as `T`
620+
let c: Maybe<'_, T, A> = unsafe { candidate.cast_unsized(|p| cast!(p => NonNull<_>)) };
621+
622+
// SAFETY: `ManuallyDrop<T>` and `T` have the same bit validity [1], so
623+
// this is a sound implementation of `ManuallyDrop::is_bit_valid`.
624+
//
625+
// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
626+
//
627+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
628+
// validity as `T`
629+
<T as TryFromBytes>::is_bit_valid(c)
630+
}
631+
}
632+
633+
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
634+
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
635+
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
636+
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
607637
assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
608638

609-
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>);
610-
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>);
611-
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>);
612-
impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
639+
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
640+
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
641+
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
642+
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
613643
assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
614644

615645
// SAFETY: See safety comment in `is_bit_valid` impl.

src/lib.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,14 @@ pub unsafe trait KnownLayout {
805805
// resulting size would not fit in a `usize`.
806806
meta.size_for_metadata(Self::LAYOUT)
807807
}
808+
809+
fn cast_from_raw<P: KnownLayout<PointerMetadata = Self::PointerMetadata> + ?Sized>(
810+
ptr: NonNull<P>,
811+
) -> NonNull<Self> {
812+
let data = ptr.cast::<u8>();
813+
let meta = P::pointer_to_metadata(ptr.as_ptr());
814+
Self::raw_from_ptr_len(data, meta)
815+
}
808816
}
809817

810818
/// The metadata associated with a [`KnownLayout`] type.
@@ -2843,15 +2851,15 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
28432851
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
28442852
// to add a `T: Immutable` bound.
28452853
let c_ptr = Ptr::from_mut(&mut candidate);
2846-
let c_ptr = c_ptr.transparent_wrapper_into_inner();
28472854
// SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from
28482855
// `candidate`, which the caller promises is entirely initialized. Since
28492856
// `candidate` is a `MaybeUninit`, it has no validity requirements, and so
2850-
// no values written to `c_ptr` can violate its validity. Since `c_ptr` has
2851-
// `Exclusive` aliasing, no mutations may happen except via `c_ptr` so long
2852-
// as it is live, so we don't need to worry about the fact that `c_ptr` may
2853-
// have more restricted validity than `candidate`.
2857+
// no values written to an `Initialized` `c_ptr` can violate its validity.
2858+
// Since `c_ptr` has `Exclusive` aliasing, no mutations may happen except
2859+
// via `c_ptr` so long as it is live, so we don't need to worry about the
2860+
// fact that `c_ptr` may have more restricted validity than `candidate`.
28542861
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };
2862+
let c_ptr = c_ptr.transmute();
28552863

28562864
// This call may panic. If that happens, it doesn't cause any soundness
28572865
// issues, as we have not generated any invalid state which we need to
@@ -2861,7 +2869,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
28612869
// calling `try_into_valid` (and thus `is_bit_valid`) with a shared
28622870
// pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic
28632871
// condition will not happen.
2864-
if !T::is_bit_valid(c_ptr.forget_aligned()) {
2872+
if !util::SizedKnownLayout::<T>::is_bit_valid(c_ptr.forget_aligned()) {
28652873
return Err(ValidityError::new(source).into());
28662874
}
28672875

@@ -4258,7 +4266,9 @@ pub unsafe trait FromBytes: FromZeros {
42584266
let source = Ptr::from_mut(source);
42594267
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
42604268
match maybe_slf {
4261-
Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()),
4269+
Ok(slf) => Ok(slf
4270+
.bikeshed_recall_valid::<(_, (_, (BecauseExclusive, BecauseExclusive)))>()
4271+
.as_mut()),
42624272
Err(err) => Err(err.map_src(|s| s.as_mut())),
42634273
}
42644274
}
@@ -4728,7 +4738,7 @@ fn ref_from_prefix_suffix<T: FromBytes + KnownLayout + Immutable + ?Sized>(
47284738
/// If there are insufficient bytes, or if that affix of `source` is not
47294739
/// appropriately aligned, this returns `Err`.
47304740
#[inline(always)]
4731-
fn mut_from_prefix_suffix<T: FromBytes + KnownLayout + ?Sized>(
4741+
fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
47324742
source: &mut [u8],
47334743
meta: Option<T::PointerMetadata>,
47344744
cast_type: CastType,

src/pointer/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ mod inner;
1212
#[doc(hidden)]
1313
pub mod invariant;
1414
mod ptr;
15+
mod transmute;
1516

1617
#[doc(hidden)]
17-
pub use invariant::{BecauseExclusive, BecauseImmutable, Read};
18+
pub(crate) use transmute::*;
1819
#[doc(hidden)]
19-
pub use ptr::Ptr;
20+
pub use {
21+
invariant::{BecauseExclusive, BecauseImmutable, Read},
22+
ptr::Ptr,
23+
};
2024

2125
use crate::Unaligned;
2226

0 commit comments

Comments
 (0)