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