diff options
67 files changed, 1342 insertions, 1273 deletions
diff --git a/Cargo.lock b/Cargo.lock index acda64172b1..671f85ca3b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,7 +332,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap 3.1.1", + "clap 3.2.5", "crates-io", "crossbeam-utils", "curl", @@ -470,7 +470,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.1.3" +version = "0.1.4" dependencies = [ "anyhow", "core-foundation", @@ -615,19 +615,19 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.1" +version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d76c22c9b9b215eeb8d016ad3a90417bd13cb24cf8142756e6472445876cab7" +checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7" dependencies = [ "atty", "bitflags", "clap_derive", + "clap_lex", "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.14.2", + "textwrap 0.15.0", ] [[package]] @@ -636,14 +636,14 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25" dependencies = [ - "clap 3.1.1", + "clap 3.2.5", ] [[package]] name = "clap_derive" -version = "3.1.18" +version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -653,6 +653,15 @@ dependencies = [ ] [[package]] +name = "clap_lex" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613" +dependencies = [ + "os_str_bytes", +] + +[[package]] name = "clippy" version = "0.1.63" dependencies = [ @@ -684,7 +693,7 @@ name = "clippy_dev" version = "0.0.1" dependencies = [ "aho-corasick", - "clap 3.1.1", + "clap 3.2.5", "indoc", "itertools", "opener", @@ -2334,7 +2343,7 @@ dependencies = [ "ammonia", "anyhow", "chrono", - "clap 3.1.1", + "clap 3.2.5", "clap_complete", "elasticlunr-rs", "env_logger 0.7.1", @@ -2572,9 +2581,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" @@ -2657,9 +2666,6 @@ name = "os_str_bytes" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] [[package]] name = "output_vt100" @@ -3515,7 +3521,7 @@ version = "1.0.0" dependencies = [ "bstr", "byteorder", - "clap 3.1.1", + "clap 3.2.5", "crossbeam-utils", "libc", "libz-sys", @@ -4696,7 +4702,7 @@ dependencies = [ "anyhow", "bytecount", "cargo_metadata", - "clap 3.1.1", + "clap 3.2.5", "derive-new", "diff", "dirs", @@ -5259,9 +5265,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 1b01f4edbb3..a56a9100059 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_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 0910e7c94ea..71699b5cf38 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -36,9 +36,9 @@ use rustc_target::abi::Size; use libc::c_uint; use smallvec::SmallVec; +use std::cell::OnceCell; use std::cell::RefCell; use std::iter; -use std::lazy::OnceCell; use tracing::debug; mod create_scope_map; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e70509f3ecc..39c7a408fb5 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -38,11 +38,11 @@ use regex::Regex; use tempfile::Builder as TempFileBuilder; use std::borrow::Borrow; +use std::cell::OnceCell; use std::collections::BTreeSet; use std::ffi::OsString; use std::fs::{File, OpenOptions}; use std::io::{BufWriter, Write}; -use std::lazy::OnceCell; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 41605afb44e..09baa3095a4 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<Client> = SyncLazy::new(|| unsafe { +static GLOBAL_CLIENT: LazyLock<Client> = 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 f99ca53ab25..feb82cb0938 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -173,7 +173,7 @@ cfg_if! { pub use std::cell::RefMut as LockGuard; pub use std::cell::RefMut as MappedLockGuard; - pub use std::lazy::OnceCell; + pub use std::cell::OnceCell; use std::cell::RefCell as InnerRwLock; use std::cell::RefCell as InnerLock; @@ -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 8cdbb1a6704..caa92e74808 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<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = - SyncLazy::new(|| { +static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + 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 fd4b2daae9c..fefcaa898c1 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -18,9 +18,9 @@ use std::path::{Path, PathBuf}; use tracing::{instrument, trace}; #[cfg(not(parallel_compiler))] -use std::lazy::Lazy; +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 d4452a79dfb..6fcdfe44d8f 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<FxHashMap<Symbol, &BuiltinAttribute>> = - SyncLazy::new(|| { +pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> = + 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 9e5d7818924..b0bfac8e1f5 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<FxHashMap<Symbol, (usize, Target)>> = SyncLazy::new(|| { + pub static ITEM_REFS: LazyLock<FxHashMap<Symbol, (usize, Target)>> = 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 78748209d1a..dad22725511 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<StableMap<Symbol, LangItem>> = SyncLazy::new(|| { +pub static WEAK_ITEMS_REFS: LazyLock<StableMap<Symbol, LangItem>> = 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 19f086b3a44..502afa493fe 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -44,11 +44,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> { @@ -774,7 +774,7 @@ pub fn prepare_outputs( Ok(outputs) } -pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| { +pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; proc_macro_decls::provide(providers); @@ -799,7 +799,7 @@ pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| { *providers }); -pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| { +pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock<ExternProviders> = 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 3fa8017dc93..fb9258eb4a9 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<PathBuf>, backend_name: Option<&str>, ) -> Box<dyn CodegenBackend> { - static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new(); + static LOAD: OnceLock<unsafe fn() -> Box<dyn CodegenBackend>> = 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<Option<PathBuf>> = SyncOnceCell::new(); + static RUSTC_PATH: OnceLock<Option<PathBuf>> = 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 59a2053ec70..c94198c56a8 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<regex::Regex> = SyncOnceCell::new(); + static RE: OnceLock<regex::Regex> = 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 d31ac04274c..0f8679b0bd6 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<DebugOptions> = SyncOnceCell::new(); + static DEBUG_OPTIONS: OnceLock<DebugOptions> = OnceLock::new(); &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env) } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 2db5f5d4071..ad85ac71fc8 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -29,9 +29,9 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use std::cell::LazyCell; use std::convert::TryInto; use std::iter; -use std::lazy::Lazy; use std::ops::ControlFlow; /// Helper type of a temporary returned by `.for_item(...)`. @@ -1728,7 +1728,7 @@ fn check_variances_for_type_defn<'tcx>( identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters); // Lazily calculated because it is only needed in case of an error. - let explicitly_bounded_params = Lazy::new(|| { + let explicitly_bounded_params = LazyCell::new(|| { let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id()); hir_generics .predicates diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 321f2feb921..63c83ddb6f7 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -199,6 +199,14 @@ use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut}; use crate::ptr::{self, NonNull}; +mod lazy; +mod once; + +#[unstable(feature = "once_cell", issue = "74465")] +pub use lazy::LazyCell; +#[unstable(feature = "once_cell", issue = "74465")] +pub use once::OnceCell; + /// A mutable memory location. /// /// # Examples diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs new file mode 100644 index 00000000000..7844be5f783 --- /dev/null +++ b/library/core/src/cell/lazy.rs @@ -0,0 +1,104 @@ +use crate::cell::{Cell, OnceCell}; +use crate::fmt; +use crate::ops::Deref; + +/// A value which is initialized on the first access. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::cell::LazyCell; +/// +/// let lazy: LazyCell<i32> = LazyCell::new(|| { +/// println!("initializing"); +/// 92 +/// }); +/// println!("ready"); +/// println!("{}", *lazy); +/// println!("{}", *lazy); +/// +/// // Prints: +/// // ready +/// // initializing +/// // 92 +/// // 92 +/// ``` +#[unstable(feature = "once_cell", issue = "74465")] +pub struct LazyCell<T, F = fn() -> T> { + cell: OnceCell<T>, + init: Cell<Option<F>>, +} + +impl<T, F> LazyCell<T, F> { + /// Creates a new lazy value with the given initializing function. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::LazyCell; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = LazyCell::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub const fn new(init: F) -> LazyCell<T, F> { + LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) } + } +} + +impl<T, F: FnOnce() -> T> LazyCell<T, F> { + /// Forces the evaluation of this lazy value and returns a reference to + /// the result. + /// + /// This is equivalent to the `Deref` impl, but is explicit. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::LazyCell; + /// + /// let lazy = LazyCell::new(|| 92); + /// + /// assert_eq!(LazyCell::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn force(this: &LazyCell<T, F>) -> &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, F: FnOnce() -> T> Deref for LazyCell<T, F> { + type Target = T; + fn deref(&self) -> &T { + LazyCell::force(self) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Default> Default for LazyCell<T> { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> LazyCell<T> { + LazyCell::new(T::default) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } +} diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs new file mode 100644 index 00000000000..3c39394dd8c --- /dev/null +++ b/library/core/src/cell/once.rs @@ -0,0 +1,283 @@ +use crate::cell::UnsafeCell; +use crate::fmt; +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. +/// +/// # Examples +/// +/// ``` +/// #![feature(once_cell)] +/// +/// use std::cell::OnceCell; +/// +/// let cell = OnceCell::new(); +/// assert!(cell.get().is_none()); +/// +/// let value: &String = cell.get_or_init(|| { +/// "Hello, World!".to_string() +/// }); +/// assert_eq!(value, "Hello, World!"); +/// assert!(cell.get().is_some()); +/// ``` +#[unstable(feature = "once_cell", issue = "74465")] +pub struct OnceCell<T> { + // Invariant: written to at most once. + inner: UnsafeCell<Option<T>>, +} + +impl<T> OnceCell<T> { + /// Creates a new empty cell. + #[unstable(feature = "once_cell", issue = "74465")] + #[must_use] + pub const fn new() -> OnceCell<T> { + OnceCell { inner: UnsafeCell::new(None) } + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get(&self) -> Option<&T> { + // SAFETY: Safe due to `inner`'s invariant + unsafe { &*self.inner.get() }.as_ref() + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[unstable(feature = "once_cell", issue = "74465")] + pub fn get_mut(&mut self) -> Option<&mut T> { + self.inner.get_mut().as_mut() + } + + /// Sets the contents of the cell to `value`. + /// + /// # Errors + /// + /// This method returns `Ok(())` if the cell was empty and `Err(value)` if + /// it was full. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.set(92), Ok(())); + /// assert_eq!(cell.set(62), Err(62)); + /// + /// assert!(cell.get().is_some()); + /// ``` + #[unstable(feature = "once_cell", issue = "74465")] + pub fn set(&self, value: T) -> Result<(), T> { + // SAFETY: Safe because we cannot have overlapping mutable borrows + let slot = unsafe { &*self.inner.get() }; + if slot.is_some() { + return Err(value); + } + + // SAFETY: This is the only place where we set the slot, no races + // due to reentrancy/concurrency are possible, and we've + // checked that slot is currently `None`, so this write + // maintains the `inner`'s invariant. + let slot = unsafe { &mut *self.inner.get() }; + *slot = Some(value); + Ok(()) + } + + /// Gets the contents of the cell, initializing it with `f` + /// if the cell was empty. + /// + /// # 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`. Doing + /// so results in a panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::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<F>(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + match self.get_or_try_init(|| Ok::<T, !>(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`. Doing + /// so results in a panic. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + /// assert!(cell.get().is_none()); + /// let value = cell.get_or_try_init(|| -> Result<i32, ()> { + /// 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<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + if let Some(val) = self.get() { + return Ok(val); + } + /// Avoid inlining the initialization closure into the common path that fetches + /// the already initialized value + #[cold] + fn outlined_call<F, T, E>(f: F) -> Result<T, E> + where + F: FnOnce() -> Result<T, E>, + { + f() + } + let val = outlined_call(f)?; + // Note that *some* forms of reentrant initialization might lead to + // UB (see `reentrant_init` test). I believe that just removing this + // `assert`, while keeping `set/get` would be sound, but it seems + // better to panic, rather than to silently use an old value. + assert!(self.set(val).is_ok(), "reentrant init"); + Ok(self.get().unwrap()) + } + + /// Consumes the cell, returning the wrapped value. + /// + /// Returns `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let cell: OnceCell<String> = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::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(self) -> Option<T> { + // 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<T>`. + self.inner.into_inner() + } + + /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. + /// + /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. + /// + /// Safety is guaranteed by requiring a mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell: OnceCell<String> = OnceCell::new(); + /// assert_eq!(cell.take(), None); + /// + /// let mut cell = OnceCell::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<T> { + mem::take(self).into_inner() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T> Default for OnceCell<T> { + fn default() -> Self { + Self::new() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Clone> Clone for OnceCell<T> { + fn clone(&self) -> OnceCell<T> { + let res = OnceCell::new(); + if let Some(value) = self.get() { + match res.set(value.clone()) { + Ok(()) => (), + Err(_) => unreachable!(), + } + } + res + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: PartialEq> PartialEq for OnceCell<T> { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Eq> Eq for OnceCell<T> {} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T> const From<T> for OnceCell<T> { + /// Creates a new `OnceCell<T>` which already contains the given `value`. + fn from(value: T) -> Self { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } +} diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs index 88826782a3d..f8c06c3f9ae 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -1,389 +1 @@ //! Lazy values and one-time initialization of static data. - -use crate::cell::{Cell, UnsafeCell}; -use crate::fmt; -use crate::mem; -use crate::ops::Deref; - -/// 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. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::lazy::OnceCell; -/// -/// let cell = OnceCell::new(); -/// assert!(cell.get().is_none()); -/// -/// let value: &String = cell.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// assert!(cell.get().is_some()); -/// ``` -#[unstable(feature = "once_cell", issue = "74465")] -pub struct OnceCell<T> { - // Invariant: written to at most once. - inner: UnsafeCell<Option<T>>, -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T> Default for OnceCell<T> { - fn default() -> Self { - Self::new() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: fmt::Debug> fmt::Debug for OnceCell<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { - Some(v) => f.debug_tuple("OnceCell").field(v).finish(), - None => f.write_str("OnceCell(Uninit)"), - } - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Clone> Clone for OnceCell<T> { - fn clone(&self) -> OnceCell<T> { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } - } - res - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: PartialEq> PartialEq for OnceCell<T> { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Eq> Eq for OnceCell<T> {} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T> const From<T> for OnceCell<T> { - /// Creates a new `OnceCell<T>` which already contains the given `value`. - fn from(value: T) -> Self { - OnceCell { inner: UnsafeCell::new(Some(value)) } - } -} - -impl<T> OnceCell<T> { - /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "74465")] - #[must_use] - pub const fn new() -> OnceCell<T> { - OnceCell { inner: UnsafeCell::new(None) } - } - - /// Gets the reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get(&self) -> Option<&T> { - // SAFETY: Safe due to `inner`'s invariant - unsafe { &*self.inner.get() }.as_ref() - } - - /// Gets the mutable reference to the underlying value. - /// - /// Returns `None` if the cell is empty. - #[unstable(feature = "once_cell", issue = "74465")] - pub fn get_mut(&mut self) -> Option<&mut T> { - self.inner.get_mut().as_mut() - } - - /// Sets the contents of the cell to `value`. - /// - /// # Errors - /// - /// This method returns `Ok(())` if the cell was empty and `Err(value)` if - /// it was full. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert!(cell.get().is_none()); - /// - /// assert_eq!(cell.set(92), Ok(())); - /// assert_eq!(cell.set(62), Err(62)); - /// - /// assert!(cell.get().is_some()); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn set(&self, value: T) -> Result<(), T> { - // SAFETY: Safe because we cannot have overlapping mutable borrows - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); - } - - // SAFETY: This is the only place where we set the slot, no races - // due to reentrancy/concurrency are possible, and we've - // checked that slot is currently `None`, so this write - // maintains the `inner`'s invariant. - let slot = unsafe { &mut *self.inner.get() }; - *slot = Some(value); - Ok(()) - } - - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. - /// - /// # 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`. Doing - /// so results in a panic. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::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<F>(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::<T, !>(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`. Doing - /// so results in a panic. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell = OnceCell::new(); - /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - /// assert!(cell.get().is_none()); - /// let value = cell.get_or_try_init(|| -> Result<i32, ()> { - /// 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<F, E>(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result<T, E>, - { - if let Some(val) = self.get() { - return Ok(val); - } - /// Avoid inlining the initialization closure into the common path that fetches - /// the already initialized value - #[cold] - fn outlined_call<F, T, E>(f: F) -> Result<T, E> - where - F: FnOnce() -> Result<T, E>, - { - f() - } - let val = outlined_call(f)?; - // Note that *some* forms of reentrant initialization might lead to - // UB (see `reentrant_init` test). I believe that just removing this - // `assert`, while keeping `set/get` would be sound, but it seems - // better to panic, rather than to silently use an old value. - assert!(self.set(val).is_ok(), "reentrant init"); - Ok(self.get().unwrap()) - } - - /// Consumes the cell, returning the wrapped value. - /// - /// Returns `None` if the cell was empty. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let cell: OnceCell<String> = OnceCell::new(); - /// assert_eq!(cell.into_inner(), None); - /// - /// let cell = OnceCell::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(self) -> Option<T> { - // 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<T>`. - self.inner.into_inner() - } - - /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. - /// - /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. - /// - /// Safety is guaranteed by requiring a mutable reference. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::OnceCell; - /// - /// let mut cell: OnceCell<String> = OnceCell::new(); - /// assert_eq!(cell.take(), None); - /// - /// let mut cell = OnceCell::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<T> { - mem::take(self).into_inner() - } -} - -/// A value which is initialized on the first access. -/// -/// # Examples -/// -/// ``` -/// #![feature(once_cell)] -/// -/// use std::lazy::Lazy; -/// -/// let lazy: Lazy<i32> = Lazy::new(|| { -/// println!("initializing"); -/// 92 -/// }); -/// println!("ready"); -/// println!("{}", *lazy); -/// println!("{}", *lazy); -/// -/// // Prints: -/// // ready -/// // initializing -/// // 92 -/// // 92 -/// ``` -#[unstable(feature = "once_cell", issue = "74465")] -pub struct Lazy<T, F = fn() -> T> { - cell: OnceCell<T>, - init: Cell<Option<F>>, -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() - } -} - -impl<T, F> Lazy<T, F> { - /// Creates a new lazy value with the given initializing function. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// # fn main() { - /// use std::lazy::Lazy; - /// - /// let hello = "Hello, World!".to_string(); - /// - /// let lazy = Lazy::new(|| hello.to_uppercase()); - /// - /// assert_eq!(&*lazy, "HELLO, WORLD!"); - /// # } - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub const fn new(init: F) -> Lazy<T, F> { - Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } - } -} - -impl<T, F: FnOnce() -> T> Lazy<T, F> { - /// Forces the evaluation of this lazy value and returns a reference to - /// the result. - /// - /// This is equivalent to the `Deref` impl, but is explicit. - /// - /// # Examples - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::Lazy; - /// - /// let lazy = Lazy::new(|| 92); - /// - /// assert_eq!(Lazy::force(&lazy), &92); - /// assert_eq!(&*lazy, &92); - /// ``` - #[unstable(feature = "once_cell", issue = "74465")] - pub fn force(this: &Lazy<T, F>) -> &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, F: FnOnce() -> T> Deref for Lazy<T, F> { - type Target = T; - fn deref(&self) -> &T { - Lazy::force(self) - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Default> Default for Lazy<T> { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> Lazy<T> { - Lazy::new(T::default) - } -} diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 81b1db4ac6f..b0c55ca4f51 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -82,9 +82,10 @@ use super::Utf8Error; /// assert_eq!("💖", sparkle_heart); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] +#[rustc_allow_const_fn_unstable(str_internals)] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - // This should use `?` again, once it's `const` + // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { Ok(_) => { // SAFETY: validation succeeded. diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index a127dd57eee..4e569fcc866 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -72,7 +72,7 @@ impl Utf8Error { /// assert_eq!(1, error.valid_up_to()); /// ``` #[stable(feature = "utf8_error", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] + #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[must_use] #[inline] pub const fn valid_up_to(&self) -> usize { @@ -95,11 +95,11 @@ impl Utf8Error { /// /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html #[stable(feature = "utf8_error_error_len", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] + #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[must_use] #[inline] pub const fn error_len(&self) -> Option<usize> { - // This should become `map` again, once it's `const` + // FIXME: This should become `map` again, once it's `const` match self.error_len { Some(len) => Some(len as usize), None => None, diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs index 416d2b2dae4..70fcc6d2d4b 100644 --- a/library/core/tests/lazy.rs +++ b/library/core/tests/lazy.rs @@ -1,6 +1,5 @@ use core::{ - cell::Cell, - lazy::{Lazy, OnceCell}, + cell::{Cell, LazyCell, OnceCell}, sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; @@ -91,7 +90,7 @@ fn into_inner() { #[test] fn lazy_new() { let called = Cell::new(0); - let x = Lazy::new(|| { + let x = LazyCell::new(|| { called.set(called.get() + 1); 92 }); diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index ae16015e35a..e3b62894d0f 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<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new(); + static INSTANCE: OnceLock<Mutex<BufReader<StdinRaw>>> = 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<LineWriter<StdoutRaw>>>, } -static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = SyncOnceCell::new(); +static STDOUT: OnceLock<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = 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<ReentrantMutex<RefCell<StderrRaw>>> = SyncOnceCell::new(); + static INSTANCE: OnceLock<ReentrantMutex<RefCell<StderrRaw>>> = 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 d7450962359..f8c06c3f9ae 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<String> = 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<T> { - once: Once, - // Whether or not the value is initialized is tracked by `state_and_queue`. - value: UnsafeCell<MaybeUninit<T>>, - /// `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<T>, -} - -// 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<T: Sync + Send> Sync for SyncOnceCell<T> {} -#[unstable(feature = "once_cell", issue = "74465")] -unsafe impl<T: Send> Send for SyncOnceCell<T> {} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} - -#[unstable(feature = "once_cell", issue = "74465")] -#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] -impl<T> const Default for SyncOnceCell<T> { - /// Creates a new empty cell. - /// - /// # Example - /// - /// ``` - /// #![feature(once_cell)] - /// - /// use std::lazy::SyncOnceCell; - /// - /// fn main() { - /// assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default()); - /// } - /// ``` - fn default() -> SyncOnceCell<T> { - SyncOnceCell::new() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> { - 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<T: Clone> Clone for SyncOnceCell<T> { - fn clone(&self) -> SyncOnceCell<T> { - 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<T> From<T> for SyncOnceCell<T> { - /// 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<T: PartialEq> PartialEq for SyncOnceCell<T> { - fn eq(&self, other: &SyncOnceCell<T>) -> bool { - self.get() == other.get() - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Eq> Eq for SyncOnceCell<T> {} - -impl<T> SyncOnceCell<T> { - /// Creates a new empty cell. - #[unstable(feature = "once_cell", issue = "74465")] - #[must_use] - pub const fn new() -> SyncOnceCell<T> { - 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<i32> = 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<F>(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - match self.get_or_try_init(|| Ok::<T, !>(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<i32, ()> { - /// 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<F, E>(&self, f: F) -> Result<&T, E> - where - F: FnOnce() -> Result<T, E>, - { - // 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<F, G>(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<String> = 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<T> { - 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<String> = 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<T> { - 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<F, E>(&self, f: F) -> Result<(), E> - where - F: FnOnce() -> Result<T, E>, - { - 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<T> { - 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<HashMap<i32, String>> = 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, F = fn() -> T> { - cell: SyncOnceCell<T>, - init: Cell<Option<F>>, -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> { - 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<T, F>` so it is fine -// to not impl `Sync` for `F` -// we do create a `&mut Option<F>` 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<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {} -// auto-derived `Send` impl is OK. - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T, F: UnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {} -#[unstable(feature = "once_cell", issue = "74465")] -impl<T, F: UnwindSafe> UnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: UnwindSafe {} - -impl<T, F> SyncLazy<T, F> { - /// Creates a new lazy value with the given initializing - /// function. - #[unstable(feature = "once_cell", issue = "74465")] - pub const fn new(f: F) -> SyncLazy<T, F> { - SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) } - } -} - -impl<T, F: FnOnce() -> T> SyncLazy<T, F> { - /// 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, F>) -> &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, F: FnOnce() -> T> Deref for SyncLazy<T, F> { - type Target = T; - fn deref(&self) -> &T { - SyncLazy::force(self) - } -} - -#[unstable(feature = "once_cell", issue = "74465")] -impl<T: Default> Default for SyncLazy<T> { - /// Creates a new lazy value using `Default` as the initializing function. - fn default() -> SyncLazy<T> { - SyncLazy::new(T::default) - } -} diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 7ff2f330f8a..eb1e7135a6e 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -122,8 +122,10 @@ impl Condvar { /// let condvar = Condvar::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] #[must_use] - pub fn new() -> Condvar { + #[inline] + pub const fn new() -> Condvar { Condvar { inner: sys::Condvar::new() } } diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs new file mode 100644 index 00000000000..535cc1c42fc --- /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<HashMap<i32, String>> = 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, F = fn() -> T> { + cell: OnceLock<T>, + init: Cell<Option<F>>, +} + +impl<T, F> LazyLock<T, F> { + /// Creates a new lazy value with the given initializing + /// function. + #[unstable(feature = "once_cell", issue = "74465")] + pub const fn new(f: F) -> LazyLock<T, F> { + LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) } + } +} + +impl<T, F: FnOnce() -> T> LazyLock<T, F> { + /// 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, F>) -> &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, F: FnOnce() -> T> Deref for LazyLock<T, F> { + type Target = T; + fn deref(&self) -> &T { + LazyLock::force(self) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Default> Default for LazyLock<T> { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> LazyLock<T> { + LazyLock::new(T::default) + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> { + 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<T, F>` so it is fine +// to not impl `Sync` for `F` +// we do create a `&mut Option<F>` 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<T, F: Send> Sync for LazyLock<T, F> where OnceLock<T>: Sync {} +// auto-derived `Send` impl is OK. + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> where OnceLock<T>: RefUnwindSafe {} +#[unstable(feature = "once_cell", issue = "74465")] +impl<T, F: UnwindSafe> UnwindSafe for LazyLock<T, F> where OnceLock<T>: 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 00000000000..f11b66bfca5 --- /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<R: Send + 'static>(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<Mutex<Foo>> = <_>::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<String> = 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<i32> = 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<Mutex<Foo>> = <_>::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<Vec<i32>> = 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<i32> { + static XS: OnceLock<Vec<i32>> = 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<String> = 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<T: Send + Sync>() {} + assert_traits::<LazyLock<String>>(); +} diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 87d01daeafc..5fc18fda6a8 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/mutex.rs b/library/std/src/sync/mutex.rs index 31342a89054..e0d13cd648c 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -213,7 +213,9 @@ impl<T> Mutex<T> { /// let mutex = Mutex::new(0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(t: T) -> Mutex<T> { + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[inline] + pub const fn new(t: T) -> Mutex<T> { Mutex { inner: sys::MovableMutex::new(), poison: poison::Flag::new(), diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs new file mode 100644 index 00000000000..813516040cd --- /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<String> = 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<T> { + once: Once, + // Whether or not the value is initialized is tracked by `state_and_queue`. + value: UnsafeCell<MaybeUninit<T>>, + /// `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<T>, +} + +impl<T> OnceLock<T> { + /// Creates a new empty cell. + #[unstable(feature = "once_cell", issue = "74465")] + #[must_use] + pub const fn new() -> OnceLock<T> { + 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<i32> = 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<F>(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + match self.get_or_try_init(|| Ok::<T, !>(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<i32, ()> { + /// 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<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + // 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<F, G>(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<String> = 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<T> { + 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<String> = 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<T> { + 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<F, E>(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result<T, E>, + { + 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<T: Sync + Send> Sync for OnceLock<T> {} +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl<T: Send> Send for OnceLock<T> {} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {} +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {} + +#[unstable(feature = "once_cell", issue = "74465")] +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for OnceLock<T> { + /// Creates a new empty cell. + /// + /// # Example + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::sync::OnceLock; + /// + /// fn main() { + /// assert_eq!(OnceLock::<()>::new(), OnceLock::default()); + /// } + /// ``` + fn default() -> OnceLock<T> { + OnceLock::new() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: fmt::Debug> fmt::Debug for OnceLock<T> { + 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<T: Clone> Clone for OnceLock<T> { + fn clone(&self) -> OnceLock<T> { + 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<T> From<T> for OnceLock<T> { + /// 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<T: PartialEq> PartialEq for OnceLock<T> { + fn eq(&self, other: &OnceLock<T>) -> bool { + self.get() == other.get() + } +} + +#[unstable(feature = "once_cell", issue = "74465")] +impl<T: Eq> Eq for OnceLock<T> {} + +#[unstable(feature = "once_cell", issue = "74465")] +unsafe impl<#[may_dangle] T> Drop for OnceLock<T> { + 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 index 83466eb0904..46695225b9f 100644 --- a/library/std/src/lazy/tests.rs +++ b/library/std/src/sync/once_lock/tests.rs @@ -1,48 +1,13 @@ use crate::{ - lazy::{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: Lazy<Mutex<Foo>> = <_>::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: Lazy<String> = Lazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } -} - fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R { thread::spawn(f).join().unwrap() } @@ -50,7 +15,7 @@ fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn sync_once_cell() { - static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new(); + static ONCE_CELL: OnceLock<i32> = OnceLock::new(); assert!(ONCE_CELL.get().is_none()); @@ -65,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; @@ -74,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); @@ -92,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); @@ -104,13 +69,13 @@ fn sync_once_cell_drop() { #[test] fn sync_once_cell_drop_empty() { - let x = SyncOnceCell::<String>::new(); + let x = OnceLock::<String>::new(); drop(x); } #[test] fn clone() { - let s = SyncOnceCell::new(); + let s = OnceLock::new(); let c = s.clone(); assert!(c.get().is_none()); @@ -121,7 +86,7 @@ fn clone() { #[test] fn get_or_try_init() { - let cell: SyncOnceCell<String> = SyncOnceCell::new(); + let cell: OnceLock<String> = OnceLock::new(); assert!(cell.get().is_none()); let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); @@ -137,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::<String>::new() == SyncOnceCell::new()); - assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned())); + assert!(OnceLock::<String>::new() == OnceLock::new()); + assert!(OnceLock::<String>::new() != OnceLock::from("value".to_owned())); } #[test] fn into_inner() { - let cell: SyncOnceCell<String> = SyncOnceCell::new(); + let cell: OnceLock<String> = 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<i32> = 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<Mutex<Foo>> = <_>::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<Vec<i32>> = 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<i32> { - static XS: SyncOnceCell<Vec<i32>> = 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<String> = 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<T: Send + Sync>() {} - assert_traits::<SyncOnceCell<String>>(); - assert_traits::<SyncLazy<String>>(); + assert_traits::<OnceLock<String>>(); } #[test] @@ -261,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)* } @@ -285,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<String> = SyncOnceCell::new(); + static ONCE_CELL: OnceLock<String> = OnceLock::new(); let n_readers = 10; let n_writers = 3; @@ -320,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/sync/poison.rs b/library/std/src/sync/poison.rs index 9c918be3387..741312d5537 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -19,6 +19,7 @@ pub struct Flag { // all cases. impl Flag { + #[inline] pub const fn new() -> Flag { Flag { failed: AtomicBool::new(false) } } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 9517e7e1f03..1192c08cb1a 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -146,7 +146,9 @@ impl<T> RwLock<T> { /// let lock = RwLock::new(5); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(t: T) -> RwLock<T> { + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[inline] + pub const fn new(t: T) -> RwLock<T> { RwLock { inner: sys::MovableRwLock::new(), poison: poison::Flag::new(), diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs index 2ba8454ff92..715e94c3b3d 100644 --- a/library/std/src/sys/itron/mutex.rs +++ b/library/std/src/sys/itron/mutex.rs @@ -26,6 +26,7 @@ fn new_mtx() -> Result<abi::ID, ItronError> { } impl Mutex { + #[inline] pub const fn new() -> Mutex { Mutex { mtx: SpinIdOnceCell::new() } } diff --git a/library/std/src/sys/solid/rwlock.rs b/library/std/src/sys/solid/rwlock.rs index 433abc895f5..0a770cf03f2 100644 --- a/library/std/src/sys/solid/rwlock.rs +++ b/library/std/src/sys/solid/rwlock.rs @@ -23,6 +23,7 @@ fn new_rwl() -> Result<abi::ID, ItronError> { } impl RwLock { + #[inline] pub const fn new() -> RwLock { RwLock { rwl: SpinIdOnceCell::new() } } diff --git a/library/std/src/sys/unsupported/locks/condvar.rs b/library/std/src/sys/unsupported/locks/condvar.rs index f27bf2b26bd..e703fd0d269 100644 --- a/library/std/src/sys/unsupported/locks/condvar.rs +++ b/library/std/src/sys/unsupported/locks/condvar.rs @@ -6,6 +6,7 @@ pub struct Condvar {} pub type MovableCondvar = Condvar; impl Condvar { + #[inline] pub const fn new() -> Condvar { Condvar {} } diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index 56bad71b189..d7cb12e0cf9 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -11,6 +11,7 @@ unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { + #[inline] pub const fn new() -> Mutex { Mutex { locked: Cell::new(false) } } diff --git a/library/std/src/sys/unsupported/locks/rwlock.rs b/library/std/src/sys/unsupported/locks/rwlock.rs index bf6e2d3d080..aca5fb7152c 100644 --- a/library/std/src/sys/unsupported/locks/rwlock.rs +++ b/library/std/src/sys/unsupported/locks/rwlock.rs @@ -11,6 +11,7 @@ unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} // no threads on this platform impl RwLock { + #[inline] pub const fn new() -> RwLock { RwLock { mode: Cell::new(0) } } diff --git a/library/std/src/sys/windows/locks/condvar.rs b/library/std/src/sys/windows/locks/condvar.rs index 59e2c1be0f0..be9a2abbe35 100644 --- a/library/std/src/sys/windows/locks/condvar.rs +++ b/library/std/src/sys/windows/locks/condvar.rs @@ -14,6 +14,7 @@ unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} impl Condvar { + #[inline] pub const fn new() -> Condvar { Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs index 08f55844a0e..f91e8f9f59a 100644 --- a/library/std/src/sys/windows/locks/mutex.rs +++ b/library/std/src/sys/windows/locks/mutex.rs @@ -33,6 +33,7 @@ pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { } impl Mutex { + #[inline] pub const fn new() -> Mutex { Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) } } diff --git a/library/std/src/sys/windows/locks/rwlock.rs b/library/std/src/sys/windows/locks/rwlock.rs index a32df85e2f6..fa5ffe5749f 100644 --- a/library/std/src/sys/windows/locks/rwlock.rs +++ b/library/std/src/sys/windows/locks/rwlock.rs @@ -11,6 +11,7 @@ unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} impl RwLock { + #[inline] pub const fn new() -> RwLock { RwLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 5de12313784..d1e72cd5443 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<unsafe extern "system" fn() -> i32> = SyncOnceCell::new(); +static WSA_CLEANUP: OnceLock<unsafe extern "system" fn() -> 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 22e024d8552..57248e3651b 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<HashMapRng> = lazy::SyncOnceCell::new(); + static VALUE: sync::OnceLock<HashMapRng> = sync::OnceLock::new(); *VALUE.get_or_init(choose_hashmap_rng) } diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index 1def0518e0a..f3ac1061b89 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -14,7 +14,8 @@ pub struct Condvar { impl Condvar { /// Creates a new condition variable for use. - pub fn new() -> Self { + #[inline] + pub const fn new() -> Self { Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() } } diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index 36ea888d8de..81eefa1133f 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -15,6 +15,7 @@ unsafe impl Sync for StaticMutex {} impl StaticMutex { /// Creates a new mutex for use. + #[inline] pub const fn new() -> Self { Self(imp::Mutex::new()) } @@ -60,7 +61,8 @@ unsafe impl Sync for MovableMutex {} impl MovableMutex { /// Creates a new mutex. - pub fn new() -> Self { + #[inline] + pub const fn new() -> Self { Self(imp::MovableMutex::new()) } diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index abc9fd561f1..265cebfdc3e 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -10,6 +10,7 @@ pub struct StaticRwLock(imp::RwLock); impl StaticRwLock { /// Creates a new rwlock for use. + #[inline] pub const fn new() -> Self { Self(imp::RwLock::new()) } @@ -73,7 +74,8 @@ pub struct MovableRwLock(imp::MovableRwLock); impl MovableRwLock { /// Creates a new reader-writer lock for use. - pub fn new() -> Self { + #[inline] + pub const fn new() -> Self { Self(imp::MovableRwLock::new()) } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index b7abf6cc78d..905fa431d29 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -692,6 +692,7 @@ macro_rules! tool_extended { stable = $stable:expr, $(in_tree = $in_tree:expr,)? $(submodule = $submodule:literal,)? + $(tool_std = $tool_std:literal,)? $extra_deps:block;)+) => { $( #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -740,7 +741,7 @@ macro_rules! tool_extended { compiler: $sel.compiler, target: $sel.target, tool: $tool_name, - mode: Mode::ToolRustc, + mode: if false $(|| $tool_std)? { Mode::ToolStd } else { Mode::ToolRustc }, path: $path, extra_features: $sel.extra_features, is_optional_tool: true, @@ -774,7 +775,10 @@ tool_extended!((self, builder), }); self.extra_features.push("clippy".to_owned()); }; - RustDemangler, rust_demangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, {}; + // FIXME: tool_std is not quite right, we shouldn't allow nightly features. + // But `builder.cargo` doesn't know how to handle ToolBootstrap in stages other than 0, + // and this is close enough for now. + RustDemangler, rust_demangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {}; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {}; RustAnalyzer, rust_analyzer, "src/tools/rust-analyzer/crates/rust-analyzer", "rust-analyzer", stable=false, submodule="rust-analyzer", {}; ); diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index a045666ca8a..6f9980dbc86 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -52,9 +52,9 @@ ENV \ CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ CXX_x86_64_fortanix_unknown_sgx=clang++-11 \ CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ - AR_i686_unknown_freebsd=i686-unknown-freebsd11-ar \ - CC_i686_unknown_freebsd=i686-unknown-freebsd11-clang \ - CXX_i686_unknown_freebsd=i686-unknown-freebsd11-clang++ \ + AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ + CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ + CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ CC=gcc-8 \ CXX=g++-8 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index 121dd3f455a..f9b1fa8951a 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -27,9 +27,9 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd11-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd11-clang \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd11-clang++ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++ ENV HOSTS=x86_64-unknown-freebsd diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 2f7c57bcdc4..4a4cac1b723 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -5,8 +5,8 @@ set -eux arch=$1 binutils_version=2.25.1 -freebsd_version=11.4 -triple=$arch-unknown-freebsd11 +freebsd_version=12.3 +triple=$arch-unknown-freebsd12 sysroot=/usr/local/$triple hide_output() { @@ -59,7 +59,7 @@ done # Originally downloaded from: # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://ci-mirrors.rust-lang.org/rustc/2020-08-09-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Clang can do cross-builds out of the box, if we give it the right @@ -68,7 +68,7 @@ curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # there might be other problems.) # # The --target option is last because the cross-build of LLVM uses -# --target without an OS version ("-freebsd" vs. "-freebsd11"). This +# --target without an OS version ("-freebsd" vs. "-freebsd12"). This # makes Clang default to libstdc++ (which no longer exists), and also # controls other features, like GNU-style symbol table hashing and # anything predicated on the version number in the __FreeBSD__ diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 83ab9acd300..2762d5e8502 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 53281bfde2e..51b245e36ba 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<FxHashSet<LocalDefId>> = - SyncLazy::new(FxHashSet::default); + static EMPTY_SET: LazyLock<FxHashSet<LocalDefId>> = + 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 8f08ff2ece3..9bddee199c7 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/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index fc8b5678080..2817a8fe144 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -89,5 +89,7 @@ module.exports = { "no-multi-assign": "error", "no-return-assign": "error", "no-script-url": "error", + "no-sequences": "error", + "no-throw-literal": "error", } }; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index c726aeeff47..c0b274c0a3f 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1333,10 +1333,7 @@ function initSearch(rawSearchIndex) { if (searchWord.indexOf(elem.pathLast) > -1 || row.normalizedName.indexOf(elem.pathLast) > -1 ) { - // filter type: ... queries - if (!results_others[fullId] !== undefined) { - index = row.normalizedName.indexOf(elem.pathLast); - } + index = row.normalizedName.indexOf(elem.pathLast); } lev = levenshtein(searchWord, elem.pathLast); if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 08a1a868521..240aec52cff 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 e9e810658ef..392e26ea6ac 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<Regex> = SyncLazy::new(|| { +static URL_REGEX: LazyLock<Regex> = 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 d899411a49e..26bc29216cf 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<ThreadId> = SyncOnceCell::new(); +static THREAD_ID: OnceLock<ThreadId> = OnceLock::new(); #[test] fn spawn_thread_would_block() { diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 4d92f07f34ba7fb7d7f207564942508f46c225d +Subproject 8d42b0e8794ce3787c9f7d6d88b02ae80ebe8d1 diff --git a/src/tools/clippy/clippy_dev/src/bless.rs b/src/tools/clippy/clippy_dev/src/bless.rs index 8e5c739afe0..f5c51b9474f 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<Option<std::time::SystemTime>> = - SyncLazy::new(|| cargo_clippy_path().metadata().ok()?.modified().ok()); +static CLIPPY_BUILD_TIME: LazyLock<Option<std::time::SystemTime>> = + 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 73c1bdd0e3f..5106c39b5c6 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -64,7 +64,7 @@ pub use self::hir_utils::{ 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; @@ -2080,7 +2080,7 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { false } -static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new(); +static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = 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 7de40fe63ac..67467f89b47 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<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = SyncLazy::new(|| { +static ICE_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + 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<String>, toolchain: Option<String>) -> Option<Pat #[allow(clippy::too_many_lines)] pub fn main() { rustc_driver::init_rustc_env_logger(); - SyncLazy::force(&ICE_HOOK); + LazyLock::force(&ICE_HOOK); exit(rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec<String> = env::args().collect(); diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 04c2eeff08b..061cda7e01e 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<String> = SyncLazy::new(|| { +static EXTERN_FLAGS: LazyLock<String> = 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 8a4de3f6def..ea8c54e08b3 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<PathBuf> = SyncLazy::new(|| { +pub static CARGO_CLIPPY_PATH: LazyLock<PathBuf> = LazyLock::new(|| { let mut path = std::env::current_exe().unwrap(); assert!(path.pop()); // deps path.set_file_name("cargo-clippy"); diff --git a/src/tools/miri b/src/tools/miri -Subproject 4c1f50bf2bef7b25613a4c42322de87ffcf8c92 +Subproject c4dd3f4ef98f8527aa652e8154ff044ca3e8845 diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 992a2e83f63..40aa0e8f715 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -73,7 +73,7 @@ features = [ [dependencies] bstr = { version = "0.2.13", features = ["default"] } byteorder = { version = "1", features = ['default', 'std'] } -clap = { version = "3.1.1", features = ["lazy_static", "derive", "clap_derive"]} +clap = { version = "3.1.1", features = ["derive", "clap_derive"]} curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } crossbeam-utils = { version = "0.8.0", features = ["nightly"] } libc = { version = "0.2.79", features = ["align"] } |
