about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs2
-rw-r--r--compiler/rustc_data_structures/src/jobserver.rs4
-rw-r--r--compiler/rustc_data_structures/src/sync.rs2
-rw-r--r--compiler/rustc_driver/src/lib.rs8
-rw-r--r--compiler/rustc_error_messages/src/lib.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs6
-rw-r--r--compiler/rustc_hir/src/lang_items.rs4
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs4
-rw-r--r--compiler/rustc_interface/src/passes.rs6
-rw-r--r--compiler/rustc_interface/src/util.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs4
-rw-r--r--library/std/src/io/stdio.rs9
-rw-r--r--library/std/src/lazy.rs616
-rw-r--r--library/std/src/sync/lazy_lock.rs121
-rw-r--r--library/std/src/sync/lazy_lock/tests.rs143
-rw-r--r--library/std/src/sync/mod.rs7
-rw-r--r--library/std/src/sync/once_lock.rs496
-rw-r--r--library/std/src/sync/once_lock/tests.rs (renamed from library/std/src/lazy/tests.rs)166
-rw-r--r--library/std/src/sys/windows/net.rs4
-rw-r--r--library/std/src/sys/windows/rand.rs4
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/core.rs6
-rw-r--r--src/librustdoc/html/render/write_shared.rs2
-rw-r--r--src/librustdoc/lint.rs2
-rw-r--r--src/librustdoc/passes/bare_urls.rs4
-rw-r--r--src/test/run-make/libtest-thread-limit/test.rs8
-rw-r--r--src/tools/clippy/clippy_dev/src/bless.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/clippy/src/driver.rs6
-rw-r--r--src/tools/clippy/tests/compile-test.rs4
-rw-r--r--src/tools/clippy/tests/test_utils/mod.rs4
32 files changed, 847 insertions, 819 deletions
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_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 ec3d3d49bcb..feb82cb0938 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -258,7 +258,7 @@ cfg_if! {
         pub use parking_lot::MutexGuard as LockGuard;
         pub use parking_lot::MappedMutexGuard as MappedLockGuard;
 
-        pub use std::lazy::SyncOnceCell as OnceCell;
+        pub use std::sync::OnceLock as OnceCell;
 
         pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
 
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 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 145fbd43ab1..fefcaa898c1 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -20,7 +20,7 @@ use tracing::{instrument, trace};
 #[cfg(not(parallel_compiler))]
 use std::cell::LazyCell as Lazy;
 #[cfg(parallel_compiler)]
-use std::lazy::SyncLazy as Lazy;
+use std::sync::LazyLock as Lazy;
 
 #[cfg(parallel_compiler)]
 use intl_memoizer::concurrent::IntlLangMemoizer;
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 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 389e6483f30..21ccb586e8f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -43,11 +43,11 @@ use std::any::Any;
 use std::cell::RefCell;
 use std::ffi::OsString;
 use std::io::{self, BufWriter, Write};
-use std::lazy::SyncLazy;
 use std::marker::PhantomPinned;
 use std::path::{Path, PathBuf};
 use std::pin::Pin;
 use std::rc::Rc;
+use std::sync::LazyLock;
 use std::{env, fs, iter};
 
 pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
@@ -759,7 +759,7 @@ pub fn prepare_outputs(
     Ok(outputs)
 }
 
-pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<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);
@@ -784,7 +784,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/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/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/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 66d6236c111..46695225b9f 100644
--- a/library/std/src/lazy/tests.rs
+++ b/library/std/src/sync/once_lock/tests.rs
@@ -1,49 +1,13 @@
 use crate::{
-    cell::LazyCell,
-    lazy::{SyncLazy, SyncOnceCell},
     panic,
+    sync::OnceLock,
     sync::{
         atomic::{AtomicUsize, Ordering::SeqCst},
         mpsc::channel,
-        Mutex,
     },
     thread,
 };
 
-#[test]
-fn lazy_default() {
-    static CALLED: AtomicUsize = AtomicUsize::new(0);
-
-    struct Foo(u8);
-    impl Default for Foo {
-        fn default() -> Self {
-            CALLED.fetch_add(1, SeqCst);
-            Foo(42)
-        }
-    }
-
-    let lazy: LazyCell<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());
-    }
-}
-
 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
     thread::spawn(f).join().unwrap()
 }
@@ -51,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());
 
@@ -66,7 +30,7 @@ fn sync_once_cell() {
 
 #[test]
 fn sync_once_cell_get_mut() {
-    let mut c = SyncOnceCell::new();
+    let mut c = OnceLock::new();
     assert!(c.get_mut().is_none());
     c.set(90).unwrap();
     *c.get_mut().unwrap() += 2;
@@ -75,7 +39,7 @@ fn sync_once_cell_get_mut() {
 
 #[test]
 fn sync_once_cell_get_unchecked() {
-    let c = SyncOnceCell::new();
+    let c = OnceLock::new();
     c.set(92).unwrap();
     unsafe {
         assert_eq!(c.get_unchecked(), &92);
@@ -93,7 +57,7 @@ fn sync_once_cell_drop() {
         }
     }
 
-    let x = SyncOnceCell::new();
+    let x = OnceLock::new();
     spawn_and_wait(move || {
         x.get_or_init(|| Dropper);
         assert_eq!(DROP_CNT.load(SeqCst), 0);
@@ -105,13 +69,13 @@ fn sync_once_cell_drop() {
 
 #[test]
 fn sync_once_cell_drop_empty() {
-    let x = SyncOnceCell::<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());
 
@@ -122,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!() }));
@@ -138,122 +102,32 @@ fn get_or_try_init() {
 
 #[test]
 fn from_impl() {
-    assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
-    assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
+    assert_eq!(OnceLock::from("value").get(), Some(&"value"));
+    assert_ne!(OnceLock::from("foo").get(), Some(&"bar"));
 }
 
 #[test]
 fn partialeq_impl() {
-    assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
-    assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
+    assert!(OnceLock::from("value") == OnceLock::from("value"));
+    assert!(OnceLock::from("foo") != OnceLock::from("bar"));
 
-    assert!(SyncOnceCell::<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]
@@ -262,7 +136,7 @@ fn eval_once_macro() {
         (|| -> $ty:ty {
             $($body:tt)*
         }) => {{
-            static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
+            static ONCE_CELL: OnceLock<$ty> = OnceLock::new();
             fn init() -> $ty {
                 $($body)*
             }
@@ -286,7 +160,7 @@ fn eval_once_macro() {
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)]
 fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
-    static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
+    static ONCE_CELL: OnceLock<String> = OnceLock::new();
 
     let n_readers = 10;
     let n_writers = 3;
@@ -321,7 +195,7 @@ fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
 
 #[test]
 fn dropck() {
-    let cell = SyncOnceCell::new();
+    let cell = OnceLock::new();
     {
         let s = String::new();
         cell.set(&s).unwrap();
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 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/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 4605793d0df..6a6c78a26dc 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/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/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 0cf23ca626c..052d9756c51 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -62,7 +62,7 @@ pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, Spanl
 
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
-use std::lazy::SyncOnceCell;
+use std::sync::OnceLock;
 use std::sync::{Mutex, MutexGuard};
 
 use if_chain::if_chain;
@@ -2078,7 +2078,7 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
     false
 }
 
-static TEST_ITEM_NAMES_CACHE: SyncOnceCell<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");