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/// Transmutations which are sound to attempt, conditional on validating the bit
28/// validity of the destination type.
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/// validate that the referent is bit-valid for the destination type. That
33/// validation mechanism could be a type bound (such as `TransmuteFrom`) or a
34/// runtime 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/// - Forwards transmutation: 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/// - Reverse transmutation: 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// - Forwards transmutation: 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// - Reverse transmutation: Since the underlying cast is size-preserving, `dst`
142// addresses the same referent as `src`. By `Src: TransmuteFrom<Dst, DV, SV>`,
143// the set of `DV`-valid referents of `src` is a subset of the set of
144// `SV`-valid referents of `dst`.
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: InvariantsEq<Src>`, which guarantees that `Src` and `Dst` have the
151// same invariants, and permit interior mutation on the same byte ranges
152unsafe impl<Src, Dst, SV, DV, A, C, R>
153 TryTransmuteFromPtr<Src, A, SV, DV, C, (BecauseMutationCompatible, R)> for Dst
154where
155 A: Aliasing,
156 SV: Validity,
157 DV: Validity,
158 Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
159 Dst: MutationCompatible<Src, A, SV, DV, R> + ?Sized,
160 C: CastExact<Src, Dst>,
161{
162}
163
164// SAFETY:
165// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`,
166// `src` does not permit mutation of its referent.
167// - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`,
168// `dst` does not permit mutation of its referent.
169// - No safe code, given access to `src` and `dst`, can cause undefined
170// behavior: `Src: Immutable` and `Dst: Immutable`
171unsafe impl<Src, Dst, SV, DV, C> TryTransmuteFromPtr<Src, Shared, SV, DV, C, BecauseImmutable>
172 for Dst
173where
174 SV: Validity,
175 DV: Validity,
176 Src: Immutable + ?Sized,
177 Dst: Immutable + ?Sized,
178 C: CastExact<Src, Dst>,
179{
180}
181
182/// Denotes that `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Self, (A, _, DV)>`,
183/// referencing the same referent at the same time, cannot be used by safe code
184/// to break library safety invariants of `Src` or `Self`.
185///
186/// # Safety
187///
188/// At least one of the following must hold:
189/// - `Src: Read<A, _>` and `Self: Read<A, _>`
190/// - `Self: InvariantsEq<Src>`, and, for some `V`:
191/// - `Dst: TransmuteFrom<Src, V, V>`
192/// - `Src: TransmuteFrom<Dst, V, V>`
193pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}
194
195#[allow(missing_copy_implementations, missing_debug_implementations)]
196pub enum BecauseRead {}
197
198// SAFETY: `Src: Read<A, _>` and `Dst: Read<A, _>`.
199unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>
200 MutationCompatible<Src, A, SV, DV, (BecauseRead, R)> for Dst
201where
202 Src: Read<A, R>,
203 Dst: Read<A, R>,
204{
205}
206
207/// Denotes that two types have the same invariants.
208///
209/// # Safety
210///
211/// It is sound for safe code to operate on a `&T` and a `&Self` pointing to the
212/// same referent at the same time - no such safe code can cause undefined
213/// behavior.
214pub unsafe trait InvariantsEq<T: ?Sized> {}
215
216// SAFETY: Trivially sound to have multiple `&T` pointing to the same referent.
217unsafe impl<T: ?Sized> InvariantsEq<T> for T {}
218
219// SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, SV, DV>`, and `Src:
220// TransmuteFrom<Dst, DV, SV>`.
221unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity>
222 MutationCompatible<Src, A, SV, DV, BecauseInvariantsEq> for Dst
223where
224 Src: TransmuteFrom<Dst, DV, SV>,
225 Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src>,
226{
227}
228
229#[allow(missing_debug_implementations, missing_copy_implementations)]
230pub enum BecauseInvariantsEq {}
231
232macro_rules! unsafe_impl_invariants_eq {
233 ($tyvar:ident => $t:ty, $u:ty) => {{
234 crate::util::macros::__unsafe();
235 // SAFETY: The caller promises that this is sound.
236 unsafe impl<$tyvar> InvariantsEq<$t> for $u {}
237 // SAFETY: The caller promises that this is sound.
238 unsafe impl<$tyvar> InvariantsEq<$u> for $t {}
239 }};
240}
241
242impl_transitive_transmute_from!(T => MaybeUninit<T> => T => Wrapping<T>);
243impl_transitive_transmute_from!(T => Wrapping<T> => T => MaybeUninit<T>);
244
245// SAFETY: `ManuallyDrop<T>` has the same size and bit validity as `T` [1], and
246// implements `Deref<Target = T>` [2]. Thus, it is already possible for safe
247// code to obtain a `&T` and a `&ManuallyDrop<T>` to the same referent at the
248// same time.
249//
250// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
251//
252// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
253// validity as `T`
254//
255// [2] https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E
256unsafe impl<T: ?Sized> InvariantsEq<T> for ManuallyDrop<T> {}
257// SAFETY: See previous safety comment.
258unsafe impl<T: ?Sized> InvariantsEq<ManuallyDrop<T>> for T {}
259
260/// Transmutations which are always sound.
261///
262/// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and
263/// [`TransmuteFrom`].
264///
265/// # Safety
266///
267/// `Dst: TransmuteFromPtr<Src, A, SV, DV, _>` is equivalent to `Dst:
268/// TryTransmuteFromPtr<Src, A, SV, DV, _> + TransmuteFrom<Src, SV, DV>`.
269pub unsafe trait TransmuteFromPtr<
270 Src: ?Sized,
271 A: Aliasing,
272 SV: Validity,
273 DV: Validity,
274 C: CastExact<Src, Self>,
275 R,
276>: TryTransmuteFromPtr<Src, A, SV, DV, C, R> + TransmuteFrom<Src, SV, DV>
277{
278}
279
280// SAFETY: The `where` bounds are equivalent to the safety invariant on
281// `TransmuteFromPtr`.
282unsafe impl<
283 Src: ?Sized,
284 Dst: ?Sized,
285 A: Aliasing,
286 SV: Validity,
287 DV: Validity,
288 C: CastExact<Src, Dst>,
289 R,
290 > TransmuteFromPtr<Src, A, SV, DV, C, R> for Dst
291where
292 Dst: TransmuteFrom<Src, SV, DV> + TryTransmuteFromPtr<Src, A, SV, DV, C, R>,
293{
294}
295
296/// Denotes that any `SV`-valid `Src` may soundly be transmuted into a
297/// `DV`-valid `Self`.
298///
299/// # Safety
300///
301/// Given `src: Ptr<Src, (_, _, SV)>` and `dst: Ptr<Dst, (_, _, DV)>`, if the
302/// referents of `src` and `dst` are the same size, then the set of bit patterns
303/// allowed to appear in `src`'s referent must be a subset of the set allowed to
304/// appear in `dst`'s referent.
305///
306/// If the referents are not the same size, then `Dst: TransmuteFrom<Src, SV,
307/// DV>` conveys no safety guarantee.
308pub unsafe trait TransmuteFrom<Src: ?Sized, SV, DV> {}
309
310/// Carries the ability to perform a size-preserving cast or conversion from a
311/// raw pointer to `Src` to a raw pointer to `Self`.
312///
313/// The cast/conversion is carried by the associated [`CastFrom`] type, and
314/// may be a no-op cast (without updating pointer metadata) or a conversion
315/// which updates pointer metadata.
316///
317/// # Safety
318///
319/// `SizeEq` on its own conveys no safety guarantee. Any safety guarantees come
320/// from the safety invariants on the associated [`CastFrom`] type, specifically
321/// the [`CastExact`] bound.
322///
323/// [`CastFrom`]: SizeEq::CastFrom
324/// [`CastExact`]: CastExact
325pub trait SizeEq<Src: ?Sized> {
326 type CastFrom: CastExact<Src, Self>;
327}
328
329impl<T: ?Sized> SizeEq<T> for T {
330 type CastFrom = cast::IdCast;
331}
332
333// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of
334// initialized bit patterns, which is exactly the set allowed in the referent of
335// any `Initialized` `Ptr`.
336unsafe impl<Src, Dst> TransmuteFrom<Src, Valid, Initialized> for Dst
337where
338 Src: IntoBytes + ?Sized,
339 Dst: ?Sized,
340{
341}
342
343// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the
344// referent of a `Ptr<Dst, (_, _, Valid)>`. This is exactly equal to the set of
345// bit patterns which may appear in the referent of any `Initialized` `Ptr`.
346unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Valid> for Dst
347where
348 Src: ?Sized,
349 Dst: FromBytes + ?Sized,
350{
351}
352
353// FIXME(#2354): This seems like a smell - the soundness of this bound has
354// nothing to do with `Src` or `Dst` - we're basically just saying `[u8; N]` is
355// transmutable into `[u8; N]`.
356
357// SAFETY: The set of allowed bit patterns in the referent of any `Initialized`
358// `Ptr` is the same regardless of referent type.
359unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Initialized> for Dst
360where
361 Src: ?Sized,
362 Dst: ?Sized,
363{
364}
365
366// FIXME(#2354): This seems like a smell - the soundness of this bound has
367// nothing to do with `Dst` - we're basically just saying that any type is
368// transmutable into `MaybeUninit<[u8; N]>`.
369
370// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and
371// therefore can be transmuted from any value.
372unsafe impl<Src, Dst, V> TransmuteFrom<Src, V, Uninit> for Dst
373where
374 Src: ?Sized,
375 Dst: ?Sized,
376 V: Validity,
377{
378}
379
380// SAFETY:
381// - `ManuallyDrop<T>` has the same size as `T` [1]
382// - `ManuallyDrop<T>` has the same validity as `T` [1]
383//
384// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
385//
386// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
387// `T`
388#[allow(clippy::multiple_unsafe_ops_per_block)]
389const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => ManuallyDrop<T>) };
390
391// SAFETY:
392// - `Unalign<T>` promises to have the same size as `T`.
393// - `Unalign<T>` promises to have the same validity as `T`.
394#[allow(clippy::multiple_unsafe_ops_per_block)]
395const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Unalign<T>) };
396// SAFETY: `Unalign<T>` promises to have the same size and validity as `T`.
397// Given `u: &Unalign<T>`, it is already possible to obtain `let t =
398// u.try_deref().unwrap()`. Because `Unalign<T>` has the same size as `T`, the
399// returned `&T` must point to the same referent as `u`, and thus it must be
400// sound for these two references to exist at the same time since it's already
401// possible for safe code to get into this state.
402#[allow(clippy::multiple_unsafe_ops_per_block)]
403const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Unalign<T>) };
404
405// SAFETY:
406// - `Wrapping<T>` has the same size as `T` [1].
407// - `Wrapping<T>` has only one field, which is `pub` [2]. We are also
408// guaranteed per that `Wrapping<T>` has the same layout as `T` [1]. The only
409// way for both of these to be true simultaneously is for `Wrapping<T>` to
410// have the same bit validity as `T`. In particular, in order to change the
411// bit validity, one of the following would need to happen:
412// - `Wrapping` could change its `repr`, but this would violate the layout
413// guarantee.
414// - `Wrapping` could add or change its fields, but this would be a
415// stability-breaking change.
416//
417// [1] Per https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html#layout-1:
418//
419// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
420//
421// [2] Definition from https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html:
422//
423// ```
424// #[repr(transparent)]
425// pub struct Wrapping<T>(pub T);
426// ```
427#[allow(clippy::multiple_unsafe_ops_per_block)]
428const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Wrapping<T>) };
429
430// SAFETY: By the preceding safety proof, `Wrapping<T>` and `T` have the same
431// layout and bit validity. Since a `Wrapping<T>`'s `T` field is `pub`, given
432// `w: &Wrapping<T>`, it's possible to do `let t = &w.t`, which means that it's
433// already possible for safe code to obtain a `&Wrapping<T>` and a `&T` pointing
434// to the same referent at the same time. Thus, this must be sound.
435#[allow(clippy::multiple_unsafe_ops_per_block)]
436const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Wrapping<T>) };
437
438// SAFETY:
439// - `UnsafeCell<T>` has the same size as `T` [1].
440// - Per [1], `UnsafeCell<T>` has the same bit validity as `T`. Technically the
441// term "representation" doesn't guarantee this, but the subsequent sentence
442// in the documentation makes it clear that this is the intention.
443//
444// [1] 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 => UnsafeCell<T>) };
451
452// SAFETY:
453// - `Cell<T>` has the same size as `T` [1].
454// - Per [1], `Cell<T>` has the same bit validity as `T`. Technically the term
455// "representation" doesn't guarantee this, but it does promise to have the
456// "same memory layout and caveats as `UnsafeCell<T>`." The `UnsafeCell` docs
457// [2] make it clear that bit validity is the intention even if that phrase
458// isn't used.
459//
460// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout:
461//
462// `Cell<T>` has the same memory layout and caveats as `UnsafeCell<T>`. In
463// particular, this means that `Cell<T>` has the same in-memory representation
464// as its inner type `T`.
465//
466// [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
467//
468// `UnsafeCell<T>` has the same in-memory representation as its inner type
469// `T`. A consequence of this guarantee is that it is possible to convert
470// between `T` and `UnsafeCell<T>`.
471#[allow(clippy::multiple_unsafe_ops_per_block)]
472const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Cell<T>) };
473
474impl_transitive_transmute_from!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);
475impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);
476
477// SAFETY: `MaybeUninit<T>` has no validity requirements. Currently this is not
478// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
479// that this is the intention:
480// https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html
481unsafe impl<T> TransmuteFrom<T, Uninit, Valid> for MaybeUninit<T> {}
482
483impl<T> SizeEq<T> for MaybeUninit<T> {
484 type CastFrom = CastSizedExact;
485}
486
487impl<T> SizeEq<MaybeUninit<T>> for T {
488 type CastFrom = CastSizedExact;
489}
490
491#[cfg(test)]
492mod tests {
493 use super::*;
494 use crate::pointer::cast::Project as _;
495
496 fn test_size_eq<Src, Dst: SizeEq<Src>>(mut src: Src) {
497 let _: *mut Dst =
498 <Dst as SizeEq<Src>>::CastFrom::project(crate::pointer::PtrInner::from_mut(&mut src));
499 }
500
501 #[test]
502 fn test_transmute_coverage() {
503 // SizeEq<T> for MaybeUninit<T>
504 test_size_eq::<u8, MaybeUninit<u8>>(0u8);
505
506 // SizeEq<MaybeUninit<T>> for T
507 test_size_eq::<MaybeUninit<u8>, u8>(MaybeUninit::<u8>::new(0));
508
509 // Transitive: MaybeUninit<T> -> Wrapping<T>
510 // T => MaybeUninit<T> => T => Wrapping<T>
511 test_size_eq::<u8, Wrapping<u8>>(0u8);
512
513 // T => Wrapping<T> => T => MaybeUninit<T>
514 test_size_eq::<Wrapping<u8>, MaybeUninit<u8>>(Wrapping(0u8));
515
516 // T: ?Sized => Cell<T> => T => UnsafeCell<T>
517 test_size_eq::<Cell<u8>, UnsafeCell<u8>>(Cell::new(0u8));
518
519 // T: ?Sized => UnsafeCell<T> => T => Cell<T>
520 test_size_eq::<UnsafeCell<u8>, Cell<u8>>(UnsafeCell::new(0u8));
521 }
522}