Skip to content

Commit c640f3e

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

File tree

11 files changed

+684
-711
lines changed

11 files changed

+684
-711
lines changed

src/impls.rs

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -417,13 +417,15 @@ 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!(=> TryFromBytes for $atomics);
426+
impl_for_transparent_wrapper!(=> FromZeros for $atomics [UnsafeCell<$primitives>]);
427+
impl_for_transparent_wrapper!(=> FromBytes for $atomics [UnsafeCell<$primitives>]);
428+
impl_for_transparent_wrapper!(=> IntoBytes for $atomics [UnsafeCell<$primitives>]);
427429
)*
428430
};
429431
}
@@ -435,13 +437,15 @@ mod atomics {
435437

436438
use super::*;
437439

438-
impl_traits_for_atomics!(AtomicU8, AtomicI8);
440+
impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);
439441

442+
impl_size_eq!(AtomicBool, bool);
440443
impl_known_layout!(AtomicBool);
441444

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

446450
safety_comment! {
447451
/// SAFETY:
@@ -471,7 +475,8 @@ mod atomics {
471475
/// SAFETY:
472476
/// All of these pass an atomic type and that type's native equivalent, as
473477
/// required by the macro safety preconditions.
474-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
478+
// unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
479+
unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
475480
}
476481
}
477482

@@ -482,13 +487,14 @@ mod atomics {
482487

483488
use super::*;
484489

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

487492
safety_comment! {
488493
/// SAFETY:
489494
/// All of these pass an atomic type and that type's native equivalent, as
490495
/// required by the macro safety preconditions.
491-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
496+
// unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
497+
unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
492498
}
493499
}
494500

@@ -499,13 +505,14 @@ mod atomics {
499505

500506
use super::*;
501507

502-
impl_traits_for_atomics!(AtomicU32, AtomicI32);
508+
impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
503509

504510
safety_comment! {
505511
/// SAFETY:
506512
/// All of these pass an atomic type and that type's native equivalent, as
507513
/// required by the macro safety preconditions.
508-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
514+
// unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
515+
unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
509516
}
510517
}
511518

@@ -516,13 +523,14 @@ mod atomics {
516523

517524
use super::*;
518525

519-
impl_traits_for_atomics!(AtomicU64, AtomicI64);
526+
impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
520527

521528
safety_comment! {
522529
/// SAFETY:
523530
/// All of these pass an atomic type and that type's native equivalent, as
524531
/// required by the macro safety preconditions.
525-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
532+
// unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
533+
unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
526534
}
527535
}
528536

@@ -533,21 +541,34 @@ mod atomics {
533541

534542
use super::*;
535543

536-
impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
544+
impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
537545

538546
impl_known_layout!(T => AtomicPtr<T>);
539547

548+
// SAFETY: `AtomicPtr<T>` and `*mut T` have the same size [1].
549+
//
550+
// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html:
551+
//
552+
// This type has the same size and bit validity as a `*mut T`.
553+
unsafe impl<T> crate::pointer::SizeEq<*mut T> for AtomicPtr<T> {}
554+
// SAFETY: See previous safety comment.
555+
unsafe impl<T> crate::pointer::SizeEq<AtomicPtr<T>> for *mut T {}
556+
540557
// TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement
541558
// 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>);
559+
// impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr<T>);
560+
impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T> [UnsafeCell<*mut T>]);
561+
// impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T> [UnsafeCell<*mut T>]);
544562

545563
safety_comment! {
546564
/// SAFETY:
547565
/// This passes an atomic type and that type's native equivalent, as
548566
/// 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]);
567+
// unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
568+
// unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
569+
570+
unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
571+
unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]);
551572
}
552573
}
553574
}
@@ -577,12 +598,12 @@ safety_comment! {
577598
assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
578599
}
579600

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>);
601+
unsafe_impl!(T: Immutable => Immutable for Wrapping<T>);
602+
impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
603+
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>[T]);
604+
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>[T]);
605+
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
606+
unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>);
586607
assert_unaligned!(Wrapping<()>, Wrapping<u8>);
587608

588609
safety_comment! {
@@ -594,22 +615,52 @@ safety_comment! {
594615
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
595616
}
596617

597-
impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit<T>);
598-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
618+
unsafe_impl!(T: Immutable => Immutable for CoreMaybeUninit<T>);
619+
unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
599620
assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<u8>);
600621

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>);
622+
unsafe_impl!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
623+
624+
// SAFETY: See inline safety comment justifying that the implementation of
625+
// `is_bit_valid`is sound.
626+
unsafe impl<T: ?Sized + TryFromBytes> TryFromBytes for ManuallyDrop<T> {
627+
#[allow(clippy::missing_inline_in_public_items)]
628+
fn only_derive_is_allowed_to_implement_this_trait() {}
629+
630+
#[inline(always)]
631+
fn is_bit_valid<A: crate::pointer::invariant::Reference>(
632+
candidate: Maybe<'_, Self, A>,
633+
) -> bool {
634+
// SAFETY: `ManuallyDrop<T>` and `T` have the same size [1], so this
635+
// cast preserves size. It also preserves provenance.
636+
//
637+
// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
638+
//
639+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
640+
// validity as `T`
641+
let c: Maybe<'_, T, A> = unsafe { candidate.cast_unsized(|p| cast!(p => NonNull<_>)) };
642+
643+
// SAFETY: `ManuallyDrop<T>` and `T` have the same bit validity [1], so
644+
// this is a sound implementation of `ManuallyDrop::is_bit_valid`.
645+
//
646+
// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
647+
//
648+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
649+
// validity as `T`
650+
<T as TryFromBytes>::is_bit_valid(c)
651+
}
652+
}
653+
654+
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
655+
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
656+
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
657+
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
607658
assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
608659

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>);
660+
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
661+
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
662+
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
663+
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
613664
assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
614665

615666
// 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)