diff --git a/library/Cargo.lock b/library/Cargo.lock index a9a611fe1ed56..09228825086ee 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -169,9 +169,9 @@ dependencies = [ [[package]] name = "object" -version = "0.37.1" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" +checksum = "b3e3d0a7419f081f4a808147e845310313a39f322d7ae1f996b7f001d6cbed04" dependencies = [ "memchr", "rustc-std-workspace-alloc", @@ -183,9 +183,8 @@ name = "panic_abort" version = "0.0.0" dependencies = [ "alloc", - "compiler_builtins", - "core", "libc", + "rustc-std-workspace-core", ] [[package]] @@ -194,9 +193,8 @@ version = "0.0.0" dependencies = [ "alloc", "cfg-if", - "compiler_builtins", - "core", "libc", + "rustc-std-workspace-core", "unwind", ] @@ -261,9 +259,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" dependencies = [ "rustc-std-workspace-core", ] @@ -313,7 +311,6 @@ dependencies = [ "addr2line", "alloc", "cfg-if", - "compiler_builtins", "core", "dlmalloc", "fortanix-sgx-abi", @@ -380,19 +377,17 @@ name = "unwind" version = "0.0.0" dependencies = [ "cfg-if", - "compiler_builtins", - "core", "libc", + "rustc-std-workspace-core", "unwinding", ] [[package]] name = "unwinding" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751" +checksum = "60612c845ef41699f39dc8c5391f252942c0a88b7d15da672eff0d14101bbd6d" dependencies = [ - "compiler_builtins", "gimli", "rustc-std-workspace-core", ] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d58240f3051e0..9eacbf00e4233 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -265,12 +265,12 @@ use crate::vec::{self, Vec}; /// You can look at these with the [`as_ptr`], [`len`], and [`capacity`] /// methods: /// +// FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// use std::mem; /// /// let story = String::from("Once upon a time..."); /// -// FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent automatically dropping the String's data /// let mut story = mem::ManuallyDrop::new(story); /// @@ -970,13 +970,13 @@ impl String { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// use std::mem; /// /// unsafe { /// let s = String::from("hello"); /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent automatically dropping the String's data /// let mut s = mem::ManuallyDrop::new(s); /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 65db56710b51b..fe672d14683df 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -566,13 +566,13 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// use std::ptr; /// use std::mem; /// /// let v = vec![1, 2, 3]; /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -674,6 +674,7 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// #![feature(box_vec_non_null)] /// @@ -682,7 +683,6 @@ impl Vec { /// /// let v = vec![1, 2, 3]; /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -994,6 +994,7 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// #![feature(allocator_api)] /// @@ -1007,7 +1008,6 @@ impl Vec { /// v.push(2); /// v.push(3); /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -1114,6 +1114,7 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// #![feature(allocator_api, box_vec_non_null)] /// @@ -1127,7 +1128,6 @@ impl Vec { /// v.push(2); /// v.push(3); /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -3872,8 +3872,8 @@ impl Vec { /// while i < vec.len() - end_items { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); - /// # extracted.push(val); /// // your code here + /// # extracted.push(val); /// } else { /// i += 1; /// } diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index bb668d2a67309..1ad2cca64a347 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -22,18 +22,16 @@ where { #[inline] fn eq(&self, other: &[U]) -> bool { - let b: Result<&[U; N], _> = other.try_into(); - match b { - Ok(b) => *self == *b, - Err(_) => false, + match other.as_array::() { + Some(b) => *self == *b, + None => false, } } #[inline] fn ne(&self, other: &[U]) -> bool { - let b: Result<&[U; N], _> = other.try_into(); - match b { - Ok(b) => *self != *b, - Err(_) => true, + match other.as_array::() { + Some(b) => *self != *b, + None => true, } } } @@ -45,18 +43,16 @@ where { #[inline] fn eq(&self, other: &[U; N]) -> bool { - let b: Result<&[T; N], _> = self.try_into(); - match b { - Ok(b) => *b == *other, - Err(_) => false, + match self.as_array::() { + Some(b) => *b == *other, + None => false, } } #[inline] fn ne(&self, other: &[U; N]) -> bool { - let b: Result<&[T; N], _> = self.try_into(); - match b { - Ok(b) => *b != *other, - Err(_) => true, + match self.as_array::() { + Some(b) => *b != *other, + None => true, } } } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d6d1bf2effae2..d67408cae1b95 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2068,9 +2068,9 @@ impl fmt::Display for RefMut<'_, T> { /// implies exclusive access to its `T`: /// /// ```rust -/// #![forbid(unsafe_code)] // with exclusive accesses, -/// // `UnsafeCell` is a transparent no-op wrapper, -/// // so no need for `unsafe` here. +/// #![forbid(unsafe_code)] +/// // with exclusive accesses, `UnsafeCell` is a transparent no-op wrapper, so no need for +/// // `unsafe` here. /// use std::cell::UnsafeCell; /// /// let mut x: UnsafeCell = 42.into(); diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 1758e84ad7cdf..a1bd4c8571706 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -15,6 +15,22 @@ enum State { /// /// [`std::sync::LazyLock`]: ../../std/sync/struct.LazyLock.html /// +/// # Poisoning +/// +/// If the initialization closure passed to [`LazyCell::new`] panics, the cell will be poisoned. +/// Once the cell is poisoned, any threads that attempt to access this cell (via a dereference +/// or via an explicit call to [`force()`]) will panic. +/// +/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key +/// difference, however, is that poisoning in `LazyCell` is _unrecoverable_. All future accesses of +/// the cell from other threads will panic, whereas a type in [`std::sync::poison`] like +/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`]. +/// +/// [`force()`]: LazyCell::force +/// [`std::sync::poison`]: ../../std/sync/poison/index.html +/// [`std::sync::poison::Mutex`]: ../../std/sync/poison/struct.Mutex.html +/// [`PoisonError::into_inner()`]: ../../std/sync/poison/struct.PoisonError.html#method.into_inner +/// /// # Examples /// /// ``` @@ -64,6 +80,10 @@ impl T> LazyCell { /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. /// + /// # Panics + /// + /// Panics if the cell is poisoned. + /// /// # Examples /// /// ``` @@ -93,6 +113,15 @@ impl T> LazyCell { /// /// This is equivalent to the `Deref` impl, but is explicit. /// + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future + /// accesses of the cell (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyCell::new + /// [`force()`]: LazyCell::force + /// /// # Examples /// /// ``` @@ -123,6 +152,15 @@ impl T> LazyCell { /// Forces the evaluation of this lazy value and returns a mutable reference to /// the result. /// + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future + /// accesses of the cell (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyCell::new + /// [`force()`]: LazyCell::force + /// /// # Examples /// /// ``` @@ -219,7 +257,8 @@ impl T> LazyCell { } impl LazyCell { - /// Returns a mutable reference to the value if initialized, or `None` if not. + /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or + /// poisoned), returns `None`. /// /// # Examples /// @@ -245,7 +284,8 @@ impl LazyCell { } } - /// Returns a reference to the value if initialized, or `None` if not. + /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned), + /// returns `None`. /// /// # Examples /// @@ -278,6 +318,15 @@ impl LazyCell { #[stable(feature = "lazy_cell", since = "1.80.0")] impl T> Deref for LazyCell { type Target = T; + + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future + /// accesses of the cell (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyCell::new + /// [`force()`]: LazyCell::force #[inline] fn deref(&self) -> &T { LazyCell::force(self) @@ -286,6 +335,14 @@ impl T> Deref for LazyCell { #[stable(feature = "lazy_deref_mut", since = "1.89.0")] impl T> DerefMut for LazyCell { + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the cell becomes poisoned. This will cause all future + /// accesses of the cell (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyCell::new + /// [`force()`]: LazyCell::force #[inline] fn deref_mut(&mut self) -> &mut T { LazyCell::force_mut(self) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 696d323c66d2e..c72eeb9a9c976 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -649,8 +649,6 @@ pub const fn must_use(value: T) -> T { /// } /// } /// ``` -/// -/// #[unstable(feature = "likely_unlikely", issue = "136873")] #[inline(always)] pub const fn likely(b: bool) -> bool { diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 7ca41d224a0a6..56ca1305b601b 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -233,10 +233,12 @@ //! //! ``` //! let mut values = vec![41]; -//! for x in &mut values { // same as `values.iter_mut()` +//! for x in &mut values { +//! // ^ same as `values.iter_mut()` //! *x += 1; //! } -//! for x in &values { // same as `values.iter()` +//! for x in &values { +//! // ^ same as `values.iter()` //! assert_eq!(*x, 42); //! } //! assert_eq!(values.len(), 1); diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b86926e0daf14..c38579b1512fc 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -811,7 +811,7 @@ pub trait Iterator { /// might be preferable to keep a functional style with longer iterators: /// /// ``` - /// (0..5).flat_map(|x| x * 100 .. x * 110) + /// (0..5).flat_map(|x| (x * 100)..(x * 110)) /// .enumerate() /// .filter(|&(i, x)| (i + x) % 3 == 0) /// .for_each(|(i, x)| println!("{i}:{x}")); diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3d57da63683b2..c59290a757b67 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -271,7 +271,10 @@ pub macro cfg_select($($tt:tt)*) { /// // expression given. /// debug_assert!(true); /// -/// fn some_expensive_computation() -> bool { true } // a very simple function +/// fn some_expensive_computation() -> bool { +/// // Some expensive computation here +/// true +/// } /// debug_assert!(some_expensive_computation()); /// /// // assert with a custom message @@ -1547,7 +1550,10 @@ pub(crate) mod builtin { /// // expression given. /// assert!(true); /// - /// fn some_computation() -> bool { true } // a very simple function + /// fn some_computation() -> bool { + /// // Some expensive computation here + /// true + /// } /// /// assert!(some_computation()); /// diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 45277a1c82d3a..ba00ee17b6528 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -138,8 +138,7 @@ unsafe impl Send for &T {} /// impl Bar for Impl { } /// /// let x: &dyn Foo = &Impl; // OK -/// // let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot -/// // be made into an object +/// // let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot be made into an object /// ``` /// /// [trait object]: ../../book/ch17-02-trait-objects.html diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 34d8370da7ecb..c160360cfacf9 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -773,8 +773,7 @@ impl MaybeUninit { /// // Initialize the `MaybeUninit` using `Cell::set`: /// unsafe { /// b.assume_init_ref().set(true); - /// // ^^^^^^^^^^^^^^^ - /// // Reference to an uninitialized `Cell`: UB! + /// //^^^^^^^^^^^^^^^ Reference to an uninitialized `Cell`: UB! /// } /// ``` #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] @@ -864,9 +863,9 @@ impl MaybeUninit { /// { /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); /// reader.read_exact(unsafe { buffer.assume_init_mut() })?; - /// // ^^^^^^^^^^^^^^^^^^^^^^^^ - /// // (mutable) reference to uninitialized memory! - /// // This is undefined behavior. + /// // ^^^^^^^^^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. /// Ok(unsafe { buffer.assume_init() }) /// } /// ``` @@ -884,13 +883,13 @@ impl MaybeUninit { /// let foo: Foo = unsafe { /// let mut foo = MaybeUninit::::uninit(); /// ptr::write(&mut foo.assume_init_mut().a as *mut u32, 1337); - /// // ^^^^^^^^^^^^^^^^^^^^^ - /// // (mutable) reference to uninitialized memory! - /// // This is undefined behavior. + /// // ^^^^^^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. /// ptr::write(&mut foo.assume_init_mut().b as *mut u8, 42); - /// // ^^^^^^^^^^^^^^^^^^^^^ - /// // (mutable) reference to uninitialized memory! - /// // This is undefined behavior. + /// // ^^^^^^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. /// foo.assume_init() /// }; /// ``` diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs index b92561c9e356d..d57b1d433e51c 100644 --- a/library/core/src/num/niche_types.rs +++ b/library/core/src/num/niche_types.rs @@ -46,11 +46,11 @@ macro_rules! define_valid_range_type { /// primitive without checking whether its zero. /// /// # Safety - /// Immediate language UB if `val == 0`, as it violates the validity - /// invariant of this type. + /// Immediate language UB if `val` is not within the valid range for this + /// type, as it violates the validity invariant. #[inline] pub const unsafe fn new_unchecked(val: $int) -> Self { - // SAFETY: Caller promised that `val` is non-zero. + // SAFETY: Caller promised that `val` is within the valid range. unsafe { $name(val) } } diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 9a1ba7d1728cb..1c824e336bed7 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -271,6 +271,7 @@ mod prim_bool {} /// When the compiler sees a value of type `!` in a [coercion site], it implicitly inserts a /// coercion to allow the type checker to infer any type: /// +// FIXME: use `core::convert::absurd` here instead, once it's merged /// ```rust,ignore (illustrative-and-has-placeholders) /// // this /// let x: u8 = panic!(); @@ -281,7 +282,6 @@ mod prim_bool {} /// // where absurd is a function with the following signature /// // (it's sound, because `!` always marks unreachable code): /// fn absurd(_: !) -> T { ... } -// FIXME: use `core::convert::absurd` here instead, once it's merged /// ``` /// /// This can lead to compilation errors if the type cannot be inferred: diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 99bf323ec572c..bbbcf1eb89183 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,3 +1,5 @@ +#![allow(clippy::enum_clike_unportable_variant)] + use safety::{ensures, invariant, requires}; #[cfg(kani)] @@ -266,7 +268,7 @@ impl const Default for Alignment { #[cfg(target_pointer_width = "16")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u16)] +#[repr(usize)] #[cfg_attr(kani, derive(kani::Arbitrary))] enum AlignmentEnum { _Align1Shl0 = 1 << 0, @@ -289,7 +291,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "32")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u32)] +#[repr(usize)] #[cfg_attr(kani, derive(kani::Arbitrary))] enum AlignmentEnum { _Align1Shl0 = 1 << 0, @@ -328,7 +330,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "64")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u64)] +#[repr(usize)] #[cfg_attr(kani, derive(kani::Arbitrary))] enum AlignmentEnum { _Align1Shl0 = 1 << 0, diff --git a/library/core/src/result.rs b/library/core/src/result.rs index f65257ff59b92..474f86395ae0e 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -534,6 +534,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{self, FusedIterator, TrustedLen}; +use crate::marker::Destruct; use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::{convert, fmt, hint}; @@ -606,7 +607,13 @@ impl Result { #[must_use] #[inline] #[stable(feature = "is_some_and", since = "1.70.0")] - pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn is_ok_and(self, f: F) -> bool + where + F: ~const FnOnce(T) -> bool + ~const Destruct, + T: ~const Destruct, + E: ~const Destruct, + { match self { Err(_) => false, Ok(x) => f(x), @@ -655,7 +662,13 @@ impl Result { #[must_use] #[inline] #[stable(feature = "is_some_and", since = "1.70.0")] - pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn is_err_and(self, f: F) -> bool + where + F: ~const FnOnce(E) -> bool + ~const Destruct, + E: ~const Destruct, + T: ~const Destruct, + { match self { Ok(_) => false, Err(e) => f(e), @@ -682,8 +695,13 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] #[rustc_diagnostic_item = "result_ok_method"] - pub fn ok(self) -> Option { + pub const fn ok(self) -> Option + where + T: ~const Destruct, + E: ~const Destruct, + { match self { Ok(x) => Some(x), Err(_) => None, @@ -706,7 +724,12 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn err(self) -> Option { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn err(self) -> Option + where + T: ~const Destruct, + E: ~const Destruct, + { match self { Ok(_) => None, Err(x) => Some(x), @@ -796,7 +819,11 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map U>(self, op: F) -> Result { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn map(self, op: F) -> Result + where + F: ~const FnOnce(T) -> U + ~const Destruct, + { match self { Ok(t) => Ok(op(t)), Err(e) => Err(e), @@ -823,8 +850,15 @@ impl Result { /// ``` #[inline] #[stable(feature = "result_map_or", since = "1.41.0")] + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] #[must_use = "if you don't need the returned value, use `if let` instead"] - pub fn map_or U>(self, default: U, f: F) -> U { + pub const fn map_or(self, default: U, f: F) -> U + where + F: ~const FnOnce(T) -> U + ~const Destruct, + T: ~const Destruct, + E: ~const Destruct, + U: ~const Destruct, + { match self { Ok(t) => f(t), Err(_) => default, @@ -851,7 +885,12 @@ impl Result { /// ``` #[inline] #[stable(feature = "result_map_or_else", since = "1.41.0")] - pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn map_or_else(self, default: D, f: F) -> U + where + D: ~const FnOnce(E) -> U + ~const Destruct, + F: ~const FnOnce(T) -> U + ~const Destruct, + { match self { Ok(t) => f(t), Err(e) => default(e), @@ -877,10 +916,13 @@ impl Result { /// [default value]: Default::default #[inline] #[unstable(feature = "result_option_map_or_default", issue = "138099")] - pub fn map_or_default(self, f: F) -> U + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn map_or_default(self, f: F) -> U where - U: Default, - F: FnOnce(T) -> U, + F: ~const FnOnce(T) -> U + ~const Destruct, + U: ~const Default, + T: ~const Destruct, + E: ~const Destruct, { match self { Ok(t) => f(t), @@ -908,7 +950,11 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map_err F>(self, op: O) -> Result { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn map_err(self, op: O) -> Result + where + O: ~const FnOnce(E) -> F + ~const Destruct, + { match self { Ok(t) => Ok(t), Err(e) => Err(op(e)), @@ -930,7 +976,11 @@ impl Result { /// ``` #[inline] #[stable(feature = "result_option_inspect", since = "1.76.0")] - pub fn inspect(self, f: F) -> Self { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn inspect(self, f: F) -> Self + where + F: ~const FnOnce(&T) + ~const Destruct, + { if let Ok(ref t) = self { f(t); } @@ -954,7 +1004,11 @@ impl Result { /// ``` #[inline] #[stable(feature = "result_option_inspect", since = "1.76.0")] - pub fn inspect_err(self, f: F) -> Self { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn inspect_err(self, f: F) -> Self + where + F: ~const FnOnce(&E) + ~const Destruct, + { if let Err(ref e) = self { f(e); } @@ -1033,7 +1087,8 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter<'_, T> { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn iter(&self) -> Iter<'_, T> { Iter { inner: self.as_ref().ok() } } @@ -1056,7 +1111,8 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut<'_, T> { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { inner: self.as_mut().ok() } } @@ -1195,9 +1251,11 @@ impl Result { /// [`FromStr`]: crate::str::FromStr #[inline] #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] - pub fn unwrap_or_default(self) -> T + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn unwrap_or_default(self) -> T where - T: Default, + T: ~const Default + ~const Destruct, + E: ~const Destruct, { match self { Ok(x) => x, @@ -1370,7 +1428,13 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn and(self, res: Result) -> Result { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn and(self, res: Result) -> Result + where + T: ~const Destruct, + E: ~const Destruct, + U: ~const Destruct, + { match self { Ok(_) => res, Err(e) => Err(e), @@ -1409,8 +1473,12 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] #[rustc_confusables("flat_map", "flatmap")] - pub fn and_then Result>(self, op: F) -> Result { + pub const fn and_then(self, op: F) -> Result + where + F: ~const FnOnce(T) -> Result + ~const Destruct, + { match self { Ok(t) => op(t), Err(e) => Err(e), @@ -1446,7 +1514,13 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, res: Result) -> Result { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn or(self, res: Result) -> Result + where + T: ~const Destruct, + E: ~const Destruct, + F: ~const Destruct, + { match self { Ok(v) => Ok(v), Err(_) => res, @@ -1471,7 +1545,11 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_else Result>(self, op: O) -> Result { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn or_else(self, op: O) -> Result + where + O: ~const FnOnce(E) -> Result + ~const Destruct, + { match self { Ok(t) => Ok(t), Err(e) => op(e), @@ -1498,7 +1576,12 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, default: T) -> T { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn unwrap_or(self, default: T) -> T + where + T: ~const Destruct, + E: ~const Destruct, + { match self { Ok(t) => t, Err(_) => default, @@ -1519,7 +1602,11 @@ impl Result { #[inline] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_else T>(self, op: F) -> T { + #[rustc_const_unstable(feature = "const_result_trait_fn", issue = "144211")] + pub const fn unwrap_or_else(self, op: F) -> T + where + F: ~const FnOnce(E) -> T + ~const Destruct, + { match self { Ok(t) => t, Err(e) => op(e), @@ -1544,7 +1631,7 @@ impl Result { /// /// ```no_run /// let x: Result = Err("emergency failure"); - /// unsafe { x.unwrap_unchecked(); } // Undefined behavior! + /// unsafe { x.unwrap_unchecked() }; // Undefined behavior! /// ``` #[inline] #[track_caller] @@ -1762,7 +1849,7 @@ impl Result, E> { #[cold] #[track_caller] fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! { - panic!("{msg}: {error:?}") + panic!("{msg}: {error:?}"); } // This is a separate function to avoid constructing a `dyn Debug` @@ -1773,7 +1860,7 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! { #[inline] #[cold] #[track_caller] -fn unwrap_failed(_msg: &str, _error: &T) -> ! { +const fn unwrap_failed(_msg: &str, _error: &T) -> ! { panic!() } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d3e78f011daa7..f17a63db1e44a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3978,8 +3978,9 @@ impl [T] { /// /// [`split_at_mut`]: slice::split_at_mut #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] #[track_caller] - pub fn swap_with_slice(&mut self, other: &mut [T]) { + pub const fn swap_with_slice(&mut self, other: &mut [T]) { assert!(self.len() == other.len(), "destination and source slices have different lengths"); // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was // checked to have the same length. The slices cannot overlap because diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 029a7b00ad36e..0a9c0c61c9584 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_eval_select)] #![feature(const_ops)] #![feature(const_ref_cell)] +#![feature(const_result_trait_fn)] #![feature(const_trait_impl)] #![feature(core_float_math)] #![feature(core_intrinsics)] @@ -82,6 +83,7 @@ #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] +#![feature(result_option_map_or_default)] #![feature(slice_from_ptr_range)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] diff --git a/library/coretests/tests/result.rs b/library/coretests/tests/result.rs index 90ec844bc5771..39898d5dbb76e 100644 --- a/library/coretests/tests/result.rs +++ b/library/coretests/tests/result.rs @@ -421,3 +421,86 @@ fn result_try_trait_v2_branch() { assert_eq!(Ok::, ()>(one).branch(), Continue(one)); assert_eq!(Err::, ()>(()).branch(), Break(Err(()))); } + +// helper functions for const contexts +const fn eq10(x: u8) -> bool { + x == 10 +} +const fn eq20(e: u8) -> bool { + e == 20 +} +const fn double_u16(x: u8) -> u16 { + x as u16 * 2 +} +const fn to_u16(x: u8) -> u16 { + x as u16 +} +const fn err_to_u16_plus1(e: u8) -> u16 { + e as u16 + 1 +} +const fn inc_u8(x: u8) -> u8 { + x + 1 +} +const fn noop_u8_ref(_x: &u8) {} +const fn add1_result(x: u8) -> Result { + Ok(x + 1) +} +const fn add5_result(e: u8) -> Result { + Ok(e + 5) +} +const fn plus7_u8(e: u8) -> u8 { + e + 7 +} + +#[test] +fn test_const_result() { + const { + let r_ok: Result = Ok(10); + let r_err: Result = Err(20); + assert!(r_ok.is_ok()); + assert!(r_err.is_err()); + + let ok_and = r_ok.is_ok_and(eq10); + let err_and = r_err.is_err_and(eq20); + assert!(ok_and); + assert!(err_and); + + let opt_ok: Option = r_ok.ok(); + let opt_err: Option = r_err.err(); + assert!(opt_ok.unwrap() == 10); + assert!(opt_err.unwrap() == 20); + + let mapped: Result = r_ok.map(double_u16); + let map_or: u16 = r_ok.map_or(0, to_u16); + let map_or_else: u16 = r_err.map_or_else(err_to_u16_plus1, to_u16); + let map_or_default: u8 = r_err.map_or_default(inc_u8); + assert!(mapped.unwrap_or_default() == 20); + assert!(map_or == 10); + assert!(map_or_else == 21); + assert!(map_or_default == 0); + + let _map_err: Result = r_err.map_err(to_u16); + //FIXME: currently can't unwrap const error + // assert!(map_err.unwrap_err() == 20); + + let inspected_ok: Result = r_ok.inspect(noop_u8_ref); + let inspected_err: Result = r_err.inspect_err(noop_u8_ref); + assert!(inspected_ok.is_ok()); + assert!(inspected_err.is_err()); + + let unwrapped_default: u8 = r_err.unwrap_or_default(); + assert!(unwrapped_default == 0); + + let and_then: Result = r_ok.and_then(add1_result); + let or: Result = r_err.or(Ok(5)); + let or_else: Result = r_err.or_else(add5_result); + assert!(and_then.unwrap_or_default() == 11); + assert!(or.unwrap_or_default() == 5); + assert!(or_else.unwrap_or_default() == 25); + + let u_or: u8 = r_err.unwrap_or(7); + let u_or_else: u8 = r_err.unwrap_or_else(plus7_u8); + assert!(u_or == 7); + assert!(u_or_else == 27); + }; +} diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index e8c66f1a4dd34..ecf043ac7071c 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -12,8 +12,7 @@ bench = false doc = false [dependencies] -core = { path = "../core" } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins" } +core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" } [target.'cfg(target_os = "android")'.dependencies] libc = { version = "0.2", default-features = false } diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index 47914b9cd3c6e..13d1a7160da8d 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -13,10 +13,9 @@ doc = false [dependencies] alloc = { path = "../alloc" } -core = { path = "../core" } -unwind = { path = "../unwind" } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins" } cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } +core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" } +unwind = { path = "../unwind" } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2", default-features = false } diff --git a/library/rustc-std-workspace-core/README.md b/library/rustc-std-workspace-core/README.md index 55a36e741065f..15bc93f7948a3 100644 --- a/library/rustc-std-workspace-core/README.md +++ b/library/rustc-std-workspace-core/README.md @@ -11,6 +11,12 @@ on crates.io will draw a dependency edge to `libcore`, the version defined in this repository. That should draw all the dependency edges to ensure Cargo builds crates successfully! +`rustc-std-workspace-core` also ensures `compiler-builtins` is in the crate +graph. This crate is used by other crates in `library/`, other than `std` and +`alloc`, so the `compiler-builtins` setup only needs to be configured in a +single place. (Otherwise these crates would just need to depend on `core` and +`compiler-builtins` separately.) + Note that crates on crates.io need to depend on this crate with the name `core` for everything to work correctly. To do that they can use: diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 6b539279ea2d7..6fdeb97f5874e 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,6 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 38eec467e3ea1..9896d07fe7b82 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -295,6 +295,8 @@ #![feature(f128)] #![feature(ffi_const)] #![feature(formatting_options)] +#![feature(hash_map_internals)] +#![feature(hash_map_macro)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_advance_by)] diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 25e2b7ea13703..254570ae9c836 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -379,3 +379,77 @@ macro_rules! dbg { ($($crate::dbg!($val)),+,) }; } + +#[doc(hidden)] +#[macro_export] +#[allow_internal_unstable(hash_map_internals)] +#[unstable(feature = "hash_map_internals", issue = "none")] +macro_rules! repetition_utils { + (@count $($tokens:tt),*) => {{ + [$($crate::repetition_utils!(@replace $tokens => ())),*].len() + }}; + + (@replace $x:tt => $y:tt) => { $y } +} + +/// Creates a [`HashMap`] containing the arguments. +/// +/// `hash_map!` allows specifying the entries that make +/// up the [`HashMap`] where the key and value are separated by a `=>`. +/// +/// The entries are separated by commas with a trailing comma being allowed. +/// +/// It is semantically equivalent to using repeated [`HashMap::insert`] +/// on a newly created hashmap. +/// +/// `hash_map!` will attempt to avoid repeated reallocations by +/// using [`HashMap::with_capacity`]. +/// +/// # Examples +/// +/// ```rust +/// #![feature(hash_map_macro)] +/// +/// let map = hash_map! { +/// "key" => "value", +/// "key1" => "value1" +/// }; +/// +/// assert_eq!(map.get("key"), Some(&"value")); +/// assert_eq!(map.get("key1"), Some(&"value1")); +/// assert!(map.get("brrrrrrooooommm").is_none()); +/// ``` +/// +/// And with a trailing comma +/// +///```rust +/// #![feature(hash_map_macro)] +/// +/// let map = hash_map! { +/// "key" => "value", // notice the , +/// }; +/// +/// assert_eq!(map.get("key"), Some(&"value")); +/// ``` +/// +/// The key and value are moved into the HashMap. +/// +/// [`HashMap`]: crate::collections::HashMap +/// [`HashMap::insert`]: crate::collections::HashMap::insert +/// [`HashMap::with_capacity`]: crate::collections::HashMap::with_capacity +#[macro_export] +#[allow_internal_unstable(hash_map_internals)] +#[unstable(feature = "hash_map_macro", issue = "144032")] +macro_rules! hash_map { + () => {{ + $crate::collections::HashMap::new() + }}; + + ( $( $key:expr => $value:expr ),* $(,)? ) => {{ + let mut map = $crate::collections::HashMap::with_capacity( + const { $crate::repetition_utils!(@count $($key),*) } + ); + $( map.insert($key, $value); )* + map + }} +} diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 234fb284a5904..913ef72f67464 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -388,7 +388,7 @@ pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { /// ``` #[stable(feature = "resume_unwind", since = "1.9.0")] pub fn resume_unwind(payload: Box) -> ! { - panicking::rust_panic_without_hook(payload) + panicking::resume_unwind(payload) } /// Makes all future panics abort directly without running the panic hook or unwinding. diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 7873049d20bfd..224cd39855a45 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -696,14 +696,14 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { let msg = info.message(); crate::sys::backtrace::__rust_end_short_backtrace(move || { if let Some(s) = msg.as_str() { - rust_panic_with_hook( + panic_with_hook( &mut StaticStrPayload(s), loc, info.can_unwind(), info.force_no_backtrace(), ); } else { - rust_panic_with_hook( + panic_with_hook( &mut FormatStringPayload { inner: &msg, string: None }, loc, info.can_unwind(), @@ -767,7 +767,7 @@ pub const fn begin_panic(msg: M) -> ! { let loc = Location::caller(); crate::sys::backtrace::__rust_end_short_backtrace(move || { - rust_panic_with_hook( + panic_with_hook( &mut Payload { inner: Some(msg) }, loc, /* can_unwind */ true, @@ -792,7 +792,7 @@ fn payload_as_str(payload: &dyn Any) -> &str { /// panics, panic hooks, and finally dispatching to the panic runtime to either /// abort or unwind. #[optimize(size)] -fn rust_panic_with_hook( +fn panic_with_hook( payload: &mut dyn PanicPayload, location: &Location<'_>, can_unwind: bool, @@ -861,7 +861,7 @@ fn rust_panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. #[cfg_attr(feature = "panic_immediate_abort", inline)] -pub fn rust_panic_without_hook(payload: Box) -> ! { +pub fn resume_unwind(payload: Box) -> ! { panic_count::increase(false); struct RewrapBox(Box); @@ -885,8 +885,8 @@ pub fn rust_panic_without_hook(payload: Box) -> ! { rust_panic(&mut RewrapBox(payload)) } -/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap -/// yer breakpoints. +/// A function with a fixed suffix (through `rustc_std_internal_symbol`) +/// on which to slap yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(not(feature = "panic_immediate_abort"))] diff --git a/library/std/src/path.rs b/library/std/src/path.rs index d9c34d4fa0451..055e7f814800d 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3259,8 +3259,8 @@ impl Path { /// /// # Examples /// - #[cfg_attr(unix, doc = "```no_run")] - #[cfg_attr(not(unix), doc = "```ignore")] + /// ```rust,no_run + /// # #[cfg(unix)] { /// use std::path::Path; /// use std::os::unix::fs::symlink; /// @@ -3268,6 +3268,7 @@ impl Path { /// symlink("/origin_does_not_exist/", link_path).unwrap(); /// assert_eq!(link_path.is_symlink(), true); /// assert_eq!(link_path.exists(), false); + /// # } /// ``` /// /// # See Also diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index eba849d16dacd..a40e29a772a9c 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -25,6 +25,22 @@ union Data { /// /// [`LazyCell`]: crate::cell::LazyCell /// +/// # Poisoning +/// +/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned. +/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference +/// or via an explicit call to [`force()`]) will panic. +/// +/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key +/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of +/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like +/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`]. +/// +/// [`force()`]: LazyLock::force +/// [`std::sync::poison`]: crate::sync::poison +/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex +/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner +/// /// # Examples /// /// Initialize static variables with `LazyLock`. @@ -102,6 +118,10 @@ impl T> LazyLock { /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. /// + /// # Panics + /// + /// Panics if the lock is poisoned. + /// /// # Examples /// /// ``` @@ -136,6 +156,15 @@ impl T> LazyLock { /// Forces the evaluation of this lazy value and returns a mutable reference to /// the result. /// + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future + /// accesses of the lock (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyLock::new + /// [`force()`]: LazyLock::force + /// /// # Examples /// /// ``` @@ -193,6 +222,15 @@ impl T> LazyLock { /// This method will block the calling thread if another initialization /// routine is currently running. /// + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future + /// accesses of the lock (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyLock::new + /// [`force()`]: LazyLock::force + /// /// # Examples /// /// ``` @@ -227,7 +265,8 @@ impl T> LazyLock { } impl LazyLock { - /// Returns a mutable reference to the value if initialized, or `None` if not. + /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or + /// poisoned), returns `None`. /// /// # Examples /// @@ -256,7 +295,8 @@ impl LazyLock { } } - /// Returns a reference to the value if initialized, or `None` if not. + /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned), + /// returns `None`. /// /// # Examples /// @@ -307,6 +347,14 @@ impl T> Deref for LazyLock { /// This method will block the calling thread if another initialization /// routine is currently running. /// + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future + /// accesses of the lock (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyLock::new + /// [`force()`]: LazyLock::force #[inline] fn deref(&self) -> &T { LazyLock::force(self) @@ -315,6 +363,14 @@ impl T> Deref for LazyLock { #[stable(feature = "lazy_deref_mut", since = "1.89.0")] impl T> DerefMut for LazyLock { + /// # Panics + /// + /// If the initialization closure panics (the one that is passed to the [`new()`] method), the + /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future + /// accesses of the lock (via [`force()`] or a dereference) to panic. + /// + /// [`new()`]: LazyLock::new + /// [`force()`]: LazyLock::force #[inline] fn deref_mut(&mut self) -> &mut T { LazyLock::force_mut(self) diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index a5c3a6c46a433..b224044cbe09c 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -16,6 +16,8 @@ use crate::sync::Once; /// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes /// initialized once written. /// +/// Unlike [`Mutex`](crate::sync::Mutex), `OnceLock` is never poisoned on panic. +/// /// [`OnceCell`]: crate::cell::OnceCell /// [`LazyLock`]: crate::sync::LazyLock /// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index b901a5701a488..31889dcc10fad 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -2,15 +2,16 @@ //! //! # Poisoning //! -//! All synchronization objects in this module implement a strategy called "poisoning" -//! where if a thread panics while holding the exclusive access granted by the primitive, -//! the state of the primitive is set to "poisoned". -//! This information is then propagated to all other threads +//! All synchronization objects in this module implement a strategy called +//! "poisoning" where a primitive becomes poisoned if it recognizes that some +//! thread has panicked while holding the exclusive access granted by the +//! primitive. This information is then propagated to all other threads //! to signify that the data protected by this primitive is likely tainted //! (some invariant is not being upheld). //! -//! The specifics of how this "poisoned" state affects other threads -//! depend on the primitive. See [#Overview] below. +//! The specifics of how this "poisoned" state affects other threads and whether +//! the panics are recognized reliably or on a best-effort basis depend on the +//! primitive. See [Overview](#overview) below. //! //! For the alternative implementations that do not employ poisoning, //! see [`std::sync::nonpoison`]. @@ -36,14 +37,15 @@ //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at //! most one thread at a time is able to access some data. //! -//! [`Mutex::lock()`] returns a [`LockResult`], -//! providing a way to deal with the poisoned state. -//! See [`Mutex`'s documentation](Mutex#poisoning) for more. +//! Panicking while holding the lock typically poisons the mutex, but it is +//! not guaranteed to detect this condition in all circumstances. +//! [`Mutex::lock()`] returns a [`LockResult`], providing a way to deal with +//! the poisoned state. See [`Mutex`'s documentation](Mutex#poisoning) for more. //! //! - [`Once`]: A thread-safe way to run a piece of code only once. //! Mostly useful for implementing one-time global initialization. //! -//! [`Once`] is poisoned if the piece of code passed to +//! [`Once`] is reliably poisoned if the piece of code passed to //! [`Once::call_once()`] or [`Once::call_once_force()`] panics. //! When in poisoned state, subsequent calls to [`Once::call_once()`] will panic too. //! [`Once::call_once_force()`] can be used to clear the poisoned state. @@ -53,7 +55,7 @@ //! writer at a time. In some cases, this can be more efficient than //! a mutex. //! -//! This implementation, like [`Mutex`], will become poisoned on a panic. +//! This implementation, like [`Mutex`], usually becomes poisoned on a panic. //! Note, however, that an `RwLock` may only be poisoned if a panic occurs //! while it is locked exclusively (write mode). If a panic occurs in any reader, //! then the lock will not be poisoned. diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 64744f18c746e..6205c4fa4ca4b 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -18,20 +18,69 @@ use crate::sys::sync as sys; /// # Poisoning /// /// The mutexes in this module implement a strategy called "poisoning" where a -/// mutex is considered poisoned whenever a thread panics while holding the -/// mutex. Once a mutex is poisoned, all other threads are unable to access the -/// data by default as it is likely tainted (some invariant is not being -/// upheld). +/// mutex becomes poisoned if it recognizes that the thread holding it has +/// panicked. /// -/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a +/// Once a mutex is poisoned, all other threads are unable to access the data by +/// default as it is likely tainted (some invariant is not being upheld). For a +/// mutex, this means that the [`lock`] and [`try_lock`] methods return a /// [`Result`] which indicates whether a mutex has been poisoned or not. Most /// usage of a mutex will simply [`unwrap()`] these results, propagating panics /// among threads to ensure that a possibly invalid invariant is not witnessed. /// -/// A poisoned mutex, however, does not prevent all access to the underlying -/// data. The [`PoisonError`] type has an [`into_inner`] method which will return -/// the guard that would have otherwise been returned on a successful lock. This -/// allows access to the data, despite the lock being poisoned. +/// Poisoning is only advisory: the [`PoisonError`] type has an [`into_inner`] +/// method which will return the guard that would have otherwise been returned +/// on a successful lock. This allows access to the data, despite the lock being +/// poisoned. +/// +/// In addition, the panic detection is not ideal, so even unpoisoned mutexes +/// need to be handled with care, since certain panics may have been skipped. +/// Here is a non-exhaustive list of situations where this might occur: +/// +/// - If a mutex is locked while a panic is underway, e.g. within a [`Drop`] +/// implementation or a [panic hook], panicking for the second time while the +/// lock is held will leave the mutex unpoisoned. Note that while double panic +/// usually aborts the program, [`catch_unwind`] can prevent this. +/// +/// - Locking and unlocking the mutex across different panic contexts, e.g. by +/// storing the guard to a [`Cell`] within [`Drop::drop`] and accessing it +/// outside, or vice versa, can affect poisoning status in an unexpected way. +/// +/// - Foreign exceptions do not currently trigger poisoning even in absence of +/// other panics. +/// +/// While this rarely happens in realistic code, `unsafe` code cannot rely on +/// poisoning for soundness, since the behavior of poisoning can depend on +/// outside context. Here's an example of **incorrect** use of poisoning: +/// +/// ```rust +/// use std::sync::Mutex; +/// +/// struct MutexBox { +/// data: Mutex<*mut T>, +/// } +/// +/// impl MutexBox { +/// pub fn new(value: T) -> Self { +/// Self { +/// data: Mutex::new(Box::into_raw(Box::new(value))), +/// } +/// } +/// +/// pub fn replace_with(&self, f: impl FnOnce(T) -> T) { +/// let ptr = self.data.lock().expect("poisoned"); +/// // While `f` is running, the data is moved out of `*ptr`. If `f` +/// // panics, `*ptr` keeps pointing at a dropped value. The intention +/// // is that this will poison the mutex, so the following calls to +/// // `replace_with` will panic without reading `*ptr`. But since +/// // poisoning is not guaranteed to occur if this is run from a panic +/// // hook, this can lead to use-after-free. +/// unsafe { +/// (*ptr).write(f((*ptr).read())); +/// } +/// } +/// } +/// ``` /// /// [`new`]: Self::new /// [`lock`]: Self::lock @@ -39,6 +88,9 @@ use crate::sys::sync as sys; /// [`unwrap()`]: Result::unwrap /// [`PoisonError`]: super::PoisonError /// [`into_inner`]: super::PoisonError::into_inner +/// [panic hook]: crate::panic::set_hook +/// [`catch_unwind`]: crate::panic::catch_unwind +/// [`Cell`]: crate::cell::Cell /// /// # Examples /// diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs index 103e519540795..faf2913c54730 100644 --- a/library/std/src/sync/poison/once.rs +++ b/library/std/src/sync/poison/once.rs @@ -136,7 +136,8 @@ impl Once { /// it will *poison* this [`Once`] instance, causing all future invocations of /// `call_once` to also panic. /// - /// This is similar to [poisoning with mutexes][poison]. + /// This is similar to [poisoning with mutexes][poison], but this mechanism + /// is guaranteed to never skip panics within `f`. /// /// [poison]: struct.Mutex.html#poisoning #[inline] @@ -293,6 +294,9 @@ impl Once { /// Blocks the current thread until initialization has completed, ignoring /// poisoning. + /// + /// If this [`Once`] has been poisoned, this function blocks until it + /// becomes completed, unlike [`Once::wait()`], which panics in this case. #[stable(feature = "once_wait", since = "1.86.0")] pub fn wait_force(&self) { if !self.inner.is_completed() { diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 934a173425a81..2c92602bc878f 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -46,10 +46,12 @@ use crate::sys::sync as sys; /// /// # Poisoning /// -/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however, -/// that an `RwLock` may only be poisoned if a panic occurs while it is locked -/// exclusively (write mode). If a panic occurs in any reader, then the lock -/// will not be poisoned. +/// An `RwLock`, like [`Mutex`], will [usually] become poisoned on a panic. Note, +/// however, that an `RwLock` may only be poisoned if a panic occurs while it is +/// locked exclusively (write mode). If a panic occurs in any reader, then the +/// lock will not be poisoned. +/// +/// [usually]: super::Mutex#poisoning /// /// # Examples /// diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 271dc4d11de75..b50574de937aa 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -444,17 +444,17 @@ impl<'a> DevicePathNode<'a> { impl<'a> PartialEq for DevicePathNode<'a> { fn eq(&self, other: &Self) -> bool { - let self_len = self.length(); - let other_len = other.length(); - - self_len == other_len - && unsafe { - compiler_builtins::mem::memcmp( - self.protocol.as_ptr().cast(), - other.protocol.as_ptr().cast(), - usize::from(self_len), - ) == 0 - } + // Compare as a single buffer rather than by field since it optimizes better. + // + // SAFETY: `Protocol` is followed by a buffer of `length - sizeof::()`. `Protocol` + // has no padding so it is sound to interpret as a slice. + unsafe { + let s1 = + slice::from_raw_parts(self.protocol.as_ptr().cast::(), self.length().into()); + let s2 = + slice::from_raw_parts(other.protocol.as_ptr().cast::(), other.length().into()); + s1 == s2 + } } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index dff981c900c08..8d3ab82ace120 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -2018,6 +2018,9 @@ fn _assert_sync_and_send() { /// which may take time on systems with large numbers of mountpoints. /// (This does not apply to cgroup v2, or to processes not in a /// cgroup.) +/// - It does not attempt to take `ulimit` into account. If there is a limit set on the number of +/// threads, `available_parallelism` cannot know how much of that limit a Rust program should +/// take, or know in a reliable and race-free way how much of that limit is already taken. /// /// On all targets: /// - It may overcount the amount of parallelism available when running in a VM diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index f8da09f71931a..b9ce676eb3ffe 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -14,9 +14,8 @@ bench = false doc = false [dependencies] -core = { path = "../core" } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins" } cfg-if = "1.0" +core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index b3b889ccf7063..4b67ad42eb300 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,5 +2,5 @@ # standard library we currently track. [toolchain] -channel = "nightly-2025-08-01" +channel = "nightly-2025-08-06" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] diff --git a/tool_config/kani-version.toml b/tool_config/kani-version.toml index 9b03a8a4dacf7..ffb2ab558c7a1 100644 --- a/tool_config/kani-version.toml +++ b/tool_config/kani-version.toml @@ -2,4 +2,4 @@ # incompatible with the verify-std repo. [kani] -commit = "53a7a3b516c5cbe504378d4a208d07d49b5aa4ec" +commit = "fade7057e845eb5e5c6c9bc00a6d72b338765683"