Skip to main content

zerocopy/pointer/
transmute.rs

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