Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6a15d05

Browse files
authoredApr 14, 2025··
Unrolled build for rust-lang#137043
Rollup merge of rust-lang#137043 - Sky9x:unsafe-pinned-pt1-libs, r=tgross35,RalfJung,WaffleLapkin Initial `UnsafePinned` implementation [Part 1: Libs] Initial libs changes necessary to unblock further work on [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html). Tracking issue: rust-lang#125735 This PR is split off from rust-lang#136964, and includes just the libs changes: - `UnsafePinned` struct - private `UnsafeUnpin` structural auto trait - Lang items for both - Compiler changes necessary to block niches on `UnsafePinned` This PR does not change codegen, miri, the existing `!Unpin` hack, or anything else. That work is to be split into later PRs. --- cc ``@RalfJung`` ``@Noratrieb`` ``@rustbot`` label F-unsafe_pinned T-libs-api
2 parents 6e83046 + 21b7360 commit 6a15d05

File tree

11 files changed

+290
-8
lines changed

11 files changed

+290
-8
lines changed
 

‎compiler/rustc_abi/src/layout.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
315315
repr: &ReprOptions,
316316
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
317317
is_enum: bool,
318-
is_unsafe_cell: bool,
318+
is_special_no_niche: bool,
319319
scalar_valid_range: (Bound<u128>, Bound<u128>),
320320
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
321321
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
@@ -348,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
348348
repr,
349349
variants,
350350
is_enum,
351-
is_unsafe_cell,
351+
is_special_no_niche,
352352
scalar_valid_range,
353353
always_sized,
354354
present_first,
@@ -505,7 +505,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
505505
repr: &ReprOptions,
506506
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
507507
is_enum: bool,
508-
is_unsafe_cell: bool,
508+
is_special_no_niche: bool,
509509
scalar_valid_range: (Bound<u128>, Bound<u128>),
510510
always_sized: bool,
511511
present_first: VariantIdx,
@@ -524,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
524524
let mut st = self.univariant(&variants[v], repr, kind)?;
525525
st.variants = Variants::Single { index: v };
526526

527-
if is_unsafe_cell {
527+
if is_special_no_niche {
528528
let hide_niches = |scalar: &mut _| match scalar {
529529
Scalar::Initialized { value, valid_range } => {
530530
*valid_range = WrappingRange::full(value.size(dl))

‎compiler/rustc_hir/src/lang_items.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ language_item_table! {
182182
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
183183

184184
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
185+
UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
185186

186187
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
187188
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
@@ -235,6 +236,8 @@ language_item_table! {
235236
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
236237

237238
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
239+
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
240+
238241
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
239242

240243
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);

‎compiler/rustc_lint/src/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,8 @@ fn ty_is_known_nonnull<'tcx>(
864864
return true;
865865
}
866866

867-
// `UnsafeCell` has its niche hidden.
868-
if def.is_unsafe_cell() {
867+
// `UnsafeCell` and `UnsafePinned` have their niche hidden.
868+
if def.is_unsafe_cell() || def.is_unsafe_pinned() {
869869
return false;
870870
}
871871

‎compiler/rustc_middle/src/ty/adt.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ bitflags::bitflags! {
5353
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
5454
/// Indicates whether the type is `UnsafeCell`.
5555
const IS_UNSAFE_CELL = 1 << 9;
56+
/// Indicates whether the type is `UnsafePinned`.
57+
const IS_UNSAFE_PINNED = 1 << 10;
58+
/// Indicates whether the type is anonymous.
59+
const IS_ANONYMOUS = 1 << 11;
5660
}
5761
}
5862
rustc_data_structures::external_bitflags_debug! { AdtFlags }
@@ -302,6 +306,9 @@ impl AdtDefData {
302306
if tcx.is_lang_item(did, LangItem::UnsafeCell) {
303307
flags |= AdtFlags::IS_UNSAFE_CELL;
304308
}
309+
if tcx.is_lang_item(did, LangItem::UnsafePinned) {
310+
flags |= AdtFlags::IS_UNSAFE_PINNED;
311+
}
305312

306313
AdtDefData { did, variants, flags, repr }
307314
}
@@ -405,6 +412,12 @@ impl<'tcx> AdtDef<'tcx> {
405412
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
406413
}
407414

415+
/// Returns `true` if this is `UnsafePinned<T>`.
416+
#[inline]
417+
pub fn is_unsafe_pinned(self) -> bool {
418+
self.flags().contains(AdtFlags::IS_UNSAFE_PINNED)
419+
}
420+
408421
/// Returns `true` if this is `ManuallyDrop<T>`.
409422
#[inline]
410423
pub fn is_manually_drop(self) -> bool {

‎compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,8 @@ symbols! {
22152215
unsafe_fields,
22162216
unsafe_no_drop_flag,
22172217
unsafe_pin_internals,
2218+
unsafe_pinned,
2219+
unsafe_unpin,
22182220
unsize,
22192221
unsized_const_param_ty,
22202222
unsized_const_params,

‎compiler/rustc_ty_utils/src/layout.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ fn layout_of_uncached<'tcx>(
514514
return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
515515
}
516516

517+
// UnsafeCell and UnsafePinned both disable niche optimizations
518+
let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
519+
517520
let get_discriminant_type =
518521
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
519522

@@ -542,7 +545,7 @@ fn layout_of_uncached<'tcx>(
542545
&def.repr(),
543546
&variants,
544547
def.is_enum(),
545-
def.is_unsafe_cell(),
548+
is_special_no_niche,
546549
tcx.layout_scalar_valid_range(def.did()),
547550
get_discriminant_type,
548551
discriminants_iter(),
@@ -568,7 +571,7 @@ fn layout_of_uncached<'tcx>(
568571
&def.repr(),
569572
&variants,
570573
def.is_enum(),
571-
def.is_unsafe_cell(),
574+
is_special_no_niche,
572575
tcx.layout_scalar_valid_range(def.did()),
573576
get_discriminant_type,
574577
discriminants_iter(),

‎library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
#![feature(ub_checks)]
128128
#![feature(unchecked_neg)]
129129
#![feature(unchecked_shifts)]
130+
#![feature(unsafe_pinned)]
130131
#![feature(utf16_extra)]
131132
#![feature(variant_count)]
132133
// tidy-alphabetical-end

‎library/core/src/marker.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::cell::UnsafeCell;
1717
use crate::cmp;
1818
use crate::fmt::Debug;
1919
use crate::hash::{Hash, Hasher};
20+
use crate::pin::UnsafePinned;
2021

2122
/// Implements a given marker trait for multiple types at the same time.
2223
///
@@ -878,6 +879,23 @@ marker_impls! {
878879
{T: ?Sized} &mut T,
879880
}
880881

882+
/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally,
883+
/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata
884+
/// for `&mut T` or not.
885+
///
886+
/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is
887+
/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735).
888+
#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")]
889+
#[cfg_attr(bootstrap, allow(dead_code))]
890+
pub(crate) unsafe auto trait UnsafeUnpin {}
891+
892+
impl<T: ?Sized> !UnsafeUnpin for UnsafePinned<T> {}
893+
unsafe impl<T: ?Sized> UnsafeUnpin for PhantomData<T> {}
894+
unsafe impl<T: ?Sized> UnsafeUnpin for *const T {}
895+
unsafe impl<T: ?Sized> UnsafeUnpin for *mut T {}
896+
unsafe impl<T: ?Sized> UnsafeUnpin for &T {}
897+
unsafe impl<T: ?Sized> UnsafeUnpin for &mut T {}
898+
881899
/// Types that do not require any pinning guarantees.
882900
///
883901
/// For information on what "pinning" is, see the [`pin` module] documentation.
@@ -953,13 +971,24 @@ pub auto trait Unpin {}
953971
/// A marker type which does not implement `Unpin`.
954972
///
955973
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
974+
//
975+
// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet.
976+
// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this
977+
// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type
978+
// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead.
956979
#[stable(feature = "pin", since = "1.33.0")]
957980
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
958981
pub struct PhantomPinned;
959982

960983
#[stable(feature = "pin", since = "1.33.0")]
961984
impl !Unpin for PhantomPinned {}
962985

986+
// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to
987+
// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same
988+
// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking
989+
// change.
990+
impl !UnsafeUnpin for PhantomPinned {}
991+
963992
marker_impls! {
964993
#[stable(feature = "pin", since = "1.33.0")]
965994
Unpin for

‎library/core/src/pin.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,11 @@ use crate::{
931931
};
932932
use crate::{cmp, fmt};
933933

934+
mod unsafe_pinned;
935+
936+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
937+
pub use self::unsafe_pinned::UnsafePinned;
938+
934939
/// A pointer which pins its pointee in place.
935940
///
936941
/// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its

‎library/core/src/pin/unsafe_pinned.rs

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
use crate::marker::{PointerLike, Unpin};
2+
use crate::ops::{CoerceUnsized, DispatchFromDyn};
3+
use crate::pin::Pin;
4+
use crate::{fmt, ptr};
5+
6+
/// This type provides a way to opt-out of typical aliasing rules;
7+
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
8+
///
9+
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
10+
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
11+
/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
12+
/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
13+
/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
14+
/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness.
15+
///
16+
/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in
17+
/// the public API of a library. It is an internal implementation detail of libraries that need to
18+
/// support aliasing mutable references.
19+
///
20+
/// Further note that this does *not* lift the requirement that shared references must be read-only!
21+
/// Use `UnsafeCell` for that.
22+
///
23+
/// This type blocks niches the same way `UnsafeCell` does.
24+
#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")]
25+
#[repr(transparent)]
26+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
27+
pub struct UnsafePinned<T: ?Sized> {
28+
value: T,
29+
}
30+
31+
/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the
32+
/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt
33+
/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned.
34+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
35+
impl<T: ?Sized> !Unpin for UnsafePinned<T> {}
36+
37+
/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no
38+
/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean
39+
/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that
40+
/// leaves the user more choices (as they can always wrap this in a `!Copy` type).
41+
// FIXME(unsafe_pinned): this may be unsound or a footgun?
42+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
43+
impl<T: Copy> Copy for UnsafePinned<T> {}
44+
45+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
46+
impl<T: Copy> Clone for UnsafePinned<T> {
47+
fn clone(&self) -> Self {
48+
*self
49+
}
50+
}
51+
52+
// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since
53+
// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes
54+
// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit
55+
// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`.
56+
57+
impl<T> UnsafePinned<T> {
58+
/// Constructs a new instance of `UnsafePinned` which will wrap the specified value.
59+
///
60+
/// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
61+
/// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
62+
#[inline(always)]
63+
#[must_use]
64+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
65+
pub const fn new(value: T) -> Self {
66+
UnsafePinned { value }
67+
}
68+
69+
/// Unwraps the value, consuming this `UnsafePinned`.
70+
#[inline(always)]
71+
#[must_use]
72+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
73+
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
74+
pub const fn into_inner(self) -> T {
75+
self.value
76+
}
77+
}
78+
79+
impl<T: ?Sized> UnsafePinned<T> {
80+
/// Get read-write access to the contents of a pinned `UnsafePinned`.
81+
#[inline(always)]
82+
#[must_use]
83+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
84+
pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T {
85+
// SAFETY: we're not using `get_unchecked_mut` to unpin anything
86+
unsafe { self.get_unchecked_mut() }.get_mut_unchecked()
87+
}
88+
89+
/// Get read-write access to the contents of an `UnsafePinned`.
90+
///
91+
/// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this
92+
/// memory is "pinned" due to there being aliases.
93+
#[inline(always)]
94+
#[must_use]
95+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
96+
pub const fn get_mut_unchecked(&mut self) -> *mut T {
97+
ptr::from_mut(self) as *mut T
98+
}
99+
100+
/// Get read-only access to the contents of a shared `UnsafePinned`.
101+
///
102+
/// Note that `&UnsafePinned<T>` is read-only if `&T` is read-only. This means that if there is
103+
/// mutation of the `T`, future reads from the `*const T` returned here are UB! Use
104+
/// [`UnsafeCell`] if you also need interior mutability.
105+
///
106+
/// [`UnsafeCell`]: crate::cell::UnsafeCell
107+
///
108+
/// ```rust,no_run
109+
/// #![feature(unsafe_pinned)]
110+
/// use std::pin::UnsafePinned;
111+
///
112+
/// unsafe {
113+
/// let mut x = UnsafePinned::new(0);
114+
/// let ptr = x.get(); // read-only pointer, assumes immutability
115+
/// x.get_mut_unchecked().write(1);
116+
/// ptr.read(); // UB!
117+
/// }
118+
/// ```
119+
#[inline(always)]
120+
#[must_use]
121+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
122+
pub const fn get(&self) -> *const T {
123+
ptr::from_ref(self) as *const T
124+
}
125+
126+
/// Gets an immutable pointer to the wrapped value.
127+
///
128+
/// The difference from [`get`] is that this function accepts a raw pointer, which is useful to
129+
/// avoid the creation of temporary references.
130+
///
131+
/// [`get`]: UnsafePinned::get
132+
#[inline(always)]
133+
#[must_use]
134+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
135+
pub const fn raw_get(this: *const Self) -> *const T {
136+
this as *const T
137+
}
138+
139+
/// Gets a mutable pointer to the wrapped value.
140+
///
141+
/// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function
142+
/// accepts a raw pointer, which is useful to avoid the creation of temporary references.
143+
///
144+
/// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned
145+
/// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked
146+
#[inline(always)]
147+
#[must_use]
148+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
149+
pub const fn raw_get_mut(this: *mut Self) -> *mut T {
150+
this as *mut T
151+
}
152+
}
153+
154+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
155+
impl<T: Default> Default for UnsafePinned<T> {
156+
/// Creates an `UnsafePinned`, with the `Default` value for T.
157+
fn default() -> Self {
158+
UnsafePinned::new(T::default())
159+
}
160+
}
161+
162+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
163+
impl<T> From<T> for UnsafePinned<T> {
164+
/// Creates a new `UnsafePinned<T>` containing the given value.
165+
fn from(value: T) -> Self {
166+
UnsafePinned::new(value)
167+
}
168+
}
169+
170+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
171+
impl<T: ?Sized> fmt::Debug for UnsafePinned<T> {
172+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173+
f.debug_struct("UnsafePinned").finish_non_exhaustive()
174+
}
175+
}
176+
177+
#[unstable(feature = "coerce_unsized", issue = "18598")]
178+
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
179+
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T> {}
180+
181+
// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn`
182+
// and become dyn-compatible method receivers.
183+
// Note that currently `UnsafePinned` itself cannot be a method receiver
184+
// because it does not implement Deref.
185+
// In other words:
186+
// `self: UnsafePinned<&Self>` won't work
187+
// `self: UnsafePinned<Self>` becomes possible
188+
// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound?
189+
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
190+
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
191+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}
192+
193+
#[unstable(feature = "pointer_like_trait", issue = "none")]
194+
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
195+
impl<T: PointerLike> PointerLike for UnsafePinned<T> {}
196+
197+
// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ check-pass
2+
// this test ensures that UnsafePinned hides the niche of its inner type, just like UnsafeCell does
3+
4+
#![crate_type = "lib"]
5+
#![feature(unsafe_pinned)]
6+
7+
use std::num::NonZero;
8+
use std::pin::UnsafePinned;
9+
10+
macro_rules! assert_size_is {
11+
($ty:ty = $size:expr) => {
12+
const _: () = assert!(size_of::<$ty>() == $size);
13+
};
14+
}
15+
16+
assert_size_is!(UnsafePinned<()> = 0);
17+
assert_size_is!(UnsafePinned<u8> = 1);
18+
19+
assert_size_is!( UnsafePinned< u32> = 4);
20+
assert_size_is!( UnsafePinned< NonZero<u32>> = 4);
21+
assert_size_is!( UnsafePinned<Option<NonZero<u32>>> = 4);
22+
assert_size_is!(Option<UnsafePinned< u32>> = 8);
23+
assert_size_is!(Option<UnsafePinned< NonZero<u32>>> = 8);
24+
assert_size_is!(Option<UnsafePinned<Option<NonZero<u32>>>> = 8);
25+
26+
assert_size_is!( UnsafePinned< &()> = size_of::<usize>());
27+
assert_size_is!( UnsafePinned<Option<&()>> = size_of::<usize>());
28+
assert_size_is!(Option<UnsafePinned< &()>> = size_of::<usize>() * 2);
29+
assert_size_is!(Option<UnsafePinned<Option<&()>>> = size_of::<usize>() * 2);

0 commit comments

Comments
 (0)
This repository has been archived.