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