From c1a2db3372a4d6896744919284f3287650a38ab7 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 16 Jun 2022 19:39:39 +0400 Subject: [PATCH] Move/rename `lazy::Sync{OnceCell,Lazy}` to `sync::{Once,Lazy}Lock` --- .../rustc_codegen_cranelift/src/driver/jit.rs | 2 +- .../rustc_data_structures/src/jobserver.rs | 4 +- compiler/rustc_data_structures/src/sync.rs | 2 +- compiler/rustc_driver/src/lib.rs | 8 +- compiler/rustc_error_messages/src/lib.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 6 +- compiler/rustc_hir/src/lang_items.rs | 4 +- compiler/rustc_hir/src/weak_lang_items.rs | 4 +- compiler/rustc_interface/src/passes.rs | 6 +- compiler/rustc_interface/src/util.rs | 6 +- .../src/framework/graphviz.rs | 4 +- .../rustc_mir_transform/src/coverage/debug.rs | 4 +- library/std/src/io/stdio.rs | 9 +- library/std/src/lazy.rs | 616 ------------------ library/std/src/sync/lazy_lock.rs | 121 ++++ library/std/src/sync/lazy_lock/tests.rs | 143 ++++ library/std/src/sync/mod.rs | 7 + library/std/src/sync/once_lock.rs | 496 ++++++++++++++ .../std/src/{lazy => sync/once_lock}/tests.rs | 166 +---- library/std/src/sys/windows/net.rs | 4 +- library/std/src/sys/windows/rand.rs | 4 +- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/core.rs | 6 +- src/librustdoc/html/render/write_shared.rs | 2 +- src/librustdoc/lint.rs | 2 +- src/librustdoc/passes/bare_urls.rs | 4 +- .../run-make/libtest-thread-limit/test.rs | 8 +- src/tools/clippy/clippy_dev/src/bless.rs | 6 +- src/tools/clippy/clippy_utils/src/lib.rs | 4 +- src/tools/clippy/src/driver.rs | 6 +- src/tools/clippy/tests/compile-test.rs | 4 +- src/tools/clippy/tests/test_utils/mod.rs | 4 +- 32 files changed, 847 insertions(+), 819 deletions(-) create mode 100644 library/std/src/sync/lazy_lock.rs create mode 100644 library/std/src/sync/lazy_lock/tests.rs create mode 100644 library/std/src/sync/once_lock.rs rename library/std/src/{lazy => sync/once_lock}/tests.rs (50%) diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 1b01f4edbb3f3..a56a91000596c 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -13,7 +13,7 @@ use rustc_span::Symbol; use cranelift_jit::{JITBuilder, JITModule}; -// FIXME use std::lazy::SyncOnceCell once it stabilizes +// FIXME use std::sync::OnceLock once it stabilizes use once_cell::sync::OnceCell; use crate::{prelude::*, BackendConfig}; diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 41605afb44e02..09baa3095a4d4 100644 --- a/compiler/rustc_data_structures/src/jobserver.rs +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -1,5 +1,5 @@ pub use jobserver_crate::Client; -use std::lazy::SyncLazy; +use std::sync::LazyLock; // We can only call `from_env` once per process @@ -18,7 +18,7 @@ use std::lazy::SyncLazy; // Also note that we stick this in a global because there could be // multiple rustc instances in this process, and the jobserver is // per-process. -static GLOBAL_CLIENT: SyncLazy = SyncLazy::new(|| unsafe { +static GLOBAL_CLIENT: LazyLock = LazyLock::new(|| unsafe { Client::from_env().unwrap_or_else(|| { let client = Client::new(32).expect("failed to create jobserver"); // Acquire a token for the main thread which we can release later diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index ec3d3d49bcb86..feb82cb093818 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -258,7 +258,7 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use parking_lot::MappedMutexGuard as MappedLockGuard; - pub use std::lazy::SyncOnceCell as OnceCell; + pub use std::sync::OnceLock as OnceCell; pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 8cdbb1a6704df..caa92e74808c0 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -47,11 +47,11 @@ use std::env; use std::ffi::OsString; use std::fs; use std::io::{self, Read, Write}; -use std::lazy::SyncLazy; use std::panic::{self, catch_unwind}; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; +use std::sync::LazyLock; use std::time::Instant; pub mod args; @@ -1141,8 +1141,8 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { } } -static DEFAULT_HOOK: SyncLazy) + Sync + Send + 'static>> = - SyncLazy::new(|| { +static DEFAULT_HOOK: LazyLock) + Sync + Send + 'static>> = + LazyLock::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| { // Invoke the default handler, which prints the actual panic message and optionally a backtrace @@ -1237,7 +1237,7 @@ pub fn install_ice_hook() { if std::env::var("RUST_BACKTRACE").is_err() { std::env::set_var("RUST_BACKTRACE", "full"); } - SyncLazy::force(&DEFAULT_HOOK); + LazyLock::force(&DEFAULT_HOOK); } /// This allows tools to enable rust logging without having to magically match rustc's diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 145fbd43ab114..fefcaa898c1b9 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -20,7 +20,7 @@ use tracing::{instrument, trace}; #[cfg(not(parallel_compiler))] use std::cell::LazyCell as Lazy; #[cfg(parallel_compiler)] -use std::lazy::SyncLazy as Lazy; +use std::sync::LazyLock as Lazy; #[cfg(parallel_compiler)] use intl_memoizer::concurrent::IntlLangMemoizer; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index d4452a79dfbe1..6fcdfe44d8f64 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -9,7 +9,7 @@ use crate::{Features, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{sym, Symbol}; -use std::lazy::SyncLazy; +use std::sync::LazyLock; type GateFn = fn(&Features) -> bool; @@ -809,8 +809,8 @@ pub fn is_builtin_only_local(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) } -pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy> = - SyncLazy::new(|| { +pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = + LazyLock::new(|| { let mut map = FxHashMap::default(); for attr in BUILTIN_ATTRIBUTES.iter() { if map.insert(attr.name, attr).is_some() { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 9e5d781892487..b0bfac8e1f5ec 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -17,7 +17,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use std::lazy::SyncLazy; +use std::sync::LazyLock; pub enum LangItemGroup { Op, @@ -134,7 +134,7 @@ macro_rules! language_item_table { } /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ITEM_REFS: SyncLazy> = SyncLazy::new(|| { + pub static ITEM_REFS: LazyLock> = LazyLock::new(|| { let mut item_refs = FxHashMap::default(); $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )* item_refs diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index 78748209d1a5b..dad22725511ed 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -7,12 +7,12 @@ use rustc_ast as ast; use rustc_data_structures::stable_map::StableMap; use rustc_span::symbol::{sym, Symbol}; -use std::lazy::SyncLazy; +use std::sync::LazyLock; macro_rules! weak_lang_items { ($($name:ident, $item:ident, $sym:ident;)*) => ( -pub static WEAK_ITEMS_REFS: SyncLazy> = SyncLazy::new(|| { +pub static WEAK_ITEMS_REFS: LazyLock> = LazyLock::new(|| { let mut map = StableMap::default(); $(map.insert(sym::$name, LangItem::$item);)* map diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 389e6483f30ff..21ccb586e8f5e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -43,11 +43,11 @@ use std::any::Any; use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; -use std::lazy::SyncLazy; use std::marker::PhantomPinned; use std::path::{Path, PathBuf}; use std::pin::Pin; use std::rc::Rc; +use std::sync::LazyLock; use std::{env, fs, iter}; pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { @@ -759,7 +759,7 @@ pub fn prepare_outputs( Ok(outputs) } -pub static DEFAULT_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { +pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; proc_macro_decls::provide(providers); @@ -784,7 +784,7 @@ pub static DEFAULT_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { *providers }); -pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { +pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { let mut extern_providers = ExternProviders::default(); rustc_metadata::provide_extern(&mut extern_providers); rustc_codegen_ssa::provide_extern(&mut extern_providers); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 3fa8017dc93c3..fb9258eb4a938 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -24,12 +24,12 @@ use rustc_span::source_map::FileLoader; use rustc_span::symbol::{sym, Symbol}; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; -use std::lazy::SyncOnceCell; use std::mem; #[cfg(not(parallel_compiler))] use std::panic; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::OnceLock; use std::thread; use tracing::info; @@ -242,7 +242,7 @@ pub fn get_codegen_backend( maybe_sysroot: &Option, backend_name: Option<&str>, ) -> Box { - static LOAD: SyncOnceCell Box> = SyncOnceCell::new(); + static LOAD: OnceLock Box> = OnceLock::new(); let load = LOAD.get_or_init(|| { let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm"); @@ -265,7 +265,7 @@ pub fn get_codegen_backend( // loading, so we leave the code here. It is potentially useful for other tools // that want to invoke the rustc binary while linking to rustc as well. pub fn rustc_path<'a>() -> Option<&'a Path> { - static RUSTC_PATH: SyncOnceCell> = SyncOnceCell::new(); + static RUSTC_PATH: OnceLock> = OnceLock::new(); const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR"); diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 59a2053ec7000..c94198c56a8d1 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -1,7 +1,7 @@ //! A helpful diagram for debugging dataflow problems. use std::borrow::Cow; -use std::lazy::SyncOnceCell; +use std::sync::OnceLock; use std::{io, ops, str}; use regex::Regex; @@ -590,7 +590,7 @@ where macro_rules! regex { ($re:literal $(,)?) => {{ - static RE: SyncOnceCell = SyncOnceCell::new(); + static RE: OnceLock = OnceLock::new(); RE.get_or_init(|| Regex::new($re).unwrap()) }}; } diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index d31ac04274cb8..0f8679b0bd69d 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -123,15 +123,15 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; use std::iter; -use std::lazy::SyncOnceCell; use std::ops::Deref; +use std::sync::OnceLock; pub const NESTED_INDENT: &str = " "; const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS"; pub(super) fn debug_options<'a>() -> &'a DebugOptions { - static DEBUG_OPTIONS: SyncOnceCell = SyncOnceCell::new(); + static DEBUG_OPTIONS: OnceLock = OnceLock::new(); &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env) } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index ae16015e35a1a..e3b62894d0f22 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,10 +8,9 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; -use crate::lazy::SyncOnceCell; use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sync::{Arc, Mutex, MutexGuard}; +use crate::sync::{Arc, Mutex, MutexGuard, OnceLock}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; @@ -318,7 +317,7 @@ pub struct StdinLock<'a> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + static INSTANCE: OnceLock>> = OnceLock::new(); Stdin { inner: INSTANCE.get_or_init(|| { Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) @@ -552,7 +551,7 @@ pub struct StdoutLock<'a> { inner: ReentrantMutexGuard<'a, RefCell>>, } -static STDOUT: SyncOnceCell>>> = SyncOnceCell::new(); +static STDOUT: OnceLock>>> = OnceLock::new(); /// Constructs a new handle to the standard output of the current process. /// @@ -837,7 +836,7 @@ pub fn stderr() -> Stderr { // Note that unlike `stdout()` we don't use `at_exit` here to register a // destructor. Stderr is not buffered , so there's no need to run a // destructor for flushing the buffer - static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + static INSTANCE: OnceLock>> = OnceLock::new(); Stderr { inner: Pin::static_ref(&INSTANCE).get_or_init_pin( diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index d7450962359df..f8c06c3f9aedb 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -1,617 +1 @@ //! Lazy values and one-time initialization of static data. - -#[cfg(test)] -mod tests; - -use crate::{ - cell::{Cell, UnsafeCell}, - fmt, - marker::PhantomData, - mem::MaybeUninit, - ops::{Deref, Drop}, - panic::{RefUnwindSafe, UnwindSafe}, - pin::Pin, - sync::Once, -}; - -#[doc(inline)] -#[unstable(feature = "once_cell", issue = "74465")] -pub use core::lazy::*; - -/// A synchronization primitive which can be written to only once. -/// -/// This type is a thread-safe `OnceCell`. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::lazy::SyncOnceCell; -/// -/// static CELL: SyncOnceCell = SyncOnceCell::new(); -/// assert!(CELL.get().is_none()); -/// -/// std::thread::spawn(|| { -/// let value: &String = CELL.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// }).join().unwrap(); -/// -/// let value: Option<&String> = CELL.get(); -/// assert!(value.is_some()); -/// assert_eq!(value.unwrap().as_str(), "Hello, World!"); -/// ``` -#[unstable(feature = "once_cell", issue = "74465")] -pub struct SyncOnceCell { - once: Once, - // Whether or not the value is initialized is tracked by `state_and_queue`. - value: UnsafeCell>, - /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl. - /// - /// ```compile_fail,E0597 - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// struct A<'a>(&'a str); - /// - /// impl<'a> Drop for A<'a> { - /// fn drop(&mut self) {} - /// } - /// - /// let cell = SyncOnceCell::new(); - /// { - /// let s = String::new(); - /// let _ = cell.set(A(&s)); - /// } - /// ``` - _marker: PhantomData, -} - -// Why do we need `T: Send`? -// Thread A creates a `SyncOnceCell` and shares it with -// scoped thread B, which fills the cell, which is -// then destroyed by A. That is, destructor observes -// a sent value. -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl Sync for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl Send for SyncOnceCell {} - -#[unstable(feature = "once_cell", issue = "74465")] -impl RefUnwindSafe for SyncOnceCell {} -#[unstable(feature = "once_cell", issue = "74465")] -impl UnwindSafe for SyncOnceCell {} - -#[unstable(feature = "once_cell", issue = "74465")] -#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] -impl const Default for SyncOnceCell { - /// Creates a new empty cell. - /// - /// # Example - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// fn main() { - /// assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default()); - /// } - /// ``` - fn default() -> SyncOnceCell { - SyncOnceCell::new() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl fmt::Debug for SyncOnceCell { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("Once").field(v).finish(), - None => f.write_str("Once(Uninit)"), - } - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl Clone for SyncOnceCell { - fn clone(&self) -> SyncOnceCell { - let cell = Self::new(); - if let Some(value) = self.get() { - match cell.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - cell - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl From for SyncOnceCell { - /// Create a new cell with its contents set to `value`. - /// - /// # Example - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// # fn main() -> Result<(), i32> { - /// let a = SyncOnceCell::from(3); - /// let b = SyncOnceCell::new(); - /// b.set(3)?; - /// assert_eq!(a, b); - /// Ok(()) - /// # } - /// ``` - fn from(value: T) -> Self { - let cell = Self::new(); - match cell.set(value) { - Ok(()) => cell, - Err(_) => unreachable!(), - } - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl PartialEq for SyncOnceCell { - fn eq(&self, other: &SyncOnceCell) -> bool { - self.get() == other.get() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl Eq for SyncOnceCell {} - -impl SyncOnceCell { - /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "74465")] - #[must_use] - pub const fn new() -> SyncOnceCell { - SyncOnceCell { - once: Once::new(), - value: UnsafeCell::new(MaybeUninit::uninit()), - _marker: PhantomData, - } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty, or being initialized. This - /// method never blocks. - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get(&self) -> Option<&T> { - if self.is_initialized() { - // Safe b/c checked is_initialized - Some(unsafe { self.get_unchecked() }) - } else { - None - } - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. This method never blocks. - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_mut(&mut self) -> Option<&mut T> { - if self.is_initialized() { - // Safe b/c checked is_initialized and we have a unique access - Some(unsafe { self.get_unchecked_mut() }) - } else { - None - } - } - - /// Sets the contents of this cell to `value`. - /// - /// May block if another thread is currently attempting to initialize the cell. The cell is - /// guaranteed to contain a value when set returns, though not necessarily the one provided. - /// - /// Returns `Ok(())` if the cell's value was set by this call. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// static CELL: SyncOnceCell = SyncOnceCell::new(); - /// - /// fn main() { - /// assert!(CELL.get().is_none()); - /// - /// std::thread::spawn(|| { - /// assert_eq!(CELL.set(92), Ok(())); - /// }).join().unwrap(); - /// - /// assert_eq!(CELL.set(62), Err(62)); - /// assert_eq!(CELL.get(), Some(&92)); - /// } - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn set(&self, value: T) -> Result<(), T> { - let mut value = Some(value); - self.get_or_init(|| value.take().unwrap()); - match value { - None => Ok(()), - Some(value) => Err(value), - } - } - - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. - /// - /// Many threads may call `get_or_init` concurrently with different - /// initializing functions, but it is guaranteed that only one function - /// will be executed. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. The - /// exact outcome is unspecified. Current implementation deadlocks, but - /// this may be changed to a panic in the future. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let cell = SyncOnceCell::new(); - /// let value = cell.get_or_init(|| 92); - /// assert_eq!(value, &92); - /// let value = cell.get_or_init(|| unreachable!()); - /// assert_eq!(value, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_or_init(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::(f())) { - Ok(val) => val, - } - } - - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and - /// the cell remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. - /// The exact outcome is unspecified. Current implementation - /// deadlocks, but this may be changed to a panic in the future. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let cell = SyncOnceCell::new(); - /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - /// assert!(cell.get().is_none()); - /// let value = cell.get_or_try_init(|| -> Result { - /// Ok(92) - /// }); - /// assert_eq!(value, Ok(&92)); - /// assert_eq!(cell.get(), Some(&92)) - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_or_try_init(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result, - { - // Fast path check - // NOTE: We need to perform an acquire on the state in this method - // in order to correctly synchronize `SyncLazy::force`. This is - // currently done by calling `self.get()`, which in turn calls - // `self.is_initialized()`, which in turn performs the acquire. - if let Some(value) = self.get() { - return Ok(value); - } - self.initialize(f)?; - - debug_assert!(self.is_initialized()); - - // SAFETY: The inner value has been initialized - Ok(unsafe { self.get_unchecked() }) - } - - /// Internal-only API that gets the contents of the cell, initializing it - /// in two steps with `f` and `g` if the cell was empty. - /// - /// `f` is called to construct the value, which is then moved into the cell - /// and given as a (pinned) mutable reference to `g` to finish - /// initialization. - /// - /// This allows `g` to inspect an manipulate the value after it has been - /// moved into its final place in the cell, but before the cell is - /// considered initialized. - /// - /// # Panics - /// - /// If `f` or `g` panics, the panic is propagated to the caller, and the - /// cell remains uninitialized. - /// - /// With the current implementation, if `g` panics, the value from `f` will - /// not be dropped. This should probably be fixed if this is ever used for - /// a type where this matters. - /// - /// It is an error to reentrantly initialize the cell from `f`. The exact - /// outcome is unspecified. Current implementation deadlocks, but this may - /// be changed to a panic in the future. - pub(crate) fn get_or_init_pin(self: Pin<&Self>, f: F, g: G) -> Pin<&T> - where - F: FnOnce() -> T, - G: FnOnce(Pin<&mut T>), - { - if let Some(value) = self.get_ref().get() { - // SAFETY: The inner value was already initialized, and will not be - // moved anymore. - return unsafe { Pin::new_unchecked(value) }; - } - - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|_| { - let value = f(); - // SAFETY: We use the Once (self.once) to guarantee unique access - // to the UnsafeCell (slot). - let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; - // SAFETY: The value has been written to its final place in - // self.value. We do not to move it anymore, which we promise here - // with a Pin<&mut T>. - g(unsafe { Pin::new_unchecked(value) }); - }); - - // SAFETY: The inner value has been initialized, and will not be moved - // anymore. - unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } - } - - /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns - /// `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let cell: SyncOnceCell = SyncOnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = SyncOnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn into_inner(mut self) -> Option { - self.take() - } - - /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. - /// - /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized. - /// - /// Safety is guaranteed by requiring a mutable reference. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// let mut cell: SyncOnceCell = SyncOnceCell::new(); - /// assert_eq!(cell.take(), None); - /// - /// let mut cell = SyncOnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.take(), Some("hello".to_string())); - /// assert_eq!(cell.get(), None); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn take(&mut self) -> Option { - if self.is_initialized() { - self.once = Once::new(); - // SAFETY: `self.value` is initialized and contains a valid `T`. - // `self.once` is reset, so `is_initialized()` will be false again - // which prevents the value from being read twice. - unsafe { Some((&mut *self.value.get()).assume_init_read()) } - } else { - None - } - } - - #[inline] - fn is_initialized(&self) -> bool { - self.once.is_completed() - } - - #[cold] - fn initialize(&self, f: F) -> Result<(), E> - where - F: FnOnce() -> Result, - { - let mut res: Result<(), E> = Ok(()); - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|p| { - match f() { - Ok(value) => { - unsafe { (&mut *slot.get()).write(value) }; - } - Err(e) => { - res = Err(e); - - // Treat the underlying `Once` as poisoned since we - // failed to initialize our value. Calls - p.poison(); - } - } - }); - res - } - - /// # Safety - /// - /// The value must be initialized - unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); - (&*self.value.get()).assume_init_ref() - } - - /// # Safety - /// - /// The value must be initialized - unsafe fn get_unchecked_mut(&mut self) -> &mut T { - debug_assert!(self.is_initialized()); - (&mut *self.value.get()).assume_init_mut() - } -} - -unsafe impl<#[may_dangle] T> Drop for SyncOnceCell { - fn drop(&mut self) { - if self.is_initialized() { - // SAFETY: The cell is initialized and being dropped, so it can't - // be accessed again. We also don't touch the `T` other than - // dropping it, which validates our usage of #[may_dangle]. - unsafe { (&mut *self.value.get()).assume_init_drop() }; - } - } -} - -/// A value which is initialized on the first access. -/// -/// This type is a thread-safe `Lazy`, and can be used in statics. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::collections::HashMap; -/// -/// use std::lazy::SyncLazy; -/// -/// static HASHMAP: SyncLazy> = SyncLazy::new(|| { -/// println!("initializing"); -/// let mut m = HashMap::new(); -/// m.insert(13, "Spica".to_string()); -/// m.insert(74, "Hoyten".to_string()); -/// m -/// }); -/// -/// fn main() { -/// println!("ready"); -/// std::thread::spawn(|| { -/// println!("{:?}", HASHMAP.get(&13)); -/// }).join().unwrap(); -/// println!("{:?}", HASHMAP.get(&74)); -/// -/// // Prints: -/// // ready -/// // initializing -/// // Some("Spica") -/// // Some("Hoyten") -/// } -/// ``` -#[unstable(feature = "once_cell", issue = "74465")] -pub struct SyncLazy T> { - cell: SyncOnceCell, - init: Cell>, -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl fmt::Debug for SyncLazy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive() - } -} - -// We never create a `&F` from a `&SyncLazy` so it is fine -// to not impl `Sync` for `F` -// we do create a `&mut Option` in `force`, but this is -// properly synchronized, so it only happens once -// so it also does not contribute to this impl. -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl Sync for SyncLazy where SyncOnceCell: Sync {} -// auto-derived `Send` impl is OK. - -#[unstable(feature = "once_cell", issue = "74465")] -impl RefUnwindSafe for SyncLazy where SyncOnceCell: RefUnwindSafe {} -#[unstable(feature = "once_cell", issue = "74465")] -impl UnwindSafe for SyncLazy where SyncOnceCell: UnwindSafe {} - -impl SyncLazy { - /// Creates a new lazy value with the given initializing - /// function. - #[unstable(feature = "once_cell", issue = "74465")] - pub const fn new(f: F) -> SyncLazy { - SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } - } -} - -impl T> SyncLazy { - /// Forces the evaluation of this lazy value and - /// returns a reference to result. This is equivalent - /// to the `Deref` impl, but is explicit. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncLazy; - /// - /// let lazy = SyncLazy::new(|| 92); - /// - /// assert_eq!(SyncLazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn force(this: &SyncLazy) -> &T { - this.cell.get_or_init(|| match this.init.take() { - Some(f) => f(), - None => panic!("Lazy instance has previously been poisoned"), - }) - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl T> Deref for SyncLazy { - type Target = T; - fn deref(&self) -> &T { - SyncLazy::force(self) - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl Default for SyncLazy { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> SyncLazy { - SyncLazy::new(T::default) - } -} diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs new file mode 100644 index 0000000000000..535cc1c42fcfd --- /dev/null +++ b/library/std/src/sync/lazy_lock.rs @@ -0,0 +1,121 @@ +use crate::cell::Cell; +use crate::fmt; +use crate::ops::Deref; +use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::sync::OnceLock; + +/// A value which is initialized on the first access. +/// +/// This type is a thread-safe `Lazy`, and can be used in statics. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::collections::HashMap; +/// +/// use std::sync::LazyLock; +/// +/// static HASHMAP: LazyLock> = LazyLock::new(|| { +/// println!("initializing"); +/// let mut m = HashMap::new(); +/// m.insert(13, "Spica".to_string()); +/// m.insert(74, "Hoyten".to_string()); +/// m +/// }); +/// +/// fn main() { +/// println!("ready"); +/// std::thread::spawn(|| { +/// println!("{:?}", HASHMAP.get(&13)); +/// }).join().unwrap(); +/// println!("{:?}", HASHMAP.get(&74)); +/// +/// // Prints: +/// // ready +/// // initializing +/// // Some("Spica") +/// // Some("Hoyten") +/// } +/// ``` +#[unstable(feature = "once_cell", issue = "74465")] +pub struct LazyLock T> { + cell: OnceLock, + init: Cell>, +} + +impl LazyLock { + /// Creates a new lazy value with the given initializing + /// function. + #[unstable(feature = "once_cell", issue = "74465")] + pub const fn new(f: F) -> LazyLock { + LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) } + } +} + +impl T> LazyLock { + /// Forces the evaluation of this lazy value and + /// returns a reference to result. This is equivalent + /// to the `Deref` impl, but is explicit. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::LazyLock; + /// + /// let lazy = LazyLock::new(|| 92); + /// + /// assert_eq!(LazyLock::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn force(this: &LazyLock) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("Lazy instance has previously been poisoned"), + }) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl T> Deref for LazyLock { + type Target = T; + fn deref(&self) -> &T { + LazyLock::force(self) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl Default for LazyLock { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> LazyLock { + LazyLock::new(T::default) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl fmt::Debug for LazyLock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).finish_non_exhaustive() + } +} + +// We never create a `&F` from a `&LazyLock` so it is fine +// to not impl `Sync` for `F` +// we do create a `&mut Option` in `force`, but this is +// properly synchronized, so it only happens once +// so it also does not contribute to this impl. +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl Sync for LazyLock where OnceLock: Sync {} +// auto-derived `Send` impl is OK. + +#[unstable(feature = "once_cell", issue = "74465")] +impl RefUnwindSafe for LazyLock where OnceLock: RefUnwindSafe {} +#[unstable(feature = "once_cell", issue = "74465")] +impl UnwindSafe for LazyLock where OnceLock: UnwindSafe {} + +#[cfg(test)] +mod tests; diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs new file mode 100644 index 0000000000000..f11b66bfca56a --- /dev/null +++ b/library/std/src/sync/lazy_lock/tests.rs @@ -0,0 +1,143 @@ +use crate::{ + cell::LazyCell, + panic, + sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + Mutex, + }, + sync::{LazyLock, OnceLock}, + thread, +}; + +fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { + thread::spawn(f).join().unwrap() +} + +#[test] +fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: LazyCell> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn lazy_poisoning() { + let x: LazyCell = LazyCell::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn sync_lazy_new() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + static SYNC_LAZY: LazyLock = LazyLock::new(|| { + CALLED.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(CALLED.load(SeqCst), 0); + + spawn_and_wait(|| { + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + }); + + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn sync_lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: LazyLock> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn static_sync_lazy() { + static XS: LazyLock> = LazyLock::new(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }); + + spawn_and_wait(|| { + assert_eq!(&*XS, &vec![1, 2, 3]); + }); + + assert_eq!(&*XS, &vec![1, 2, 3]); +} + +#[test] +fn static_sync_lazy_via_fn() { + fn xs() -> &'static Vec { + static XS: OnceLock> = OnceLock::new(); + XS.get_or_init(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }) + } + assert_eq!(xs(), &vec![1, 2, 3]); +} + +#[test] +fn sync_lazy_poisoning() { + let x: LazyLock = LazyLock::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } +} + +#[test] +fn is_sync_send() { + fn assert_traits() {} + assert_traits::>(); +} diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 87d01daeafc4c..5fc18fda6a83b 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -170,11 +170,18 @@ pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +#[unstable(feature = "once_cell", issue = "74465")] +pub use self::lazy_lock::LazyLock; +#[unstable(feature = "once_cell", issue = "74465")] +pub use self::once_lock::OnceLock; + pub mod mpsc; mod barrier; mod condvar; +mod lazy_lock; mod mutex; mod once; +mod once_lock; mod poison; mod rwlock; diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs new file mode 100644 index 0000000000000..813516040cdb6 --- /dev/null +++ b/library/std/src/sync/once_lock.rs @@ -0,0 +1,496 @@ +use crate::cell::UnsafeCell; +use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::MaybeUninit; +use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::pin::Pin; +use crate::sync::Once; + +/// A synchronization primitive which can be written to only once. +/// +/// This type is a thread-safe `OnceCell`. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::sync::OnceLock; +/// +/// static CELL: OnceLock = OnceLock::new(); +/// assert!(CELL.get().is_none()); +/// +/// std::thread::spawn(|| { +/// let value: &String = CELL.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// }).join().unwrap(); +/// +/// let value: Option<&String> = CELL.get(); +/// assert!(value.is_some()); +/// assert_eq!(value.unwrap().as_str(), "Hello, World!"); +/// ``` +#[unstable(feature = "once_cell", issue = "74465")] +pub struct OnceLock { + once: Once, + // Whether or not the value is initialized is tracked by `state_and_queue`. + value: UnsafeCell>, + /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl. + /// + /// ```compile_fail,E0597 + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// struct A<'a>(&'a str); + /// + /// impl<'a> Drop for A<'a> { + /// fn drop(&mut self) {} + /// } + /// + /// let cell = OnceLock::new(); + /// { + /// let s = String::new(); + /// let _ = cell.set(A(&s)); + /// } + /// ``` + _marker: PhantomData, +} + +impl OnceLock { + /// Creates a new empty cell. + #[unstable(feature = "once_cell", issue = "74465")] + #[must_use] + pub const fn new() -> OnceLock { + OnceLock { + once: Once::new(), + value: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData, + } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty, or being initialized. This + /// method never blocks. + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get(&self) -> Option<&T> { + if self.is_initialized() { + // Safe b/c checked is_initialized + Some(unsafe { self.get_unchecked() }) + } else { + None + } + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. This method never blocks. + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_mut(&mut self) -> Option<&mut T> { + if self.is_initialized() { + // Safe b/c checked is_initialized and we have a unique access + Some(unsafe { self.get_unchecked_mut() }) + } else { + None + } + } + + /// Sets the contents of this cell to `value`. + /// + /// May block if another thread is currently attempting to initialize the cell. The cell is + /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// + /// Returns `Ok(())` if the cell's value was set by this call. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// static CELL: OnceLock = OnceLock::new(); + /// + /// fn main() { + /// assert!(CELL.get().is_none()); + /// + /// std::thread::spawn(|| { + /// assert_eq!(CELL.set(92), Ok(())); + /// }).join().unwrap(); + /// + /// assert_eq!(CELL.set(62), Err(62)); + /// assert_eq!(CELL.get(), Some(&92)); + /// } + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn set(&self, value: T) -> Result<(), T> { + let mut value = Some(value); + self.get_or_init(|| value.take().unwrap()); + match value { + None => Ok(()), + Some(value) => Err(value), + } + } + + /// Gets the contents of the cell, initializing it with `f` if the cell + /// was empty. + /// + /// Many threads may call `get_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. The + /// exact outcome is unspecified. Current implementation deadlocks, but + /// this may be changed to a panic in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// let cell = OnceLock::new(); + /// let value = cell.get_or_init(|| 92); + /// assert_eq!(value, &92); + /// let value = cell.get_or_init(|| unreachable!()); + /// assert_eq!(value, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + match self.get_or_try_init(|| Ok::(f())) { + Ok(val) => val, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. + /// The exact outcome is unspecified. Current implementation + /// deadlocks, but this may be changed to a panic in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// let cell = OnceLock::new(); + /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + /// assert!(cell.get().is_none()); + /// let value = cell.get_or_try_init(|| -> Result { + /// Ok(92) + /// }); + /// assert_eq!(value, Ok(&92)); + /// assert_eq!(cell.get(), Some(&92)) + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_or_try_init(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result, + { + // Fast path check + // NOTE: We need to perform an acquire on the state in this method + // in order to correctly synchronize `LazyLock::force`. This is + // currently done by calling `self.get()`, which in turn calls + // `self.is_initialized()`, which in turn performs the acquire. + if let Some(value) = self.get() { + return Ok(value); + } + self.initialize(f)?; + + debug_assert!(self.is_initialized()); + + // SAFETY: The inner value has been initialized + Ok(unsafe { self.get_unchecked() }) + } + + /// Internal-only API that gets the contents of the cell, initializing it + /// in two steps with `f` and `g` if the cell was empty. + /// + /// `f` is called to construct the value, which is then moved into the cell + /// and given as a (pinned) mutable reference to `g` to finish + /// initialization. + /// + /// This allows `g` to inspect an manipulate the value after it has been + /// moved into its final place in the cell, but before the cell is + /// considered initialized. + /// + /// # Panics + /// + /// If `f` or `g` panics, the panic is propagated to the caller, and the + /// cell remains uninitialized. + /// + /// With the current implementation, if `g` panics, the value from `f` will + /// not be dropped. This should probably be fixed if this is ever used for + /// a type where this matters. + /// + /// It is an error to reentrantly initialize the cell from `f`. The exact + /// outcome is unspecified. Current implementation deadlocks, but this may + /// be changed to a panic in the future. + pub(crate) fn get_or_init_pin(self: Pin<&Self>, f: F, g: G) -> Pin<&T> + where + F: FnOnce() -> T, + G: FnOnce(Pin<&mut T>), + { + if let Some(value) = self.get_ref().get() { + // SAFETY: The inner value was already initialized, and will not be + // moved anymore. + return unsafe { Pin::new_unchecked(value) }; + } + + let slot = &self.value; + + // Ignore poisoning from other threads + // If another thread panics, then we'll be able to run our closure + self.once.call_once_force(|_| { + let value = f(); + // SAFETY: We use the Once (self.once) to guarantee unique access + // to the UnsafeCell (slot). + let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; + // SAFETY: The value has been written to its final place in + // self.value. We do not to move it anymore, which we promise here + // with a Pin<&mut T>. + g(unsafe { Pin::new_unchecked(value) }); + }); + + // SAFETY: The inner value has been initialized, and will not be moved + // anymore. + unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } + } + + /// Consumes the `OnceLock`, returning the wrapped value. Returns + /// `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// let cell: OnceLock = OnceLock::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceLock::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn into_inner(mut self) -> Option { + self.take() + } + + /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state. + /// + /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized. + /// + /// Safety is guaranteed by requiring a mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell: OnceLock = OnceLock::new(); + /// assert_eq!(cell.take(), None); + /// + /// let mut cell = OnceLock::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.take(), Some("hello".to_string())); + /// assert_eq!(cell.get(), None); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn take(&mut self) -> Option { + if self.is_initialized() { + self.once = Once::new(); + // SAFETY: `self.value` is initialized and contains a valid `T`. + // `self.once` is reset, so `is_initialized()` will be false again + // which prevents the value from being read twice. + unsafe { Some((&mut *self.value.get()).assume_init_read()) } + } else { + None + } + } + + #[inline] + fn is_initialized(&self) -> bool { + self.once.is_completed() + } + + #[cold] + fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result, + { + let mut res: Result<(), E> = Ok(()); + let slot = &self.value; + + // Ignore poisoning from other threads + // If another thread panics, then we'll be able to run our closure + self.once.call_once_force(|p| { + match f() { + Ok(value) => { + unsafe { (&mut *slot.get()).write(value) }; + } + Err(e) => { + res = Err(e); + + // Treat the underlying `Once` as poisoned since we + // failed to initialize our value. Calls + p.poison(); + } + } + }); + res + } + + /// # Safety + /// + /// The value must be initialized + unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + (&*self.value.get()).assume_init_ref() + } + + /// # Safety + /// + /// The value must be initialized + unsafe fn get_unchecked_mut(&mut self) -> &mut T { + debug_assert!(self.is_initialized()); + (&mut *self.value.get()).assume_init_mut() + } +} + +// Why do we need `T: Send`? +// Thread A creates a `OnceLock` and shares it with +// scoped thread B, which fills the cell, which is +// then destroyed by A. That is, destructor observes +// a sent value. +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl Sync for OnceLock {} +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl Send for OnceLock {} + +#[unstable(feature = "once_cell", issue = "74465")] +impl RefUnwindSafe for OnceLock {} +#[unstable(feature = "once_cell", issue = "74465")] +impl UnwindSafe for OnceLock {} + +#[unstable(feature = "once_cell", issue = "74465")] +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl const Default for OnceLock { + /// Creates a new empty cell. + /// + /// # Example + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// fn main() { + /// assert_eq!(OnceLock::<()>::new(), OnceLock::default()); + /// } + /// ``` + fn default() -> OnceLock { + OnceLock::new() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl fmt::Debug for OnceLock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("Once").field(v).finish(), + None => f.write_str("Once(Uninit)"), + } + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl Clone for OnceLock { + fn clone(&self) -> OnceLock { + let cell = Self::new(); + if let Some(value) = self.get() { + match cell.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + cell + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl From for OnceLock { + /// Create a new cell with its contents set to `value`. + /// + /// # Example + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// # fn main() -> Result<(), i32> { + /// let a = OnceLock::from(3); + /// let b = OnceLock::new(); + /// b.set(3)?; + /// assert_eq!(a, b); + /// Ok(()) + /// # } + /// ``` + fn from(value: T) -> Self { + let cell = Self::new(); + match cell.set(value) { + Ok(()) => cell, + Err(_) => unreachable!(), + } + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl PartialEq for OnceLock { + fn eq(&self, other: &OnceLock) -> bool { + self.get() == other.get() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl Eq for OnceLock {} + +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl<#[may_dangle] T> Drop for OnceLock { + fn drop(&mut self) { + if self.is_initialized() { + // SAFETY: The cell is initialized and being dropped, so it can't + // be accessed again. We also don't touch the `T` other than + // dropping it, which validates our usage of #[may_dangle]. + unsafe { (&mut *self.value.get()).assume_init_drop() }; + } + } +} + +#[cfg(test)] +mod tests; diff --git a/library/std/src/lazy/tests.rs b/library/std/src/sync/once_lock/tests.rs similarity index 50% rename from library/std/src/lazy/tests.rs rename to library/std/src/sync/once_lock/tests.rs index 66d6236c1117f..46695225b9f5a 100644 --- a/library/std/src/lazy/tests.rs +++ b/library/std/src/sync/once_lock/tests.rs @@ -1,49 +1,13 @@ use crate::{ - cell::LazyCell, - lazy::{SyncLazy, SyncOnceCell}, panic, + sync::OnceLock, sync::{ atomic::{AtomicUsize, Ordering::SeqCst}, mpsc::channel, - Mutex, }, thread, }; -#[test] -fn lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: LazyCell> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); -} - -#[test] -fn lazy_poisoning() { - let x: LazyCell = LazyCell::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } -} - fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { thread::spawn(f).join().unwrap() } @@ -51,7 +15,7 @@ fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn sync_once_cell() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); + static ONCE_CELL: OnceLock = OnceLock::new(); assert!(ONCE_CELL.get().is_none()); @@ -66,7 +30,7 @@ fn sync_once_cell() { #[test] fn sync_once_cell_get_mut() { - let mut c = SyncOnceCell::new(); + let mut c = OnceLock::new(); assert!(c.get_mut().is_none()); c.set(90).unwrap(); *c.get_mut().unwrap() += 2; @@ -75,7 +39,7 @@ fn sync_once_cell_get_mut() { #[test] fn sync_once_cell_get_unchecked() { - let c = SyncOnceCell::new(); + let c = OnceLock::new(); c.set(92).unwrap(); unsafe { assert_eq!(c.get_unchecked(), &92); @@ -93,7 +57,7 @@ fn sync_once_cell_drop() { } } - let x = SyncOnceCell::new(); + let x = OnceLock::new(); spawn_and_wait(move || { x.get_or_init(|| Dropper); assert_eq!(DROP_CNT.load(SeqCst), 0); @@ -105,13 +69,13 @@ fn sync_once_cell_drop() { #[test] fn sync_once_cell_drop_empty() { - let x = SyncOnceCell::::new(); + let x = OnceLock::::new(); drop(x); } #[test] fn clone() { - let s = SyncOnceCell::new(); + let s = OnceLock::new(); let c = s.clone(); assert!(c.get().is_none()); @@ -122,7 +86,7 @@ fn clone() { #[test] fn get_or_try_init() { - let cell: SyncOnceCell = SyncOnceCell::new(); + let cell: OnceLock = OnceLock::new(); assert!(cell.get().is_none()); let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); @@ -138,122 +102,32 @@ fn get_or_try_init() { #[test] fn from_impl() { - assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); - assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); + assert_eq!(OnceLock::from("value").get(), Some(&"value")); + assert_ne!(OnceLock::from("foo").get(), Some(&"bar")); } #[test] fn partialeq_impl() { - assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); - assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); + assert!(OnceLock::from("value") == OnceLock::from("value")); + assert!(OnceLock::from("foo") != OnceLock::from("bar")); - assert!(SyncOnceCell::::new() == SyncOnceCell::new()); - assert!(SyncOnceCell::::new() != SyncOnceCell::from("value".to_owned())); + assert!(OnceLock::::new() == OnceLock::new()); + assert!(OnceLock::::new() != OnceLock::from("value".to_owned())); } #[test] fn into_inner() { - let cell: SyncOnceCell = SyncOnceCell::new(); + let cell: OnceLock = OnceLock::new(); assert_eq!(cell.into_inner(), None); - let cell = SyncOnceCell::new(); + let cell = OnceLock::new(); cell.set("hello".to_string()).unwrap(); assert_eq!(cell.into_inner(), Some("hello".to_string())); } -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn sync_lazy_new() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - static SYNC_LAZY: SyncLazy = SyncLazy::new(|| { - CALLED.fetch_add(1, SeqCst); - 92 - }); - - assert_eq!(CALLED.load(SeqCst), 0); - - spawn_and_wait(|| { - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - }); - - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); -} - -#[test] -fn sync_lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: SyncLazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn static_sync_lazy() { - static XS: SyncLazy> = SyncLazy::new(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }); - - spawn_and_wait(|| { - assert_eq!(&*XS, &vec![1, 2, 3]); - }); - - assert_eq!(&*XS, &vec![1, 2, 3]); -} - -#[test] -fn static_sync_lazy_via_fn() { - fn xs() -> &'static Vec { - static XS: SyncOnceCell> = SyncOnceCell::new(); - XS.get_or_init(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }) - } - assert_eq!(xs(), &vec![1, 2, 3]); -} - -#[test] -fn sync_lazy_poisoning() { - let x: SyncLazy = SyncLazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } -} - #[test] fn is_sync_send() { fn assert_traits() {} - assert_traits::>(); - assert_traits::>(); + assert_traits::>(); } #[test] @@ -262,7 +136,7 @@ fn eval_once_macro() { (|| -> $ty:ty { $($body:tt)* }) => {{ - static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); + static ONCE_CELL: OnceLock<$ty> = OnceLock::new(); fn init() -> $ty { $($body)* } @@ -286,7 +160,7 @@ fn eval_once_macro() { #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn sync_once_cell_does_not_leak_partially_constructed_boxes() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); + static ONCE_CELL: OnceLock = OnceLock::new(); let n_readers = 10; let n_writers = 3; @@ -321,7 +195,7 @@ fn sync_once_cell_does_not_leak_partially_constructed_boxes() { #[test] fn dropck() { - let cell = SyncOnceCell::new(); + let cell = OnceLock::new(); { let s = String::new(); cell.set(&s).unwrap(); diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 5de1231378488..d1e72cd54437c 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -2,13 +2,13 @@ use crate::cmp; use crate::io::{self, IoSlice, IoSliceMut, Read}; -use crate::lazy::SyncOnceCell; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; use crate::ptr; +use crate::sync::OnceLock; use crate::sys; use crate::sys::c; use crate::sys_common::net; @@ -29,7 +29,7 @@ pub mod netc { pub struct Socket(OwnedSocket); -static WSA_CLEANUP: SyncOnceCell i32> = SyncOnceCell::new(); +static WSA_CLEANUP: OnceLock i32> = OnceLock::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index 22e024d8552ec..57248e3651ba2 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -1,6 +1,6 @@ use crate::io; -use crate::lazy; use crate::mem; +use crate::sync; use crate::sys::c; /// The kinds of HashMap RNG that may be available @@ -28,7 +28,7 @@ fn get_hashmap_rng() -> HashMapRng { // Assume that if the preferred RNG is broken the first time we use it, it likely means // that: the DLL has failed to load, there is no point to calling it over-and-over again, // and we should cache the result - static VALUE: lazy::SyncOnceCell = lazy::SyncOnceCell::new(); + static VALUE: sync::OnceLock = sync::OnceLock::new(); *VALUE.get_or_init(choose_hashmap_rng) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 4605793d0df94..6a6c78a26dcf7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,10 +1,10 @@ use std::cell::RefCell; use std::default::Default; use std::hash::Hash; -use std::lazy::SyncOnceCell as OnceCell; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; +use std::sync::OnceLock as OnceCell; use std::{cmp, fmt, iter}; use arrayvec::ArrayVec; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 53281bfde2e4f..51b245e36ba3b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -21,9 +21,9 @@ use rustc_span::symbol::sym; use rustc_span::{source_map, Span, Symbol}; use std::cell::RefCell; -use std::lazy::SyncLazy; use std::mem; use std::rc::Rc; +use std::sync::LazyLock; use crate::clean::inline::build_external_trait; use crate::clean::{self, ItemId, TraitWithExtraInfo}; @@ -293,8 +293,8 @@ pub(crate) fn create_config( providers.typeck_item_bodies = |_, _| {}; // hack so that `used_trait_imports` won't try to call typeck providers.used_trait_imports = |_, _| { - static EMPTY_SET: SyncLazy> = - SyncLazy::new(FxHashSet::default); + static EMPTY_SET: LazyLock> = + LazyLock::new(FxHashSet::default); &EMPTY_SET }; // In case typeck does end up being called, don't ICE in case there were name resolution errors diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 8f08ff2ece3f6..9bddee199c7bf 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -3,9 +3,9 @@ use std::fmt::Write; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; -use std::lazy::SyncLazy as Lazy; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; +use std::sync::LazyLock as Lazy; use itertools::Itertools; use rustc_data_structures::flock; diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 08a1a868521f4..240aec52cff02 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -3,7 +3,7 @@ use rustc_lint::LintStore; use rustc_lint_defs::{declare_tool_lint, Lint, LintId}; use rustc_session::{lint, Session}; -use std::lazy::SyncLazy as Lazy; +use std::sync::LazyLock as Lazy; /// This function is used to setup the lint initialization. By default, in rustdoc, everything /// is "allowed". Depending if we run in test mode or not, we want some of them to be at their diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs index e9e810658ef85..392e26ea6ac4c 100644 --- a/src/librustdoc/passes/bare_urls.rs +++ b/src/librustdoc/passes/bare_urls.rs @@ -9,8 +9,8 @@ use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use regex::Regex; use rustc_errors::Applicability; -use std::lazy::SyncLazy; use std::mem; +use std::sync::LazyLock; pub(crate) const CHECK_BARE_URLS: Pass = Pass { name: "check-bare-urls", @@ -18,7 +18,7 @@ pub(crate) const CHECK_BARE_URLS: Pass = Pass { description: "detects URLs that are not hyperlinks", }; -static URL_REGEX: SyncLazy = SyncLazy::new(|| { +static URL_REGEX: LazyLock = LazyLock::new(|| { Regex::new(concat!( r"https?://", // url scheme r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains diff --git a/src/test/run-make/libtest-thread-limit/test.rs b/src/test/run-make/libtest-thread-limit/test.rs index d899411a49ea0..26bc29216cf1a 100644 --- a/src/test/run-make/libtest-thread-limit/test.rs +++ b/src/test/run-make/libtest-thread-limit/test.rs @@ -1,8 +1,12 @@ #![feature(once_cell)] -use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}}; +use std::{ + io::ErrorKind, + sync::OnceLock, + thread::{self, Builder, ThreadId}, +}; -static THREAD_ID: SyncOnceCell = SyncOnceCell::new(); +static THREAD_ID: OnceLock = OnceLock::new(); #[test] fn spawn_thread_would_block() { diff --git a/src/tools/clippy/clippy_dev/src/bless.rs b/src/tools/clippy/clippy_dev/src/bless.rs index 8e5c739afe05a..f5c51b9474fcd 100644 --- a/src/tools/clippy/clippy_dev/src/bless.rs +++ b/src/tools/clippy/clippy_dev/src/bless.rs @@ -4,12 +4,12 @@ use crate::cargo_clippy_path; use std::ffi::OsStr; use std::fs; -use std::lazy::SyncLazy; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; use walkdir::{DirEntry, WalkDir}; -static CLIPPY_BUILD_TIME: SyncLazy> = - SyncLazy::new(|| cargo_clippy_path().metadata().ok()?.modified().ok()); +static CLIPPY_BUILD_TIME: LazyLock> = + LazyLock::new(|| cargo_clippy_path().metadata().ok()?.modified().ok()); /// # Panics /// diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 0cf23ca626c75..052d9756c5153 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -62,7 +62,7 @@ pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, Spanl use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; -use std::lazy::SyncOnceCell; +use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; @@ -2078,7 +2078,7 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { false } -static TEST_ITEM_NAMES_CACHE: SyncOnceCell>>> = SyncOnceCell::new(); +static TEST_ITEM_NAMES_CACHE: OnceLock>>> = OnceLock::new(); fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 7de40fe63ac23..67467f89b475f 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -21,11 +21,11 @@ use rustc_tools_util::VersionInfo; use std::borrow::Cow; use std::env; -use std::lazy::SyncLazy; use std::ops::Deref; use std::panic; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; +use std::sync::LazyLock; /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. @@ -152,7 +152,7 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = SyncLazy::new(|| { +static ICE_HOOK: LazyLock) + Sync + Send + 'static>> = LazyLock::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); hook @@ -219,7 +219,7 @@ fn toolchain_path(home: Option, toolchain: Option) -> Option = env::args().collect(); diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 04c2eeff08b6f..061cda7e01e5b 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -12,8 +12,8 @@ use std::env::{self, remove_var, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fs; use std::io; -use std::lazy::SyncLazy; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; use test_utils::IS_RUSTC_TEST_SUITE; mod test_utils; @@ -69,7 +69,7 @@ extern crate tokio; /// dependencies must be added to Cargo.toml at the project root. Test /// dependencies that are not *directly* used by this test module require an /// `extern crate` declaration. -static EXTERN_FLAGS: SyncLazy = SyncLazy::new(|| { +static EXTERN_FLAGS: LazyLock = LazyLock::new(|| { let current_exe_depinfo = { let mut path = env::current_exe().unwrap(); path.set_extension("d"); diff --git a/src/tools/clippy/tests/test_utils/mod.rs b/src/tools/clippy/tests/test_utils/mod.rs index 8a4de3f6def90..ea8c54e08b338 100644 --- a/src/tools/clippy/tests/test_utils/mod.rs +++ b/src/tools/clippy/tests/test_utils/mod.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] // see https://github.com/rust-lang/rust/issues/46379 -use std::lazy::SyncLazy; use std::path::PathBuf; +use std::sync::LazyLock; -pub static CARGO_CLIPPY_PATH: SyncLazy = SyncLazy::new(|| { +pub static CARGO_CLIPPY_PATH: LazyLock = LazyLock::new(|| { let mut path = std::env::current_exe().unwrap(); assert!(path.pop()); // deps path.set_file_name("cargo-clippy");