Skip to content

Commit 5da2332

Browse files
committed
make LazyLock<T, F> covariant in both T and F
1 parent 7dd751f commit 5da2332

2 files changed

Lines changed: 13 additions & 7 deletions

File tree

‎library/std/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@
280280
#![feature(cfg_target_thread_local)]
281281
#![feature(cfi_encoding)]
282282
#![feature(const_trait_impl)]
283+
#![feature(covariant_unsafe_cell)]
283284
#![feature(decl_macro)]
284285
#![feature(deprecated_suggestion)]
285286
#![feature(diagnostic_on_move)]

‎library/std/src/sync/lazy_lock.rs‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::once::OnceExclusiveState;
2-
use crate::cell::UnsafeCell;
2+
use crate::cell::CovariantUnsafeCell;
33
use crate::mem::ManuallyDrop;
44
use crate::ops::{Deref, DerefMut};
55
use crate::panic::{RefUnwindSafe, UnwindSafe};
@@ -81,7 +81,9 @@ union Data<T, F> {
8181
pub struct LazyLock<T, F = fn() -> T> {
8282
// FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available
8383
once: Once,
84-
data: UnsafeCell<Data<T, F>>,
84+
// See justification on `core::cell::LazyCell::state` for why this can be covariant in both
85+
// `T` and `F`.
86+
data: CovariantUnsafeCell<Data<T, F>>,
8587
}
8688

8789
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
@@ -102,7 +104,10 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
102104
#[stable(feature = "lazy_cell", since = "1.80.0")]
103105
#[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")]
104106
pub const fn new(f: F) -> LazyLock<T, F> {
105-
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
107+
LazyLock {
108+
once: Once::new(),
109+
data: CovariantUnsafeCell::new(Data { f: ManuallyDrop::new(f) }),
110+
}
106111
}
107112

108113
/// Consumes this `LazyLock` returning the stored value.
@@ -245,7 +250,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
245250
}
246251

247252
// SAFETY: `call_once` only runs this closure once, ever.
248-
let data = unsafe { &mut *this.data.get() };
253+
let data = unsafe { this.data.get().as_mut() };
249254
let f = unsafe { ManuallyDrop::take(&mut data.f) };
250255
let value = f();
251256
data.value = ManuallyDrop::new(value);
@@ -258,7 +263,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
258263
// * the closure was not called, but a previous call initialized `value`.
259264
// * the closure was not called because the Once is poisoned, which we handled above.
260265
// So `value` has definitely been initialized and will not be modified again.
261-
unsafe { &*(*this.data.get()).value }
266+
unsafe { &this.data.get().as_ref().value }
262267
}
263268
}
264269

@@ -313,7 +318,7 @@ impl<T, F> LazyLock<T, F> {
313318
// SAFETY:
314319
// The closure has been run successfully, so `value` has been initialized
315320
// and will not be modified again.
316-
Some(unsafe { &(*this.data.get()).value })
321+
Some(unsafe { &this.data.get().as_ref().value })
317322
} else {
318323
None
319324
}
@@ -404,7 +409,7 @@ impl<T, F> From<T> for LazyLock<T, F> {
404409
fn from(value: T) -> Self {
405410
LazyLock {
406411
once: Once::new_complete(),
407-
data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }),
412+
data: CovariantUnsafeCell::new(Data { value: ManuallyDrop::new(value) }),
408413
}
409414
}
410415
}

0 commit comments

Comments
 (0)