Skip to content

Commit 459de15

Browse files
joshlfjswrenn
andcommitted
Teach transmute_{ref,mut}! to handle slice DSTs
TODO: - Convince ourselves that it's acceptable to drop the `TransmuteFrom: SizeCompatible` super-trait bound. - Write Kani tests for layout computations - Print useful error message when `try_compute_cast_params` fails during static assertion - Test when post padding doesn't match between types - Do we need to prevent the padded size from increasing? While it's not a problem on today's Rust, it would become a problem if unsized locals are ever introduced, as you could then do `*dst = ...`, which would have the effect of writing padding past the end of `*src` Makes progress on #1817 Co-authored-by: Jack Wrenn <jswrenn@amazon.com> gherrit-pr-id: Ib4bc62202e0b3b09d155333b525087f7aa8f02c2
1 parent 3baab3f commit 459de15

File tree

7 files changed

+784
-233
lines changed

7 files changed

+784
-233
lines changed

src/impls.rs

+14-38
Original file line numberDiff line numberDiff line change
@@ -179,39 +179,13 @@ safety_comment! {
179179
});
180180
}
181181

182-
// SAFETY: `str` and `[u8]` have the same layout [1].
183-
//
184-
// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout:
185-
//
186-
// String slices are a UTF-8 representation of characters that have the same
187-
// layout as slices of type `[u8]`.
188-
unsafe impl pointer::SizeEq<str> for [u8] {
189-
fn cast_from_raw(s: NonNull<str>) -> NonNull<[u8]> {
190-
cast!(s)
191-
}
192-
}
193-
// SAFETY: See previous safety comment.
194-
unsafe impl pointer::SizeEq<[u8]> for str {
195-
fn cast_from_raw(bytes: NonNull<[u8]>) -> NonNull<str> {
196-
cast!(bytes)
197-
}
198-
}
182+
impl_size_eq!(str, [u8]);
199183

200184
macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
201185
($($nonzero:ident[$prim:ty]),*) => {
202186
$(
203187
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
204-
unsafe impl pointer::SizeEq<$nonzero> for Unalign<$prim> {
205-
fn cast_from_raw(n: NonNull<$nonzero>) -> NonNull<Unalign<$prim>> {
206-
cast!(n)
207-
}
208-
}
209-
unsafe impl pointer::SizeEq<Unalign<$prim>> for $nonzero {
210-
fn cast_from_raw(p: NonNull<Unalign<$prim>>) -> NonNull<$nonzero> {
211-
cast!(p)
212-
}
213-
}
214-
188+
impl_size_eq!($nonzero, Unalign<$prim>);
215189
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
216190
$nonzero::new(n.read_unaligned().into_inner()).is_some()
217191
});
@@ -430,7 +404,7 @@ mod atomics {
430404
($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {
431405
const _: () = {
432406
use core::{cell::UnsafeCell, ptr::NonNull};
433-
use crate::pointer::{TransmuteFrom, SizeEq, invariant::Valid};
407+
use crate::pointer::{TransmuteFrom, SizeCompat, invariant::Valid};
434408

435409
$(
436410
#[allow(unused_unsafe)] // Force the caller to call this macro inside `safety_comment!`.
@@ -443,36 +417,38 @@ mod atomics {
443417
// the same size and bit validity.
444418
unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {}
445419

446-
// SAFETY: THe caller promised that `$atomic` and `$prim`
447-
// have the same size.
448-
unsafe impl<$($tyvar)?> SizeEq<$atomic> for $prim {
420+
// SAFETY: The caller promised that `$atomic` and `$prim`
421+
// have the same size. Thus, this cast preserves address,
422+
// referent size, and provenance.
423+
unsafe impl<$($tyvar)?> SizeCompat<$atomic> for $prim {
449424
fn cast_from_raw(a: NonNull<$atomic>) -> NonNull<$prim> {
450425
cast!(a)
451426
}
452427
}
453-
// SAFETY: THe caller promised that `$atomic` and `$prim`
454-
// have the same size.
455-
unsafe impl<$($tyvar)?> SizeEq<$prim> for $atomic {
428+
// SAFETY: See previous safety comment.
429+
unsafe impl<$($tyvar)?> SizeCompat<$prim> for $atomic {
456430
fn cast_from_raw(p: NonNull<$prim>) -> NonNull<$atomic> {
457431
cast!(p)
458432
}
459433
}
434+
460435
// SAFETY: The caller promised that `$atomic` and `$prim`
461436
// have the same size. `UnsafeCell<T>` has the same size as
462-
// `T` [1].
437+
// `T` [1]. Thus, this cast preserves address, referent
438+
// size, and provenance.
463439
//
464440
// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout:
465441
//
466442
// `UnsafeCell<T>` has the same in-memory representation as
467443
// its inner type `T`. A consequence of this guarantee is that
468444
// it is possible to convert between `T` and `UnsafeCell<T>`.
469-
unsafe impl<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> {
445+
unsafe impl<$($tyvar)?> SizeCompat<$atomic> for UnsafeCell<$prim> {
470446
fn cast_from_raw(a: NonNull<$atomic>) -> NonNull<UnsafeCell<$prim>> {
471447
cast!(a)
472448
}
473449
}
474450
// SAFETY: See previous safety comment.
475-
unsafe impl<$($tyvar)?> SizeEq<UnsafeCell<$prim>> for $atomic {
451+
unsafe impl<$($tyvar)?> SizeCompat<UnsafeCell<$prim>> for $atomic {
476452
fn cast_from_raw(p: NonNull<UnsafeCell<$prim>>) -> NonNull<$atomic> {
477453
cast!(p)
478454
}

0 commit comments

Comments
 (0)