zerocopy/pointer/
transmute.rs

1// Copyright 2025 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9use core::{
10    cell::{Cell, UnsafeCell},
11    mem::{ManuallyDrop, MaybeUninit},
12    num::Wrapping,
13};
14
15use crate::{
16    pointer::{cast, invariant::*},
17    FromBytes, Immutable, IntoBytes, Unalign,
18};
19
20/// Transmutations which are sound to attempt, conditional on validating the bit
21/// validity of the destination type.
22///
23/// If a `Ptr` transmutation is `TryTransmuteFromPtr`, then it is sound to
24/// perform that transmutation so long as some additional mechanism is used to
25/// validate that the referent is bit-valid for the destination type. That
26/// validation mechanism could be a type bound (such as `TransmuteFrom`) or a
27/// runtime validity check.
28///
29/// # Safety
30///
31/// ## Post-conditions
32///
33/// Given `Dst: TryTransmuteFromPtr<Src, A, SV, DV, _>`, callers may assume the
34/// following:
35///
36/// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is
37/// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a,
38/// Dst, (A, Unaligned, DV)>` by preserving pointer address and metadata.
39///
40/// ## Pre-conditions
41///
42/// Given `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Dst, (A, Unaligned, DV)>`,
43/// `Dst: TryTransmuteFromPtr<Src, A, SV, DV, _>` is sound if all of the
44/// following hold:
45/// - Forwards transmutation: Either of the following hold:
46///   - So long as `dst` is active, no mutation of `dst`'s referent is allowed
47///     except via `dst` itself
48///   - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
49///     `Src`s
50/// - Reverse transmutation: Either of the following hold:
51///   - `dst` does not permit mutation of its referent
52///   - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s
53/// - No safe code, given access to `src` and `dst`, can cause undefined
54///   behavior: Any of the following hold:
55///   - `A` is `Exclusive`
56///   - `Src: Immutable` and `Dst: Immutable`
57///   - It is sound for shared code to operate on a `&Src` and `&Dst` which
58///     reference the same byte range at the same time
59///
60/// ## Proof
61///
62/// Given:
63/// - `src: Ptr<'a, Src, (A, _, SV)>`
64/// - `src`'s referent is `DV`-valid for `Dst`
65/// - `Dst: SizeEq<Src>`
66///
67/// We are trying to prove that it is sound to perform a pointer address- and
68/// metadata-preserving transmute from `src` to a `dst: Ptr<'a, Dst, (A,
69/// Unaligned, DV)>`. We need to prove that such a transmute does not violate
70/// any of `src`'s invariants, and that it satisfies all invariants of the
71/// destination `Ptr` type.
72///
73/// First, all of `src`'s `PtrInner` invariants are upheld. `src`'s address and
74/// metadata are unchanged, so:
75/// - If its referent is not zero sized, then it still has valid provenance for
76///   its referent, which is still entirely contained in some Rust allocation,
77///   `A`
78/// - If its referent is not zero sized, `A` is guaranteed to live for at least
79///   `'a`
80///
81/// Since `Dst: SizeEq<Src>`, and since `dst` has the same address and metadata
82/// as `src`, `dst` addresses the same byte range as `src`. `dst` also has the
83/// same lifetime as `src`. Therefore, all of the `PtrInner` invariants
84/// mentioned above also hold for `dst`.
85///
86/// Second, since `src`'s address is unchanged, it still satisfies its
87/// alignment. Since `dst`'s alignment is `Unaligned`, it trivially satisfies
88/// its alignment.
89///
90/// Third, aliasing is either `Exclusive` or `Shared`:
91/// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive`
92///   aliasing trivially: since `src` and `dst` have the same lifetime, `src` is
93///   inaccessible so long as `dst` is alive, and no other live `Ptr`s or
94///   references may reference the same referent.
95/// - If it is `Shared`, then either:
96///   - `Src: Immutable` and `Dst: Immutable`, and so `UnsafeCell`s trivially
97///     cover the same byte ranges in both types.
98///   - It is explicitly sound for safe code to operate on a `&Src` and a `&Dst`
99///     pointing to the same byte range at the same time.
100///
101/// Fourth, `src`'s validity is satisfied. By invariant, `src`'s referent began
102/// as an `SV`-valid `Src`. It is guaranteed to remain so, as either of the
103/// following hold:
104/// - `dst` does not permit mutation of its referent.
105/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
106///   `Src`s. Thus, any value written via `dst` is guaranteed to be `SV`-valid
107///   for `Src`.
108///
109/// Fifth, `dst`'s validity is satisfied. It is a given of this proof that the
110/// referent is `DV`-valid for `Dst`. It is guaranteed to remain so, as either
111/// of the following hold:
112/// - So long as `dst` is active, no mutation of the referent is allowed except
113///   via `dst` itself.
114/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
115///   `Src`s. Thus, any value written via `src` is guaranteed to be a `DV`-valid
116///   `Dst`.
117pub unsafe trait TryTransmuteFromPtr<Src: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>:
118    SizeEq<Src>
119{
120}
121
122#[allow(missing_copy_implementations, missing_debug_implementations)]
123pub enum BecauseMutationCompatible {}
124
125// SAFETY:
126// - Forwards transmutation: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, we
127//   know that at least one of the following holds:
128//   - So long as `dst: Ptr<Dst>` is active, no mutation of its referent is
129//     allowed except via `dst` itself if either of the following hold:
130//     - Aliasing is `Exclusive`, in which case, so long as the `Dst` `Ptr`
131//       exists, no mutation is permitted except via that `Ptr`
132//     - Aliasing is `Shared`, `Src: Immutable`, and `Dst: Immutable`, in which
133//       case no mutation is possible via either `Ptr`
134//   - `Dst: TransmuteFrom<Src, SV, DV>`. Since `Dst: SizeEq<Src>`, this bound
135//     guarantees that the set of `DV`-valid `Dst`s is a supserset of the set of
136//     `SV`-valid `Src`s.
137// - Reverse transmutation: `Src: TransmuteFrom<Dst, DV, SV>`. Since `Dst:
138//   SizeEq<Src>`, this guarantees that the set of `DV`-valid `Dst`s is a subset
139//   of the set of `SV`-valid `Src`s.
140// - No safe code, given access to `src` and `dst`, can cause undefined
141//   behavior: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, at least one of
142//   the following holds:
143//   - `A` is `Exclusive`
144//   - `Src: Immutable` and `Dst: Immutable`
145//   - `Dst: InvariantsEq<Src>`, which guarantees that `Src` and `Dst` have the
146//     same invariants, and have `UnsafeCell`s covering the same byte ranges
147unsafe impl<Src, Dst, SV, DV, A, R>
148    TryTransmuteFromPtr<Src, A, SV, DV, (BecauseMutationCompatible, R)> for Dst
149where
150    A: Aliasing,
151    SV: Validity,
152    DV: Validity,
153    Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
154    Dst: MutationCompatible<Src, A, SV, DV, R> + SizeEq<Src> + ?Sized,
155{
156}
157
158// SAFETY:
159// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`,
160//   `src` does not permit mutation of its referent.
161// - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`,
162//   `dst` does not permit mutation of its referent.
163// - No safe code, given access to `src` and `dst`, can cause undefined
164//   behavior: `Src: Immutable` and `Dst: Immutable`
165unsafe impl<Src, Dst, SV, DV> TryTransmuteFromPtr<Src, Shared, SV, DV, BecauseImmutable> for Dst
166where
167    SV: Validity,
168    DV: Validity,
169    Src: Immutable + ?Sized,
170    Dst: Immutable + SizeEq<Src> + ?Sized,
171{
172}
173
174/// Denotes that `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Self, (A, _, DV)>`,
175/// referencing the same referent at the same time, cannot be used by safe code
176/// to break library safety invariants of `Src` or `Self`.
177///
178/// # Safety
179///
180/// At least one of the following must hold:
181/// - `Src: Read<A, _>` and `Self: Read<A, _>`
182/// - `Self: InvariantsEq<Src>`, and, for some `V`:
183///   - `Dst: TransmuteFrom<Src, V, V>`
184///   - `Src: TransmuteFrom<Dst, V, V>`
185pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}
186
187#[allow(missing_copy_implementations, missing_debug_implementations)]
188pub enum BecauseRead {}
189
190// SAFETY: `Src: Read<A, _>` and `Dst: Read<A, _>`.
191unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R, S>
192    MutationCompatible<Src, A, SV, DV, (BecauseRead, (R, S))> for Dst
193where
194    Src: Read<A, R>,
195    Dst: Read<A, S>,
196{
197}
198
199/// Denotes that two types have the same invariants.
200///
201/// # Safety
202///
203/// It is sound for safe code to operate on a `&T` and a `&Self` pointing to the
204/// same referent at the same time - no such safe code can cause undefined
205/// behavior.
206pub unsafe trait InvariantsEq<T: ?Sized> {}
207
208// SAFETY: Trivially sound to have multiple `&T` pointing to the same referent.
209unsafe impl<T: ?Sized> InvariantsEq<T> for T {}
210
211// SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, SV, DV>`, and `Src:
212// TransmuteFrom<Dst, DV, SV>`.
213unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity>
214    MutationCompatible<Src, A, SV, DV, BecauseInvariantsEq> for Dst
215where
216    Src: TransmuteFrom<Dst, DV, SV>,
217    Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src>,
218{
219}
220
221#[allow(missing_debug_implementations, missing_copy_implementations)]
222#[doc(hidden)]
223pub enum BecauseInvariantsEq {}
224
225macro_rules! unsafe_impl_invariants_eq {
226    ($tyvar:ident => $t:ty, $u:ty) => {{
227        crate::util::macros::__unsafe();
228        // SAFETY: The caller promises that this is sound.
229        unsafe impl<$tyvar> InvariantsEq<$t> for $u {}
230        // SAFETY: The caller promises that this is sound.
231        unsafe impl<$tyvar> InvariantsEq<$u> for $t {}
232    }};
233}
234
235impl_transitive_transmute_from!(T => MaybeUninit<T> => T => Wrapping<T>);
236impl_transitive_transmute_from!(T => Wrapping<T> => T => MaybeUninit<T>);
237
238// SAFETY: `ManuallyDrop<T>` has the same size and bit validity as `T` [1], and
239// implements `Deref<Target = T>` [2]. Thus, it is already possible for safe
240// code to obtain a `&T` and a `&ManuallyDrop<T>` to the same referent at the
241// same time.
242//
243// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
244//
245//   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
246//   validity as `T`
247//
248// [2] https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E
249unsafe impl<T: ?Sized> InvariantsEq<T> for ManuallyDrop<T> {}
250// SAFETY: See previous safety comment.
251unsafe impl<T: ?Sized> InvariantsEq<ManuallyDrop<T>> for T {}
252
253/// Transmutations which are always sound.
254///
255/// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and
256/// [`TransmuteFrom`].
257///
258/// # Safety
259///
260/// `Dst: TransmuteFromPtr<Src, A, SV, DV, _>` is equivalent to `Dst:
261/// TryTransmuteFromPtr<Src, A, SV, DV, _> + TransmuteFrom<Src, SV, DV>`.
262pub unsafe trait TransmuteFromPtr<Src: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>:
263    TryTransmuteFromPtr<Src, A, SV, DV, R> + TransmuteFrom<Src, SV, DV>
264{
265}
266
267// SAFETY: The `where` bounds are equivalent to the safety invariant on
268// `TransmuteFromPtr`.
269unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>
270    TransmuteFromPtr<Src, A, SV, DV, R> for Dst
271where
272    Dst: TransmuteFrom<Src, SV, DV> + TryTransmuteFromPtr<Src, A, SV, DV, R>,
273{
274}
275
276/// Denotes that any `SV`-valid `Src` may soundly be transmuted into a
277/// `DV`-valid `Self`.
278///
279/// # Safety
280///
281/// Given `src: Ptr<Src, (_, _, SV)>` and `dst: Ptr<Dst, (_, _, DV)>`, if the
282/// referents of `src` and `dst` are the same size, then the set of bit patterns
283/// allowed to appear in `src`'s referent must be a subset of the set allowed to
284/// appear in `dst`'s referent.
285///
286/// If the referents are not the same size, then `Dst: TransmuteFrom<Src, SV,
287/// DV>` conveys no safety guarantee.
288pub unsafe trait TransmuteFrom<Src: ?Sized, SV, DV> {}
289
290/// # Safety
291///
292/// `T` and `Self` must have the same vtable kind (`Sized`, slice DST, `dyn`,
293/// etc) and have the same size. In particular:
294/// - If `T: Sized` and `Self: Sized`, then their sizes must be equal
295/// - If `T: ?Sized` and `Self: ?Sized`, then `Self::CastFrom` must be a
296///   size-preserving cast. *Note that it is **not** guaranteed that an `as`
297///   cast preserves referent size: it may be the case that `Self::CastFrom`
298///   modifies the pointer's metadata in order to preserve referent size, which
299///   an `as` cast does not do.*
300pub unsafe trait SizeEq<T: ?Sized> {
301    type CastFrom: cast::Cast<T, Self>;
302}
303
304// SAFETY: `T` trivially has the same size and vtable kind as `T`, and since
305// pointer `*mut T -> *mut T` pointer casts are no-ops, this cast trivially
306// preserves referent size (when `T: ?Sized`).
307unsafe impl<T: ?Sized> SizeEq<T> for T {
308    type CastFrom = cast::IdCast;
309}
310
311// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of
312// initialized bit patterns, which is exactly the set allowed in the referent of
313// any `Initialized` `Ptr`.
314unsafe impl<Src, Dst> TransmuteFrom<Src, Valid, Initialized> for Dst
315where
316    Src: IntoBytes + ?Sized,
317    Dst: ?Sized,
318{
319}
320
321// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the
322// referent of a `Ptr<Dst, (_, _, Valid)>`. This is exactly equal to the set of
323// bit patterns which may appear in the referent of any `Initialized` `Ptr`.
324unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Valid> for Dst
325where
326    Src: ?Sized,
327    Dst: FromBytes + ?Sized,
328{
329}
330
331// FIXME(#2354): This seems like a smell - the soundness of this bound has
332// nothing to do with `Src` or `Dst` - we're basically just saying `[u8; N]` is
333// transmutable into `[u8; N]`.
334
335// SAFETY: The set of allowed bit patterns in the referent of any `Initialized`
336// `Ptr` is the same regardless of referent type.
337unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Initialized> for Dst
338where
339    Src: ?Sized,
340    Dst: ?Sized,
341{
342}
343
344// FIXME(#2354): This seems like a smell - the soundness of this bound has
345// nothing to do with `Dst` - we're basically just saying that any type is
346// transmutable into `MaybeUninit<[u8; N]>`.
347
348// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and
349// therefore can be transmuted from any value.
350unsafe impl<Src, Dst, V> TransmuteFrom<Src, V, Uninit> for Dst
351where
352    Src: ?Sized,
353    Dst: ?Sized,
354    V: Validity,
355{
356}
357
358// SAFETY:
359// - `ManuallyDrop<T>` has the same size as `T` [1]
360// - `ManuallyDrop<T>` has the same validity as `T` [1]
361//
362// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
363//
364//   `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
365//   `T`
366#[allow(clippy::multiple_unsafe_ops_per_block)]
367const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => ManuallyDrop<T>) };
368
369// SAFETY:
370// - `Unalign<T>` promises to have the same size as `T`.
371// - `Unalign<T>` promises to have the same validity as `T`.
372#[allow(clippy::multiple_unsafe_ops_per_block)]
373const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Unalign<T>) };
374// SAFETY: `Unalign<T>` promises to have the same size and validity as `T`.
375// Given `u: &Unalign<T>`, it is already possible to obtain `let t =
376// u.try_deref().unwrap()`. Because `Unalign<T>` has the same size as `T`, the
377// returned `&T` must point to the same referent as `u`, and thus it must be
378// sound for these two references to exist at the same time since it's already
379// possible for safe code to get into this state.
380#[allow(clippy::multiple_unsafe_ops_per_block)]
381const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Unalign<T>) };
382
383// SAFETY:
384// - `Wrapping<T>` has the same size as `T` [1].
385// - `Wrapping<T>` has only one field, which is `pub` [2]. We are also
386//   guaranteed per that `Wrapping<T>` has the same layout as `T` [1]. The only
387//   way for both of these to be true simultaneously is for `Wrapping<T>` to
388//   have the same bit validity as `T`. In particular, in order to change the
389//   bit validity, one of the following would need to happen:
390//   - `Wrapping` could change its `repr`, but this would violate the layout
391//     guarantee.
392//   - `Wrapping` could add or change its fields, but this would be a
393//     stability-breaking change.
394//
395// [1] Per https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html#layout-1:
396//
397//   `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
398//
399// [2] Definition from https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html:
400//
401//   ```
402//   #[repr(transparent)]
403//   pub struct Wrapping<T>(pub T);
404//   ```
405#[allow(clippy::multiple_unsafe_ops_per_block)]
406const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Wrapping<T>) };
407
408// SAFETY: By the preceding safety proof, `Wrapping<T>` and `T` have the same
409// layout and bit validity. Since a `Wrapping<T>`'s `T` field is `pub`, given
410// `w: &Wrapping<T>`, it's possible to do `let t = &w.t`, which means that it's
411// already possible for safe code to obtain a `&Wrapping<T>` and a `&T` pointing
412// to the same referent at the same time. Thus, this must be sound.
413#[allow(clippy::multiple_unsafe_ops_per_block)]
414const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Wrapping<T>) };
415
416// SAFETY:
417// - `UnsafeCell<T>` has the same size as `T` [1].
418// - Per [1], `UnsafeCell<T>` has the same bit validity as `T`. Technically the
419//   term "representation" doesn't guarantee this, but the subsequent sentence
420//   in the documentation makes it clear that this is the intention.
421//
422// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
423//
424//   `UnsafeCell<T>` has the same in-memory representation as its inner type
425//   `T`. A consequence of this guarantee is that it is possible to convert
426//   between `T` and `UnsafeCell<T>`.
427#[allow(clippy::multiple_unsafe_ops_per_block)]
428const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => UnsafeCell<T>) };
429
430// SAFETY:
431// - `Cell<T>` has the same size as `T` [1].
432// - Per [1], `Cell<T>` has the same bit validity as `T`. Technically the term
433//   "representation" doesn't guarantee this, but it does promise to have the
434//   "same memory layout and caveats as `UnsafeCell<T>`." The `UnsafeCell` docs
435//   [2] make it clear that bit validity is the intention even if that phrase
436//   isn't used.
437//
438// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout:
439//
440//   `Cell<T>` has the same memory layout and caveats as `UnsafeCell<T>`. In
441//   particular, this means that `Cell<T>` has the same in-memory representation
442//   as its inner type `T`.
443//
444// [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
445//
446//   `UnsafeCell<T>` has the same in-memory representation as its inner type
447//   `T`. A consequence of this guarantee is that it is possible to convert
448//   between `T` and `UnsafeCell<T>`.
449#[allow(clippy::multiple_unsafe_ops_per_block)]
450const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Cell<T>) };
451
452impl_transitive_transmute_from!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);
453impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);
454
455// SAFETY: `MaybeUninit<T>` has no validity requirements. Currently this is not
456// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
457// that this is the intention:
458// https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html
459unsafe impl<T> TransmuteFrom<T, Uninit, Valid> for MaybeUninit<T> {}
460
461// SAFETY: `MaybeUninit<T>` has the same size as `T` [1].
462//
463// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
464//
465//   `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
466//   `T`
467unsafe impl<T> SizeEq<T> for MaybeUninit<T> {
468    type CastFrom = cast::CastSized;
469}
470
471// SAFETY: See previous safety comment.
472unsafe impl<T> SizeEq<MaybeUninit<T>> for T {
473    type CastFrom = cast::CastSized;
474}
475
476#[cfg(test)]
477mod tests {
478    use super::*;
479    use crate::pointer::cast::Project as _;
480
481    fn test_size_eq<Src, Dst: SizeEq<Src>>(mut src: Src) {
482        let _: *mut Dst =
483            <Dst as SizeEq<Src>>::CastFrom::project(crate::pointer::PtrInner::from_mut(&mut src));
484    }
485
486    #[test]
487    fn test_transmute_coverage() {
488        // SizeEq<T> for MaybeUninit<T>
489        test_size_eq::<u8, MaybeUninit<u8>>(0u8);
490
491        // SizeEq<MaybeUninit<T>> for T
492        test_size_eq::<MaybeUninit<u8>, u8>(MaybeUninit::<u8>::new(0));
493
494        // Transitive: MaybeUninit<T> -> Wrapping<T>
495        // T => MaybeUninit<T> => T => Wrapping<T>
496        test_size_eq::<u8, Wrapping<u8>>(0u8);
497
498        // T => Wrapping<T> => T => MaybeUninit<T>
499        test_size_eq::<Wrapping<u8>, MaybeUninit<u8>>(Wrapping(0u8));
500
501        // T: ?Sized => Cell<T> => T => UnsafeCell<T>
502        test_size_eq::<Cell<u8>, UnsafeCell<u8>>(Cell::new(0u8));
503
504        // T: ?Sized => UnsafeCell<T> => T => Cell<T>
505        test_size_eq::<UnsafeCell<u8>, Cell<u8>>(UnsafeCell::new(0u8));
506    }
507
508    #[cfg(not(no_zerocopy_target_has_atomics_1_60_0))]
509    #[cfg(target_has_atomic = "8")]
510    #[test]
511    fn test_atomic_u8_transmutes() {
512        use core::sync::atomic::AtomicU8;
513
514        // 1. Atomic -> Prim (SizeEq<Atomic> for Prim)
515        test_size_eq::<AtomicU8, u8>(AtomicU8::new(0));
516
517        // 2. Prim -> Atomic (SizeEq<Prim> for Atomic)
518        test_size_eq::<u8, AtomicU8>(0u8);
519
520        // 3. Atomic -> UnsafeCell<Prim> (SizeEq<Atomic> for UnsafeCell<Prim>)
521        test_size_eq::<AtomicU8, UnsafeCell<u8>>(AtomicU8::new(0));
522
523        // 4. UnsafeCell<Prim> -> Atomic (SizeEq<UnsafeCell<Prim>> for Atomic)
524        test_size_eq::<UnsafeCell<u8>, AtomicU8>(UnsafeCell::new(0u8));
525    }
526}