Skip to content

Commit bbf07a8

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

File tree

11 files changed

+763
-722
lines changed

11 files changed

+763
-722
lines changed

src/impls.rs

Lines changed: 160 additions & 50 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:
@@ -469,9 +471,28 @@ mod atomics {
469471
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
470472

471473
/// 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]);
474+
/// `AtomicU8`, `AtomicI8`, and `AtomicBool` have the same size and
475+
/// bit validity as `u8`, `i8`, and `bool` respectively [1][2][3].
476+
///
477+
/// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU8.html:
478+
///
479+
/// This type has the same size, alignment, and bit validity as
480+
/// the underlying integer type, `u8`.
481+
///
482+
/// [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI8.html:
483+
///
484+
/// This type has the same size, alignment, and bit validity as
485+
/// the underlying integer type, `i8`.
486+
///
487+
/// [3] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicBool.html:
488+
///
489+
/// This type has the same size, alignment, and bit validity a
490+
/// `bool`.
491+
unsafe_impl_transmute_from_for_atomic!(
492+
=> AtomicU8 [u8],
493+
=> AtomicI8 [i8],
494+
=> AtomicBool [bool]
495+
);
475496
}
476497
}
477498

@@ -482,13 +503,23 @@ mod atomics {
482503

483504
use super::*;
484505

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

487508
safety_comment! {
488509
/// 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]);
510+
/// `AtomicU16` and `AtomicI16` have the same size and bit validity
511+
/// as `u16` and `i16` respectively [1][2].
512+
///
513+
/// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU16.html:
514+
///
515+
/// This type has the same size and bit validity as the underlying
516+
/// integer type, `u16`.
517+
///
518+
/// [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI16.html:
519+
///
520+
/// This type has the same size and bit validity as the underlying
521+
/// integer type, `i16`.
522+
unsafe_impl_transmute_from_for_atomic!(=> AtomicU16 [u16], => AtomicI16 [i16]);
492523
}
493524
}
494525

@@ -499,13 +530,23 @@ mod atomics {
499530

500531
use super::*;
501532

502-
impl_traits_for_atomics!(AtomicU32, AtomicI32);
533+
impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
503534

504535
safety_comment! {
505536
/// 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]);
537+
/// `AtomicU32` and `AtomicI32` have the same size and bit validity
538+
/// as `u32` and `i32` respectively [1][2].
539+
///
540+
/// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU32.html:
541+
///
542+
/// This type has the same size and bit validity as the underlying
543+
/// integer type, `u32`.
544+
///
545+
/// [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI32.html:
546+
///
547+
/// This type has the same size and bit validity as the underlying
548+
/// integer type, `i32`.
549+
unsafe_impl_transmute_from_for_atomic!(=> AtomicU32 [u32], => AtomicI32 [i32]);
509550
}
510551
}
511552

@@ -516,13 +557,23 @@ mod atomics {
516557

517558
use super::*;
518559

519-
impl_traits_for_atomics!(AtomicU64, AtomicI64);
560+
impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
520561

521562
safety_comment! {
522563
/// 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]);
564+
/// `AtomicU64` and `AtomicI64` have the same size and bit validity
565+
/// as `u64` and `i64` respectively [1][2].
566+
///
567+
/// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU64.html:
568+
///
569+
/// This type has the same size and bit validity as the underlying
570+
/// integer type, `u64`.
571+
///
572+
/// [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI64.html:
573+
///
574+
/// This type has the same size and bit validity as the underlying
575+
/// integer type, `i64`.
576+
unsafe_impl_transmute_from_for_atomic!(=> AtomicU64 [u64], => AtomicI64 [i64]);
526577
}
527578
}
528579

@@ -533,21 +584,43 @@ mod atomics {
533584

534585
use super::*;
535586

536-
impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
587+
impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
537588

538589
impl_known_layout!(T => AtomicPtr<T>);
539590

591+
// SAFETY: `AtomicPtr<T>` and `*mut T` have the same size [1].
592+
//
593+
// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html:
594+
//
595+
// This type has the same size and bit validity as a `*mut T`.
596+
unsafe impl<T> crate::pointer::SizeEq<*mut T> for AtomicPtr<T> {}
597+
// SAFETY: See previous safety comment.
598+
unsafe impl<T> crate::pointer::SizeEq<AtomicPtr<T>> for *mut T {}
599+
540600
// TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement
541601
// 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>);
602+
impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T> [UnsafeCell<*mut T>]);
544603

545604
safety_comment! {
546605
/// 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]);
606+
/// `AtomicUsize` and `AtomicIsize` have the same size and bit
607+
/// validity as `usize` and `isize` respectively [1][2].
608+
///
609+
/// [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicUsize.html:
610+
///
611+
/// This type has the same size and bit validity as the underlying
612+
/// integer type, `usize`.
613+
///
614+
/// [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicIsize.html:
615+
///
616+
/// This type has the same size and bit validity as the underlying
617+
/// integer type, `isize`.
618+
unsafe_impl_transmute_from_for_atomic!(=> AtomicUsize [usize], => AtomicIsize [isize]);
619+
/// SAFETY:
620+
/// Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html:
621+
///
622+
/// This type has the same size and bit validity as a `*mut T`.
623+
unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]);
551624
}
552625
}
553626
}
@@ -577,39 +650,76 @@ safety_comment! {
577650
assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
578651
}
579652

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>);
653+
impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
654+
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>[T]);
655+
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>[T]);
656+
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
586657
assert_unaligned!(Wrapping<()>, Wrapping<u8>);
587658

659+
safety_comment! {
660+
/// SAFETY: TODO
661+
unsafe_impl!(T: Immutable => Immutable for Wrapping<T>);
662+
unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>);
663+
}
664+
588665
safety_comment! {
589666
/// SAFETY:
590667
/// `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
591668
/// `MaybeUninit<T>` has no restrictions on its contents.
592669
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
593670
unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
594671
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
672+
/// SAFETY: TODO
673+
unsafe_impl!(T: Immutable => Immutable for CoreMaybeUninit<T>);
674+
unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
595675
}
596-
597-
impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit<T>);
598-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
599676
assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<u8>);
600677

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>);
678+
safety_comment! {
679+
/// SAFETY: TODO
680+
unsafe_impl!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
681+
}
682+
683+
// SAFETY: See inline safety comment justifying that the implementation of
684+
// `is_bit_valid`is sound.
685+
unsafe impl<T: ?Sized + TryFromBytes> TryFromBytes for ManuallyDrop<T> {
686+
#[allow(clippy::missing_inline_in_public_items)]
687+
fn only_derive_is_allowed_to_implement_this_trait() {}
688+
689+
#[inline(always)]
690+
fn is_bit_valid<A: crate::pointer::invariant::Reference>(
691+
candidate: Maybe<'_, Self, A>,
692+
) -> bool {
693+
// SAFETY: `ManuallyDrop<T>` and `T` have the same size [1], so this
694+
// cast preserves size. It also preserves provenance.
695+
//
696+
// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
697+
//
698+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
699+
// validity as `T`
700+
let c: Maybe<'_, T, A> = unsafe { candidate.cast_unsized(|p| cast!(p => NonNull<_>)) };
701+
702+
// SAFETY: `ManuallyDrop<T>` and `T` have the same bit validity [1], so
703+
// this is a sound implementation of `ManuallyDrop::is_bit_valid`.
704+
//
705+
// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
706+
//
707+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
708+
// validity as `T`
709+
<T as TryFromBytes>::is_bit_valid(c)
710+
}
711+
}
712+
713+
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
714+
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
715+
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
716+
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
607717
assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
608718

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>);
719+
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
720+
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
721+
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
722+
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
613723
assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
614724

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