From 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:20:39 +0200 Subject: Merging upstream version 1.70.0+dfsg1. Signed-off-by: Daniel Baumann --- library/core/src/cell/lazy.rs | 106 ++++++++++++++++++++++++++++++++++-------- library/core/src/cell/once.rs | 52 +++++++++------------ 2 files changed, 109 insertions(+), 49 deletions(-) (limited to 'library/core/src/cell') diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 65d12c25c..44adcfa1a 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -1,6 +1,13 @@ -use crate::cell::{Cell, OnceCell}; -use crate::fmt; use crate::ops::Deref; +use crate::{fmt, mem}; + +use super::UnsafeCell; + +enum State { + Uninit(F), + Init(T), + Poisoned, +} /// A value which is initialized on the first access. /// @@ -11,7 +18,7 @@ use crate::ops::Deref; /// # Examples /// /// ``` -/// #![feature(once_cell)] +/// #![feature(lazy_cell)] /// /// use std::cell::LazyCell; /// @@ -29,10 +36,9 @@ use crate::ops::Deref; /// // 92 /// // 92 /// ``` -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "lazy_cell", issue = "109736")] pub struct LazyCell T> { - cell: OnceCell, - init: Cell>, + state: UnsafeCell>, } impl T> LazyCell { @@ -41,7 +47,7 @@ impl T> LazyCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] + /// #![feature(lazy_cell)] /// /// use std::cell::LazyCell; /// @@ -52,9 +58,9 @@ impl T> LazyCell { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// ``` #[inline] - #[unstable(feature = "once_cell", issue = "74465")] - pub const fn new(init: F) -> LazyCell { - LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) } + #[unstable(feature = "lazy_cell", issue = "109736")] + pub const fn new(f: F) -> LazyCell { + LazyCell { state: UnsafeCell::new(State::Uninit(f)) } } /// Forces the evaluation of this lazy value and returns a reference to @@ -65,7 +71,7 @@ impl T> LazyCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] + /// #![feature(lazy_cell)] /// /// use std::cell::LazyCell; /// @@ -75,16 +81,71 @@ impl T> LazyCell { /// assert_eq!(&*lazy, &92); /// ``` #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "lazy_cell", issue = "109736")] pub fn force(this: &LazyCell) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("`Lazy` instance has previously been poisoned"), - }) + // SAFETY: + // This invalidates any mutable references to the data. The resulting + // reference lives either until the end of the borrow of `this` (in the + // initialized case) or is invalidated in `really_init` (in the + // uninitialized case; `really_init` will create and return a fresh reference). + let state = unsafe { &*this.state.get() }; + match state { + State::Init(data) => data, + // SAFETY: The state is uninitialized. + State::Uninit(_) => unsafe { LazyCell::really_init(this) }, + State::Poisoned => panic!("LazyCell has previously been poisoned"), + } + } + + /// # Safety + /// May only be called when the state is `Uninit`. + #[cold] + unsafe fn really_init(this: &LazyCell) -> &T { + // SAFETY: + // This function is only called when the state is uninitialized, + // so no references to `state` can exist except for the reference + // in `force`, which is invalidated here and not accessed again. + let state = unsafe { &mut *this.state.get() }; + // Temporarily mark the state as poisoned. This prevents reentrant + // accesses and correctly poisons the cell if the closure panicked. + let State::Uninit(f) = mem::replace(state, State::Poisoned) else { unreachable!() }; + + let data = f(); + + // SAFETY: + // If the closure accessed the cell through something like a reentrant + // mutex, but caught the panic resulting from the state being poisoned, + // the mutable borrow for `state` will be invalidated, so we need to + // go through the `UnsafeCell` pointer here. The state can only be + // poisoned at this point, so using `write` to skip the destructor + // of `State` should help the optimizer. + unsafe { this.state.get().write(State::Init(data)) }; + + // SAFETY: + // The previous references were invalidated by the `write` call above, + // so do a new shared borrow of the state instead. + let state = unsafe { &*this.state.get() }; + let State::Init(data) = state else { unreachable!() }; + data + } +} + +impl LazyCell { + #[inline] + fn get(&self) -> Option<&T> { + // SAFETY: + // This is sound for the same reason as in `force`: once the state is + // initialized, it will not be mutably accessed again, so this reference + // will stay valid for the duration of the borrow to `self`. + let state = unsafe { &*self.state.get() }; + match state { + State::Init(data) => Some(data), + _ => None, + } } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "lazy_cell", issue = "109736")] impl T> Deref for LazyCell { type Target = T; #[inline] @@ -93,7 +154,7 @@ impl T> Deref for LazyCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "lazy_cell", issue = "109736")] impl Default for LazyCell { /// Creates a new lazy value using `Default` as the initializing function. #[inline] @@ -102,9 +163,14 @@ impl Default for LazyCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[unstable(feature = "lazy_cell", issue = "109736")] impl fmt::Debug for LazyCell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + let mut d = f.debug_tuple("LazyCell"); + match self.get() { + Some(data) => d.field(data), + None => d.field(&format_args!("")), + }; + d.finish() } } diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index f74e563f1..f7cd3ec5f 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -4,8 +4,10 @@ use crate::mem; /// A cell which can be written to only once. /// -/// Unlike [`RefCell`], a `OnceCell` only provides shared `&T` references to its value. -/// Unlike [`Cell`], a `OnceCell` doesn't require copying or replacing the value to access it. +/// This allows obtaining a shared `&T` reference to its inner value without copying or replacing +/// it (unlike [`Cell`]), and without runtime borrow checks (unlike [`RefCell`]). However, +/// only immutable references can be obtained unless one has a mutable reference to the cell +/// itself. /// /// For a thread-safe version of this struct, see [`std::sync::OnceLock`]. /// @@ -16,8 +18,6 @@ use crate::mem; /// # Examples /// /// ``` -/// #![feature(once_cell)] -/// /// use std::cell::OnceCell; /// /// let cell = OnceCell::new(); @@ -29,7 +29,7 @@ use crate::mem; /// assert_eq!(value, "Hello, World!"); /// assert!(cell.get().is_some()); /// ``` -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] pub struct OnceCell { // Invariant: written to at most once. inner: UnsafeCell>, @@ -39,7 +39,8 @@ impl OnceCell { /// Creates a new empty cell. #[inline] #[must_use] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] + #[rustc_const_stable(feature = "once_cell", since = "1.70.0")] pub const fn new() -> OnceCell { OnceCell { inner: UnsafeCell::new(None) } } @@ -48,7 +49,7 @@ impl OnceCell { /// /// Returns `None` if the cell is empty. #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] pub fn get(&self) -> Option<&T> { // SAFETY: Safe due to `inner`'s invariant unsafe { &*self.inner.get() }.as_ref() @@ -58,7 +59,7 @@ impl OnceCell { /// /// Returns `None` if the cell is empty. #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] pub fn get_mut(&mut self) -> Option<&mut T> { self.inner.get_mut().as_mut() } @@ -73,8 +74,6 @@ impl OnceCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] - /// /// use std::cell::OnceCell; /// /// let cell = OnceCell::new(); @@ -86,7 +85,7 @@ impl OnceCell { /// assert!(cell.get().is_some()); /// ``` #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] pub fn set(&self, value: T) -> Result<(), T> { // SAFETY: Safe because we cannot have overlapping mutable borrows let slot = unsafe { &*self.inner.get() }; @@ -117,8 +116,6 @@ impl OnceCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] - /// /// use std::cell::OnceCell; /// /// let cell = OnceCell::new(); @@ -128,7 +125,7 @@ impl OnceCell { /// assert_eq!(value, &92); /// ``` #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, @@ -153,7 +150,7 @@ impl OnceCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] + /// #![feature(once_cell_try)] /// /// use std::cell::OnceCell; /// @@ -166,7 +163,7 @@ impl OnceCell { /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` - #[unstable(feature = "once_cell", issue = "74465")] + #[unstable(feature = "once_cell_try", issue = "109737")] pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, @@ -199,8 +196,6 @@ impl OnceCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] - /// /// use std::cell::OnceCell; /// /// let cell: OnceCell = OnceCell::new(); @@ -211,7 +206,7 @@ impl OnceCell { /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] pub fn into_inner(self) -> Option { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option`. @@ -227,8 +222,6 @@ impl OnceCell { /// # Examples /// /// ``` - /// #![feature(once_cell)] - /// /// use std::cell::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); @@ -240,13 +233,13 @@ impl OnceCell { /// assert_eq!(cell.get(), None); /// ``` #[inline] - #[unstable(feature = "once_cell", issue = "74465")] + #[stable(feature = "once_cell", since = "1.70.0")] pub fn take(&mut self) -> Option { mem::take(self).into_inner() } } -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] impl Default for OnceCell { #[inline] fn default() -> Self { @@ -254,7 +247,7 @@ impl Default for OnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] impl fmt::Debug for OnceCell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get() { @@ -264,7 +257,7 @@ impl fmt::Debug for OnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] impl Clone for OnceCell { #[inline] fn clone(&self) -> OnceCell { @@ -279,7 +272,7 @@ impl Clone for OnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] impl PartialEq for OnceCell { #[inline] fn eq(&self, other: &Self) -> bool { @@ -287,10 +280,11 @@ impl PartialEq for OnceCell { } } -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] impl Eq for OnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for OnceCell { /// Creates a new `OnceCell` which already contains the given `value`. #[inline] @@ -300,5 +294,5 @@ impl const From for OnceCell { } // Just like for `Cell` this isn't needed, but results in nicer error messages. -#[unstable(feature = "once_cell", issue = "74465")] +#[stable(feature = "once_cell", since = "1.70.0")] impl !Sync for OnceCell {} -- cgit v1.2.3