Skip to content
/ rust Public
forked from rust-lang/rust

Commit 6cbc5a2

Browse files
authored
Rollup merge of rust-lang#159738 - WaffleLapkin:covariant-unsafe-cell, r=jhpratt
implement `CovariantUnsafeCell` Implements rust-lang#159735 / rust-lang/libs-team#815.
2 parents c5e9c91 + c37239a commit 6cbc5a2

5 files changed

Lines changed: 189 additions & 0 deletions

File tree

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ language_item_table! {
226226
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
227227

228228
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
229+
CovariantUnsafeCell, sym::covariant_unsafe_cell, covariant_unsafe_cell_type, Target::Struct, GenericRequirement::Exact(1);
229230
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
230231

231232
VaArgSafe, sym::va_arg_safe, va_arg_safe, Target::Trait, GenericRequirement::None;

compiler/rustc_hir_analysis/src/variance/terms.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ fn lang_items(tcx: TyCtxt<'_>) -> Vec<(LocalDefId, Vec<ty::Variance>)> {
111111
let all = [
112112
(lang_items.phantom_data(), vec![ty::Covariant]),
113113
(lang_items.unsafe_cell_type(), vec![ty::Invariant]),
114+
(lang_items.covariant_unsafe_cell_type(), vec![ty::Covariant]),
114115
];
115116

116117
all.into_iter() // iterating over (Option<DefId>, Variance)

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ symbols! {
738738
cosf64,
739739
cosf128,
740740
count,
741+
covariant_unsafe_cell,
741742
coverage,
742743
coverage_attribute,
743744
cr,

library/core/src/cell.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,12 @@ use crate::pin::PinCoerceUnsized;
259259
use crate::ptr::{self, NonNull};
260260
use crate::range;
261261

262+
mod covariant_unsafe_cell;
262263
mod lazy;
263264
mod once;
264265

266+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
267+
pub use covariant_unsafe_cell::CovariantUnsafeCell;
265268
#[stable(feature = "lazy_cell", since = "1.80.0")]
266269
pub use lazy::LazyCell;
267270
#[stable(feature = "once_cell", since = "1.70.0")]
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
use crate::cell::UnsafeCell;
2+
use crate::fmt;
3+
use crate::ops::CoerceUnsized;
4+
use crate::ptr::{self, NonNull};
5+
6+
/// **Co**variant version of [`UnsafeCell`].
7+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
8+
#[repr(transparent)]
9+
#[rustc_pub_transparent]
10+
// Implementation note:
11+
//
12+
// We could make `CovariantUnsafeCell` be the canonical lang item and make `UnsafeCell` a wrapper
13+
// over it, with `PhantomData<*mut T>`. That would however be a huge compiler change, without clear
14+
// benefit.
15+
//
16+
// As such, `CovariantUnsafeCell` is wrapping `UnsafeCell` instead. It is a lang-item only to
17+
// hardcode its variance to be **co**variant in `T`, even though it is wrapping `UnsafeCell` which
18+
// is **in**variant in `T`.
19+
#[lang = "covariant_unsafe_cell"]
20+
pub struct CovariantUnsafeCell<T: ?Sized>(UnsafeCell<T>);
21+
22+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
23+
impl<T: ?Sized> !Sync for CovariantUnsafeCell<T> {}
24+
25+
impl<T> CovariantUnsafeCell<T> {
26+
/// Constructs a new instance of `CovariantUnsafeCell` which will wrap the specified value.
27+
///
28+
/// All access to the inner value through `&CovariantUnsafeCell<T>` requires `unsafe` code.
29+
///
30+
/// # Examples
31+
///
32+
/// ```
33+
/// #![feature(covariant_unsafe_cell)]
34+
/// use std::cell::CovariantUnsafeCell;
35+
///
36+
/// let uc = CovariantUnsafeCell::new(5);
37+
/// ```
38+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
39+
#[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")]
40+
#[inline(always)]
41+
pub const fn new(value: T) -> CovariantUnsafeCell<T> {
42+
CovariantUnsafeCell(UnsafeCell::new(value))
43+
}
44+
45+
/// Unwraps the value, consuming the cell.
46+
///
47+
/// # Examples
48+
///
49+
/// ```
50+
/// #![feature(covariant_unsafe_cell)]
51+
/// use std::cell::CovariantUnsafeCell;
52+
///
53+
/// let uc = CovariantUnsafeCell::new(5);
54+
///
55+
/// let five = uc.into_inner();
56+
/// ```
57+
#[inline(always)]
58+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
59+
#[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")]
60+
pub const fn into_inner(self) -> T {
61+
self.0.into_inner()
62+
}
63+
}
64+
65+
impl<T: ?Sized> CovariantUnsafeCell<T> {
66+
/// Gets a mutable non-null pointer to the wrapped value.
67+
///
68+
/// This can be cast to a pointer of any kind. When creating (shared or mutable) references, you
69+
/// must uphold the aliasing rules; see [the `UnsafeCell` type-level docs] for more discussion
70+
/// and caveats.
71+
///
72+
/// [the `UnsafeCell` type-level docs]: super::UnsafeCell#aliasing-rules
73+
///
74+
/// # Examples
75+
///
76+
/// ```
77+
/// #![feature(covariant_unsafe_cell)]
78+
/// use std::cell::CovariantUnsafeCell;
79+
/// use std::ptr::NonNull;
80+
///
81+
/// let uc = CovariantUnsafeCell::new(5);
82+
///
83+
/// let ptr: NonNull<i32> = uc.get();
84+
/// ```
85+
#[inline(always)]
86+
#[rustc_as_ptr]
87+
#[rustc_should_not_be_called_on_const_items]
88+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
89+
#[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")]
90+
pub const fn get(&self) -> NonNull<T> {
91+
// We can just cast the pointer from `CovariantUnsafeCell<T>` to `T` because of
92+
// #[repr(transparent)].
93+
//
94+
// Note that this is also known to be allowed for user code as per
95+
// `#[rustc_pub_transparent]`.
96+
// SAFETY: the pointer is not null, as it comes from a reference
97+
unsafe { NonNull::new_unchecked(ptr::from_ref(self).cast_mut() as *mut T) }
98+
}
99+
100+
/// Returns a mutable reference to the underlying data.
101+
///
102+
/// This call borrows the `CovariantUnsafeCell` mutably (at compile-time) which guarantees that
103+
/// we possess the only reference.
104+
///
105+
/// # Examples
106+
///
107+
/// ```
108+
/// #![feature(covariant_unsafe_cell)]
109+
/// use std::cell::CovariantUnsafeCell;
110+
///
111+
/// let mut c = CovariantUnsafeCell::new(5);
112+
/// *c.get_mut() += 1;
113+
///
114+
/// assert_eq!(*c.get_mut(), 6);
115+
/// ```
116+
#[inline(always)]
117+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
118+
#[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")]
119+
pub const fn get_mut(&mut self) -> &mut T {
120+
self.0.get_mut()
121+
}
122+
123+
/// Gets a mutable pointer to the wrapped value.
124+
/// The difference from [`get`] is that this function accepts a raw pointer,
125+
/// which is useful to avoid the creation of temporary references.
126+
///
127+
/// This can be cast to a pointer of any kind. When creating (shared or mutable) references, you
128+
/// must uphold the aliasing rules; see [the `UnsafeCell` type-level docs] for more discussion
129+
/// and caveats.
130+
///
131+
/// [`get`]: CovariantUnsafeCell::get()
132+
///
133+
/// # Examples
134+
///
135+
/// Gradual initialization of an `CovariantUnsafeCell` requires `raw_get`, as
136+
/// calling `get` would require creating a reference to uninitialized data:
137+
///
138+
/// ```
139+
/// #![feature(covariant_unsafe_cell)]
140+
/// use std::cell::CovariantUnsafeCell;
141+
/// use std::mem::MaybeUninit;
142+
///
143+
/// let m = MaybeUninit::<CovariantUnsafeCell<i32>>::uninit();
144+
/// unsafe { CovariantUnsafeCell::raw_get(m.as_ptr()).write(5); }
145+
/// // avoid below which references to uninitialized data
146+
/// // unsafe { CovariantUnsafeCell::get(&*m.as_ptr()).write(5); }
147+
/// let uc = unsafe { m.assume_init() };
148+
///
149+
/// assert_eq!(uc.into_inner(), 5);
150+
/// ```
151+
#[inline(always)]
152+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
153+
#[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")]
154+
pub const fn raw_get(this: *const Self) -> *mut T {
155+
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
156+
// #[repr(transparent)].
157+
//
158+
// Note that this is also known to be allowed for user code as per
159+
// `#[rustc_pub_transparent]`.
160+
this as *const T as *mut T
161+
}
162+
}
163+
164+
#[unstable(feature = "coerce_unsized", issue = "18598")]
165+
impl<T: CoerceUnsized<U>, U> CoerceUnsized<CovariantUnsafeCell<U>> for CovariantUnsafeCell<T> {}
166+
167+
#[unstable(feature = "covariant_unsafe_cell", issue = "159735")]
168+
impl<T: ?Sized> fmt::Debug for CovariantUnsafeCell<T> {
169+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170+
f.debug_struct("CovariantUnsafeCell").finish_non_exhaustive()
171+
}
172+
}
173+
174+
#[cfg(test)]
175+
mod tests {
176+
use super::*;
177+
178+
fn _covarience<'short, 'long: 'short>(
179+
x: CovariantUnsafeCell<&'long ()>,
180+
) -> CovariantUnsafeCell<&'short ()> {
181+
x
182+
}
183+
}

0 commit comments

Comments
 (0)