diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index b4176e9c1f4d0..c9b98fa4e5a9b 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -429,10 +429,10 @@ pub mod __alloc_error_handler { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. #[rustc_std_internal_symbol] - static __rust_alloc_error_handler_should_panic: u8; + fn __rust_alloc_error_handler_should_panic_v2() -> u8; } - if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } { panic!("memory allocation of {size} bytes failed") } else { core::panicking::panic_nounwind_fmt( diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 4536f55544354..3db37f1d16f3d 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -191,7 +191,7 @@ use core::error::{self, Error}; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; -use core::marker::{PointerLike, Tuple, Unsize}; +use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, @@ -1098,115 +1098,6 @@ impl Box { pub unsafe fn from_non_null(ptr: NonNull) -> Self { unsafe { Self::from_raw(ptr.as_ptr()) } } -} - -impl Box { - /// Constructs a box from a raw pointer in the given allocator. - /// - /// After calling this function, the raw pointer is owned by the - /// resulting `Box`. Specifically, the `Box` destructor will call - /// the destructor of `T` and free the allocated memory. For this - /// to be safe, the memory must have been allocated in accordance - /// with the [memory layout] used by `Box` . - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to - /// memory problems. For example, a double-free may occur if the - /// function is called twice on the same raw pointer. - /// - /// The raw pointer must point to a block of memory allocated by `alloc`. - /// - /// # Examples - /// - /// Recreate a `Box` which was previously converted to a raw pointer - /// using [`Box::into_raw_with_allocator`]: - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::alloc::System; - /// - /// let x = Box::new_in(5, System); - /// let (ptr, alloc) = Box::into_raw_with_allocator(x); - /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; - /// ``` - /// Manually create a `Box` from scratch by using the system allocator: - /// ``` - /// #![feature(allocator_api, slice_ptr_get)] - /// - /// use std::alloc::{Allocator, Layout, System}; - /// - /// unsafe { - /// let ptr = System.allocate(Layout::new::())?.as_mut_ptr() as *mut i32; - /// // In general .write is required to avoid attempting to destruct - /// // the (uninitialized) previous contents of `ptr`, though for this - /// // simple example `*ptr = 5` would have worked as well. - /// ptr.write(5); - /// let x = Box::from_raw_in(ptr, System); - /// } - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [memory layout]: self#memory-layout - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { - Box(unsafe { Unique::new_unchecked(raw) }, alloc) - } - - /// Constructs a box from a `NonNull` pointer in the given allocator. - /// - /// After calling this function, the `NonNull` pointer is owned by - /// the resulting `Box`. Specifically, the `Box` destructor will call - /// the destructor of `T` and free the allocated memory. For this - /// to be safe, the memory must have been allocated in accordance - /// with the [memory layout] used by `Box` . - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to - /// memory problems. For example, a double-free may occur if the - /// function is called twice on the same raw pointer. - /// - /// The non-null pointer must point to a block of memory allocated by `alloc`. - /// - /// # Examples - /// - /// Recreate a `Box` which was previously converted to a `NonNull` pointer - /// using [`Box::into_non_null_with_allocator`]: - /// ``` - /// #![feature(allocator_api, box_vec_non_null)] - /// - /// use std::alloc::System; - /// - /// let x = Box::new_in(5, System); - /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); - /// let x = unsafe { Box::from_non_null_in(non_null, alloc) }; - /// ``` - /// Manually create a `Box` from scratch by using the system allocator: - /// ``` - /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)] - /// - /// use std::alloc::{Allocator, Layout, System}; - /// - /// unsafe { - /// let non_null = System.allocate(Layout::new::())?.cast::(); - /// // In general .write is required to avoid attempting to destruct - /// // the (uninitialized) previous contents of `non_null`. - /// non_null.write(5); - /// let x = Box::from_non_null_in(non_null, System); - /// } - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [memory layout]: self#memory-layout - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] - #[inline] - pub unsafe fn from_non_null_in(raw: NonNull, alloc: A) -> Self { - // SAFETY: guaranteed by the caller. - unsafe { Box::from_raw_in(raw.as_ptr(), alloc) } - } /// Consumes the `Box`, returning a wrapped raw pointer. /// @@ -1259,8 +1150,11 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Self) -> *mut T { - // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here. - unsafe { &raw mut *&mut *Self::into_raw_with_allocator(b).0 } + // Avoid `into_raw_with_allocator` as that interacts poorly with Miri's Stacked Borrows. + let mut b = mem::ManuallyDrop::new(b); + // We go through the built-in deref for `Box`, which is crucial for Miri to recognize this + // operation for it's alias tracking. + &raw mut **b } /// Consumes the `Box`, returning a wrapped `NonNull` pointer. @@ -1322,6 +1216,115 @@ impl Box { // SAFETY: `Box` is guaranteed to be non-null. unsafe { NonNull::new_unchecked(Self::into_raw(b)) } } +} + +impl Box { + /// Constructs a box from a raw pointer in the given allocator. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// The raw pointer must point to a block of memory allocated by `alloc`. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw_with_allocator`]: + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(5, System); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); + /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; + /// ``` + /// Manually create a `Box` from scratch by using the system allocator: + /// ``` + /// #![feature(allocator_api, slice_ptr_get)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// + /// unsafe { + /// let ptr = System.allocate(Layout::new::())?.as_mut_ptr() as *mut i32; + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `ptr`, though for this + /// // simple example `*ptr = 5` would have worked as well. + /// ptr.write(5); + /// let x = Box::from_raw_in(ptr, System); + /// } + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [memory layout]: self#memory-layout + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + Box(unsafe { Unique::new_unchecked(raw) }, alloc) + } + + /// Constructs a box from a `NonNull` pointer in the given allocator. + /// + /// After calling this function, the `NonNull` pointer is owned by + /// the resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// The non-null pointer must point to a block of memory allocated by `alloc`. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a `NonNull` pointer + /// using [`Box::into_non_null_with_allocator`]: + /// ``` + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(5, System); + /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); + /// let x = unsafe { Box::from_non_null_in(non_null, alloc) }; + /// ``` + /// Manually create a `Box` from scratch by using the system allocator: + /// ``` + /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// + /// unsafe { + /// let non_null = System.allocate(Layout::new::())?.cast::(); + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `non_null`. + /// non_null.write(5); + /// let x = Box::from_non_null_in(non_null, System); + /// } + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [memory layout]: self#memory-layout + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[inline] + pub unsafe fn from_non_null_in(raw: NonNull, alloc: A) -> Self { + // SAFETY: guaranteed by the caller. + unsafe { Box::from_raw_in(raw.as_ptr(), alloc) } + } /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. /// @@ -1602,7 +1605,9 @@ impl Box { where A: 'a, { - unsafe { &mut *Box::into_raw(b) } + let (ptr, alloc) = Box::into_raw_with_allocator(b); + mem::forget(alloc); + unsafe { &mut *ptr } } /// Converts a `Box` into a `Pin>`. If `T` does not implement [`Unpin`], then @@ -2127,6 +2132,3 @@ impl Error for Box { Error::provide(&**self, request); } } - -#[unstable(feature = "pointer_like_trait", issue = "none")] -impl PointerLike for Box {} diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index d03c1969b5b70..70c344e49b76a 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1031,7 +1031,7 @@ impl LinkedList { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// In other words, remove all elements `e` for which `f(&mut e)` returns false. /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. /// @@ -1047,7 +1047,7 @@ impl LinkedList { /// d.push_front(2); /// d.push_front(3); /// - /// d.retain(|&x| x % 2 == 0); + /// d.retain(|&mut x| x % 2 == 0); /// /// assert_eq!(d.pop_front(), Some(2)); /// assert_eq!(d.pop_front(), None); @@ -1074,41 +1074,6 @@ impl LinkedList { /// ``` #[unstable(feature = "linked_list_retain", issue = "114135")] pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.retain_mut(|elem| f(elem)); - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` for which `f(&mut e)` returns false. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_retain)] - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// - /// d.push_front(1); - /// d.push_front(2); - /// d.push_front(3); - /// - /// d.retain_mut(|x| if *x % 2 == 0 { - /// *x += 1; - /// true - /// } else { - /// false - /// }); - /// assert_eq!(d.pop_front(), Some(3)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[unstable(feature = "linked_list_retain", issue = "114135")] - pub fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b79f56fb893bc..9bf8fcae64e91 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -108,8 +108,10 @@ #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] +#![feature(const_default)] #![feature(const_eval_select)] #![feature(const_heap)] +#![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] @@ -135,7 +137,6 @@ #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] -#![feature(pointer_like_trait)] #![feature(ptr_alignment_type)] #![feature(ptr_internals)] #![feature(ptr_metadata)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 010d17f74762c..5018ff4ad71f3 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1322,6 +1322,30 @@ impl Rc { unsafe { Self::from_raw_in(ptr, Global) } } + /// Consumes the `Rc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new("hello".to_owned()); + /// let x_ptr = Rc::into_raw(x); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Rc::from_raw(x_ptr) }); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "rc_raw", since = "1.17.0")] + #[rustc_never_returns_null_ptr] + pub fn into_raw(this: Self) -> *const T { + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) + } + /// Increments the strong reference count on the `Rc` associated with the /// provided pointer by one. /// @@ -1408,30 +1432,6 @@ impl Rc { &this.alloc } - /// Consumes the `Rc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new("hello".to_owned()); - /// let x_ptr = Rc::into_raw(x); - /// assert_eq!(unsafe { &*x_ptr }, "hello"); - /// # // Prevent leaks for Miri. - /// # drop(unsafe { Rc::from_raw(x_ptr) }); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] - pub fn into_raw(this: Self) -> *const T { - let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } - /// Consumes the `Rc`, returning the wrapped pointer and allocator. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -1525,7 +1525,7 @@ impl Rc { /// use std::alloc::System; /// /// let x = Rc::new_in("hello".to_owned(), System); - /// let x_ptr = Rc::into_raw(x); + /// let (x_ptr, _alloc) = Rc::into_raw_with_allocator(x); /// /// unsafe { /// // Convert back to an `Rc` to prevent leak. @@ -1547,7 +1547,7 @@ impl Rc { /// use std::alloc::System; /// /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); - /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// let x_ptr: *const [u32] = Rc::into_raw_with_allocator(x).0; /// /// unsafe { /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); @@ -1648,7 +1648,7 @@ impl Rc { /// let five = Rc::new_in(5, System); /// /// unsafe { - /// let ptr = Rc::into_raw(five); + /// let (ptr, _alloc) = Rc::into_raw_with_allocator(five); /// Rc::increment_strong_count_in(ptr, System); /// /// let five = Rc::from_raw_in(ptr, System); @@ -1694,7 +1694,7 @@ impl Rc { /// let five = Rc::new_in(5, System); /// /// unsafe { - /// let ptr = Rc::into_raw(five); + /// let (ptr, _alloc) = Rc::into_raw_with_allocator(five); /// Rc::increment_strong_count_in(ptr, System); /// /// let five = Rc::from_raw_in(ptr, System); @@ -3123,6 +3123,39 @@ impl Weak { pub unsafe fn from_raw(ptr: *const T) -> Self { unsafe { Self::from_raw_in(ptr, Global) } } + + /// Consumes the `Weak` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// let raw = weak.into_raw(); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub fn into_raw(self) -> *const T { + mem::ManuallyDrop::new(self).as_ptr() + } } impl Weak { @@ -3175,39 +3208,6 @@ impl Weak { } } - /// Consumes the `Weak` and turns it into a raw pointer. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak` with [`from_raw`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// let weak = Rc::downgrade(&strong); - /// let raw = weak.into_raw(); - /// - /// assert_eq!(1, Rc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw(raw) }); - /// assert_eq!(0, Rc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw`]: Weak::from_raw - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub fn into_raw(self) -> *const T { - mem::ManuallyDrop::new(self).as_ptr() - } - /// Consumes the `Weak`, returning the wrapped pointer and allocator. /// /// This converts the weak pointer into a raw pointer, while still preserving the ownership of diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 5f69f699867a9..58baa07bc1741 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -156,7 +156,7 @@ use crate::vec::{self, Vec}; /// ``` /// /// Next, what should `s[i]` return? Because indexing returns a reference -/// to underlying data it could be `&u8`, `&[u8]`, or something else similar. +/// to underlying data it could be `&u8`, `&[u8]`, or something similar. /// Since we're only providing one index, `&u8` makes the most sense but that /// might not be what the user expects and can be explicitly achieved with /// [`as_bytes()`]: @@ -2611,7 +2611,8 @@ impl_eq! { Cow<'a, str>, &'b str } impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for String { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for String { /// Creates an empty `String`. #[inline] fn default() -> String { @@ -2875,7 +2876,8 @@ macro_rules! impl_to_string { out = String::with_capacity(SIZE); } - out.push_str(self.unsigned_abs()._fmt(&mut buf)); + // SAFETY: `buf` is always big enough to contain all the digits. + unsafe { out.push_str(self.unsigned_abs()._fmt(&mut buf)); } out } } @@ -2887,7 +2889,8 @@ macro_rules! impl_to_string { const SIZE: usize = $unsigned::MAX.ilog10() as usize + 1; let mut buf = [core::mem::MaybeUninit::::uninit(); SIZE]; - self._fmt(&mut buf).to_string() + // SAFETY: `buf` is always big enough to contain all the digits. + unsafe { self._fmt(&mut buf).to_string() } } } )* diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1e3c03977bd75..b8925f4544f44 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1467,6 +1467,30 @@ impl Arc { unsafe { Arc::from_raw_in(ptr, Global) } } + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new("hello".to_owned()); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Arc::from_raw(x_ptr) }); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "rc_raw", since = "1.17.0")] + #[rustc_never_returns_null_ptr] + pub fn into_raw(this: Self) -> *const T { + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) + } + /// Increments the strong reference count on the `Arc` associated with the /// provided pointer by one. /// @@ -1558,30 +1582,6 @@ impl Arc { &this.alloc } - /// Consumes the `Arc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Arc` using - /// [`Arc::from_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new("hello".to_owned()); - /// let x_ptr = Arc::into_raw(x); - /// assert_eq!(unsafe { &*x_ptr }, "hello"); - /// # // Prevent leaks for Miri. - /// # drop(unsafe { Arc::from_raw(x_ptr) }); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] - pub fn into_raw(this: Self) -> *const T { - let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } - /// Consumes the `Arc`, returning the wrapped pointer and allocator. /// /// To avoid a memory leak the pointer must be converted back to an `Arc` using @@ -1676,7 +1676,7 @@ impl Arc { /// use std::alloc::System; /// /// let x = Arc::new_in("hello".to_owned(), System); - /// let x_ptr = Arc::into_raw(x); + /// let (x_ptr, alloc) = Arc::into_raw_with_allocator(x); /// /// unsafe { /// // Convert back to an `Arc` to prevent leak. @@ -1698,7 +1698,7 @@ impl Arc { /// use std::alloc::System; /// /// let x: Arc<[u32], _> = Arc::new_in([1, 2, 3], System); - /// let x_ptr: *const [u32] = Arc::into_raw(x); + /// let x_ptr: *const [u32] = Arc::into_raw_with_allocator(x).0; /// /// unsafe { /// let x: Arc<[u32; 3], _> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); @@ -1850,7 +1850,7 @@ impl Arc { /// let five = Arc::new_in(5, System); /// /// unsafe { - /// let ptr = Arc::into_raw(five); + /// let (ptr, _alloc) = Arc::into_raw_with_allocator(five); /// Arc::increment_strong_count_in(ptr, System); /// /// // This assertion is deterministic because we haven't shared @@ -1899,7 +1899,7 @@ impl Arc { /// let five = Arc::new_in(5, System); /// /// unsafe { - /// let ptr = Arc::into_raw(five); + /// let (ptr, _alloc) = Arc::into_raw_with_allocator(five); /// Arc::increment_strong_count_in(ptr, System); /// /// // Those assertions are deterministic because we haven't shared @@ -2863,6 +2863,39 @@ impl Weak { pub unsafe fn from_raw(ptr: *const T) -> Self { unsafe { Weak::from_raw_in(ptr, Global) } } + + /// Consumes the `Weak` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Weak}; + /// + /// let strong = Arc::new("hello".to_owned()); + /// let weak = Arc::downgrade(&strong); + /// let raw = weak.into_raw(); + /// + /// assert_eq!(1, Arc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Arc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub fn into_raw(self) -> *const T { + ManuallyDrop::new(self).as_ptr() + } } impl Weak { @@ -2915,39 +2948,6 @@ impl Weak { } } - /// Consumes the `Weak` and turns it into a raw pointer. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak` with [`from_raw`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Weak}; - /// - /// let strong = Arc::new("hello".to_owned()); - /// let weak = Arc::downgrade(&strong); - /// let raw = weak.into_raw(); - /// - /// assert_eq!(1, Arc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw(raw) }); - /// assert_eq!(0, Arc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw`]: Weak::from_raw - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub fn into_raw(self) -> *const T { - ManuallyDrop::new(self).as_ptr() - } - /// Consumes the `Weak`, returning the wrapped pointer and allocator. /// /// This converts the weak pointer into a raw pointer, while still preserving the ownership of diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1bc07933e8cb3..51071eb974c38 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -761,6 +761,88 @@ impl Vec { pub fn peek_mut(&mut self) -> Option> { PeekMut::new(self) } + + /// Decomposes a `Vec` into its raw components: `(pointer, length, capacity)`. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts`]: Vec::from_raw_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts)] + /// let v: Vec = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_raw_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(self); + (me.as_mut_ptr(), me.len(), me.capacity()) + } + + #[doc(alias = "into_non_null_parts")] + /// Decomposes a `Vec` into its raw components: `(NonNull pointer, length, capacity)`. + /// + /// Returns the `NonNull` pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the `NonNull` pointer, length, and capacity back + /// into a `Vec` with the [`from_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_parts`]: Vec::from_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts, box_vec_non_null)] + /// + /// let v: Vec = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr.cast::(); + /// + /// Vec::from_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_parts(self) -> (NonNull, usize, usize) { + let (ptr, len, capacity) = self.into_raw_parts(); + // SAFETY: A `Vec` always has a non-null pointer. + (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) + } } impl Vec { @@ -1095,88 +1177,6 @@ impl Vec { unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } - /// Decomposes a `Vec` into its raw components: `(pointer, length, capacity)`. - /// - /// Returns the raw pointer to the underlying data, the length of - /// the vector (in elements), and the allocated capacity of the - /// data (in elements). These are the same arguments in the same - /// order as the arguments to [`from_raw_parts`]. - /// - /// After calling this function, the caller is responsible for the - /// memory previously managed by the `Vec`. The only way to do - /// this is to convert the raw pointer, length, and capacity back - /// into a `Vec` with the [`from_raw_parts`] function, allowing - /// the destructor to perform the cleanup. - /// - /// [`from_raw_parts`]: Vec::from_raw_parts - /// - /// # Examples - /// - /// ``` - /// #![feature(vec_into_raw_parts)] - /// let v: Vec = vec![-1, 0, 1]; - /// - /// let (ptr, len, cap) = v.into_raw_parts(); - /// - /// let rebuilt = unsafe { - /// // We can now make changes to the components, such as - /// // transmuting the raw pointer to a compatible type. - /// let ptr = ptr as *mut u32; - /// - /// Vec::from_raw_parts(ptr, len, cap) - /// }; - /// assert_eq!(rebuilt, [4294967295, 0, 1]); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_raw_parts(self) -> (*mut T, usize, usize) { - let mut me = ManuallyDrop::new(self); - (me.as_mut_ptr(), me.len(), me.capacity()) - } - - #[doc(alias = "into_non_null_parts")] - /// Decomposes a `Vec` into its raw components: `(NonNull pointer, length, capacity)`. - /// - /// Returns the `NonNull` pointer to the underlying data, the length of - /// the vector (in elements), and the allocated capacity of the - /// data (in elements). These are the same arguments in the same - /// order as the arguments to [`from_parts`]. - /// - /// After calling this function, the caller is responsible for the - /// memory previously managed by the `Vec`. The only way to do - /// this is to convert the `NonNull` pointer, length, and capacity back - /// into a `Vec` with the [`from_parts`] function, allowing - /// the destructor to perform the cleanup. - /// - /// [`from_parts`]: Vec::from_parts - /// - /// # Examples - /// - /// ``` - /// #![feature(vec_into_raw_parts, box_vec_non_null)] - /// - /// let v: Vec = vec![-1, 0, 1]; - /// - /// let (ptr, len, cap) = v.into_parts(); - /// - /// let rebuilt = unsafe { - /// // We can now make changes to the components, such as - /// // transmuting the raw pointer to a compatible type. - /// let ptr = ptr.cast::(); - /// - /// Vec::from_parts(ptr, len, cap) - /// }; - /// assert_eq!(rebuilt, [4294967295, 0, 1]); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] - // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_parts(self) -> (NonNull, usize, usize) { - let (ptr, len, capacity) = self.into_raw_parts(); - // SAFETY: A `Vec` always has a non-null pointer. - (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) - } - /// Decomposes a `Vec` into its raw components: `(pointer, length, capacity, allocator)`. /// /// Returns the raw pointer to the underlying data, the length of the vector (in elements), @@ -3031,6 +3031,61 @@ impl Vec { (initialized, spare, &mut self.len) } } + + /// Groups every `N` elements in the `Vec` into chunks to produce a `Vec<[T; N]>`, dropping + /// elements in the remainder. `N` must be greater than zero. + /// + /// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the + /// nearest multiple with a reallocation or deallocation. + /// + /// This function can be used to reverse [`Vec::into_flattened`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_chunks)] + /// + /// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; + /// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]); + /// + /// let vec = vec![0, 1, 2, 3]; + /// let chunks: Vec<[u8; 10]> = vec.into_chunks(); + /// assert!(chunks.is_empty()); + /// + /// let flat = vec![0; 8 * 8 * 8]; + /// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks(); + /// assert_eq!(reshaped.len(), 1); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "vec_into_chunks", issue = "142137")] + pub fn into_chunks(mut self) -> Vec<[T; N], A> { + const { + assert!(N != 0, "chunk size must be greater than zero"); + } + + let (len, cap) = (self.len(), self.capacity()); + + let len_remainder = len % N; + if len_remainder != 0 { + self.truncate(len - len_remainder); + } + + let cap_remainder = cap % N; + if !T::IS_ZST && cap_remainder != 0 { + self.buf.shrink_to_fit(cap - cap_remainder); + } + + let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc(); + + // SAFETY: + // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()` + // - `[T; N]` has the same alignment as `T` + // - `size_of::<[T; N]>() * cap / N == size_of::() * cap` + // - `len / N <= cap / N` because `len <= cap` + // - the allocated memory consists of `len / N` valid values of type `[T; N]` + // - `cap / N` fits the size of the allocated memory after shrinking + unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) } + } } impl Vec { @@ -3840,7 +3895,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for Vec { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for Vec { /// Creates an empty `Vec`. /// /// The vector will not allocate until elements are pushed onto it. diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index a41162ecd51a0..fcfc7f8dd296d 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -9,6 +9,7 @@ #![feature(downcast_unchecked)] #![feature(exact_size_is_empty)] #![feature(hashmap_internals)] +#![feature(int_format_into)] #![feature(linked_list_cursors)] #![feature(map_try_insert)] #![feature(pattern)] diff --git a/library/alloctests/tests/num.rs b/library/alloctests/tests/num.rs index a169bbec8e0c9..589b809009636 100644 --- a/library/alloctests/tests/num.rs +++ b/library/alloctests/tests/num.rs @@ -1,15 +1,21 @@ -use std::fmt::{Debug, Display}; +use core::fmt::NumBuffer; use std::str::FromStr; -fn assert_nb(value: Int) { - let s = value.to_string(); - let s2 = format!("s: {}.", value); +macro_rules! assert_nb { + ($int:ident, $value:expr) => { + let value: $int = $value; + let s = value.to_string(); + let s2 = format!("s: {}.", value); - assert_eq!(format!("s: {s}."), s2); - let Ok(ret) = Int::from_str(&s) else { - panic!("failed to convert into to string"); + assert_eq!(format!("s: {s}."), s2); + let Ok(ret) = $int::from_str(&s) else { + panic!("failed to convert into to string"); + }; + assert_eq!(ret, value); + + let mut buffer = NumBuffer::<$int>::new(); + assert_eq!(value.format_into(&mut buffer), s.as_str()); }; - assert_eq!(ret, value); } macro_rules! uint_to_s { @@ -17,11 +23,11 @@ macro_rules! uint_to_s { $( #[test] fn $fn_name() { - assert_nb::<$int>($int::MIN); - assert_nb::<$int>($int::MAX); - assert_nb::<$int>(1); - assert_nb::<$int>($int::MIN / 2); - assert_nb::<$int>($int::MAX / 2); + assert_nb!($int, $int::MIN); + assert_nb!($int, $int::MAX); + assert_nb!($int, 1); + assert_nb!($int, $int::MIN / 2); + assert_nb!($int, $int::MAX / 2); } )+ } @@ -31,13 +37,13 @@ macro_rules! int_to_s { $( #[test] fn $fn_name() { - assert_nb::<$int>($int::MIN); - assert_nb::<$int>($int::MAX); - assert_nb::<$int>(1); - assert_nb::<$int>(0); - assert_nb::<$int>(-1); - assert_nb::<$int>($int::MIN / 2); - assert_nb::<$int>($int::MAX / 2); + assert_nb!($int, $int::MIN); + assert_nb!($int, $int::MAX); + assert_nb!($int, 1); + assert_nb!($int, 0); + assert_nb!($int, -1); + assert_nb!($int, $int::MIN / 2); + assert_nb!($int, $int::MAX / 2); } )+ } diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 440a6598aa487..32cb47bf444c9 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -32,8 +32,6 @@ debug_typeid = [] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - # #[cfg(bootstrap)] loongarch32 - 'cfg(target_arch, values("loongarch32"))', 'cfg(no_fp_fmt_parse)', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index bf38a74258b2f..492a064781e41 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -71,8 +71,8 @@ impl Layout { /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow `isize` (i.e., the rounded value must be - /// less than or equal to `isize::MAX`). + /// must not overflow `isize` (i.e., the rounded value must be + /// less than or equal to `isize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index a59b2f05305d2..fdae5c08f1e8e 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -224,7 +224,7 @@ impl IntoIter { } } -#[stable(feature = "array_value_iter_default", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "array_value_iter_default", since = "1.89.0")] impl Default for IntoIter { fn default() -> Self { IntoIter::empty() diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 221ca91e005f7..16356f749c92b 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -588,7 +588,7 @@ impl [T; N] { /// Returns a mutable slice containing the entire array. Equivalent to /// `&mut s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] - #[rustc_const_stable(feature = "const_array_as_mut_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_array_as_mut_slice", since = "1.89.0")] pub const fn as_mut_slice(&mut self) -> &mut [T] { self } @@ -707,7 +707,7 @@ impl [T; N] { )] #[inline] pub fn split_array_ref(&self) -> (&[T; M], &[T]) { - (&self[..]).split_first_chunk::().unwrap() + self.split_first_chunk::().unwrap() } /// Divides one mutable array reference into two at an index. @@ -740,7 +740,7 @@ impl [T; N] { )] #[inline] pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { - (&mut self[..]).split_first_chunk_mut::().unwrap() + self.split_first_chunk_mut::().unwrap() } /// Divides one array reference into two at an index from the end. @@ -785,7 +785,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { - (&self[..]).split_last_chunk::().unwrap() + self.split_last_chunk::().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -818,7 +818,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { - (&mut self[..]).split_last_chunk_mut::().unwrap() + self.split_last_chunk_mut::().unwrap() } } diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index 2016ece007eba..99268d6182f6c 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -61,4 +61,71 @@ impl bool { pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } } + + /// Returns `Ok(())` if the `bool` is [`true`](../std/keyword.true.html), + /// or `Err(err)` otherwise. + /// + /// Arguments passed to `ok_or` are eagerly evaluated; if you are + /// passing the result of a function call, it is recommended to use + /// [`ok_or_else`], which is lazily evaluated. + /// + /// [`ok_or_else`]: bool::ok_or_else + /// + /// # Examples + /// + /// ``` + /// #![feature(bool_to_result)] + /// + /// assert_eq!(false.ok_or(0), Err(0)); + /// assert_eq!(true.ok_or(0), Ok(())); + /// ``` + /// + /// ``` + /// #![feature(bool_to_result)] + /// + /// let mut a = 0; + /// let mut function_with_side_effects = || { a += 1; }; + /// + /// assert!(true.ok_or(function_with_side_effects()).is_ok()); + /// assert!(false.ok_or(function_with_side_effects()).is_err()); + /// + /// // `a` is incremented twice because the value passed to `ok_or` is + /// // evaluated eagerly. + /// assert_eq!(a, 2); + /// ``` + #[unstable(feature = "bool_to_result", issue = "142748")] + #[inline] + pub fn ok_or(self, err: E) -> Result<(), E> { + if self { Ok(()) } else { Err(err) } + } + + /// Returns `Ok(())` if the `bool` is [`true`](../std/keyword.true.html), + /// or `Err(f())` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(bool_to_result)] + /// + /// assert_eq!(false.ok_or_else(|| 0), Err(0)); + /// assert_eq!(true.ok_or_else(|| 0), Ok(())); + /// ``` + /// + /// ``` + /// #![feature(bool_to_result)] + /// + /// let mut a = 0; + /// + /// assert!(true.ok_or_else(|| { a += 1; }).is_ok()); + /// assert!(false.ok_or_else(|| { a += 1; }).is_err()); + /// + /// // `a` is incremented once because the closure is evaluated lazily by + /// // `ok_or_else`. + /// assert_eq!(a, 1); + /// ``` + #[unstable(feature = "bool_to_result", issue = "142748")] + #[inline] + pub fn ok_or_else E>(self, f: F) -> Result<(), E> { + if self { Ok(()) } else { Err(f()) } + } } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7ce03e3d83198..c53a2b2beb4cc 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -252,7 +252,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; -use crate::marker::{PhantomData, PointerLike, Unsize}; +use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::panic::const_panic; @@ -333,7 +333,8 @@ impl Clone for Cell { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for Cell { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for Cell { /// Creates a `Cell`, with the `Default` value for T. #[inline] fn default() -> Cell { @@ -669,9 +670,6 @@ impl, U> CoerceUnsized> for Cell {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U> DispatchFromDyn> for Cell {} -#[unstable(feature = "pointer_like_trait", issue = "none")] -impl PointerLike for Cell {} - impl Cell<[T]> { /// Returns a `&[Cell]` from a `&Cell<[T]>` /// @@ -1326,7 +1324,8 @@ impl Clone for RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for RefCell { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for RefCell { /// Creates a `RefCell`, with the `Default` value for T. #[inline] fn default() -> RefCell { @@ -1941,21 +1940,21 @@ impl fmt::Display for RefMut<'_, T> { /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// /// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference), then -/// you must not access the data in any way that contradicts that reference for the remainder of -/// `'a`. For example, this means that if you take the `*mut T` from an `UnsafeCell` and cast it -/// to an `&T`, then the data in `T` must remain immutable (modulo any `UnsafeCell` data found -/// within `T`, of course) until that reference's lifetime expires. Similarly, if you create a `&mut -/// T` reference that is released to safe code, then you must not access the data within the -/// `UnsafeCell` until that reference expires. +/// you must not access the data in any way that contradicts that reference for the remainder of +/// `'a`. For example, this means that if you take the `*mut T` from an `UnsafeCell` and cast it +/// to an `&T`, then the data in `T` must remain immutable (modulo any `UnsafeCell` data found +/// within `T`, of course) until that reference's lifetime expires. Similarly, if you create a +/// `&mut T` reference that is released to safe code, then you must not access the data within the +/// `UnsafeCell` until that reference expires. /// /// - For both `&T` without `UnsafeCell<_>` and `&mut T`, you must also not deallocate the data -/// until the reference expires. As a special exception, given an `&T`, any part of it that is -/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the -/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part -/// of what a reference points to, this means the memory an `&T` points to can be deallocated only if -/// *every part of it* (including padding) is inside an `UnsafeCell`. +/// until the reference expires. As a special exception, given an `&T`, any part of it that is +/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the +/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part +/// of what a reference points to, this means the memory an `&T` points to can be deallocated only if +/// *every part of it* (including padding) is inside an `UnsafeCell`. /// -/// However, whenever a `&UnsafeCell` is constructed or dereferenced, it must still point to +/// However, whenever a `&UnsafeCell` is constructed or dereferenced, it must still point to /// live memory and the compiler is allowed to insert spurious reads if it can prove that this /// memory has not yet been deallocated. /// @@ -1963,10 +1962,10 @@ impl fmt::Display for RefMut<'_, T> { /// for single-threaded code: /// /// 1. A `&T` reference can be released to safe code and there it can co-exist with other `&T` -/// references, but not with a `&mut T` +/// references, but not with a `&mut T` /// /// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T` -/// co-exist with it. A `&mut T` must always be unique. +/// co-exist with it. A `&mut T` must always be unique. /// /// Note that whilst mutating the contents of an `&UnsafeCell` (even while other /// `&UnsafeCell` references alias the cell) is @@ -2333,7 +2332,8 @@ impl UnsafeCell { } #[stable(feature = "unsafe_cell_default", since = "1.10.0")] -impl Default for UnsafeCell { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for UnsafeCell { /// Creates an `UnsafeCell`, with the `Default` value for T. fn default() -> UnsafeCell { UnsafeCell::new(Default::default()) @@ -2361,9 +2361,6 @@ impl, U> CoerceUnsized> for UnsafeCell {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U> DispatchFromDyn> for UnsafeCell {} -#[unstable(feature = "pointer_like_trait", issue = "none")] -impl PointerLike for UnsafeCell {} - /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` @@ -2440,7 +2437,8 @@ impl SyncUnsafeCell { } #[unstable(feature = "sync_unsafe_cell", issue = "95439")] -impl Default for SyncUnsafeCell { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for SyncUnsafeCell { /// Creates an `SyncUnsafeCell`, with the `Default` value for T. fn default() -> SyncUnsafeCell { SyncUnsafeCell::new(Default::default()) @@ -2470,9 +2468,6 @@ impl, U> CoerceUnsized> for SyncUnsafeCell //#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl, U> DispatchFromDyn> for SyncUnsafeCell {} -#[unstable(feature = "pointer_like_trait", issue = "none")] -impl PointerLike for SyncUnsafeCell {} - #[allow(unused)] fn assert_coerce_unsized( a: UnsafeCell<&i32>, diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 0b2a2ce7ded04..1758e84ad7cdf 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -284,7 +284,7 @@ impl T> Deref for LazyCell { } } -#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "lazy_deref_mut", since = "1.89.0")] impl T> DerefMut for LazyCell { #[inline] fn deref_mut(&mut self) -> &mut T { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0aa8f47462dbd..b1ca3701fa5ae 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1449,7 +1449,6 @@ pub trait PartialOrd: PartialEq + PointeeSized { /// check `==` and `<` separately to do rather than needing to calculate /// (then optimize out) the three-way `Ordering` result. #[inline] - #[must_use] // Added to improve the behaviour of tuples; not necessarily stabilization-track. #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] #[doc(hidden)] @@ -1459,7 +1458,6 @@ pub trait PartialOrd: PartialEq + PointeeSized { /// Same as `__chaining_lt`, but for `<=` instead of `<`. #[inline] - #[must_use] #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] #[doc(hidden)] fn __chaining_le(&self, other: &Rhs) -> ControlFlow { @@ -1468,7 +1466,6 @@ pub trait PartialOrd: PartialEq + PointeeSized { /// Same as `__chaining_lt`, but for `>` instead of `<`. #[inline] - #[must_use] #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] #[doc(hidden)] fn __chaining_gt(&self, other: &Rhs) -> ControlFlow { @@ -1477,7 +1474,6 @@ pub trait PartialOrd: PartialEq + PointeeSized { /// Same as `__chaining_lt`, but for `>=` instead of `<`. #[inline] - #[must_use] #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] #[doc(hidden)] fn __chaining_ge(&self, other: &Rhs) -> ControlFlow { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 0a15cedfb552d..4d108b0c18ed3 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -103,6 +103,8 @@ use crate::ascii::Char as AsciiChar; /// ``` #[rustc_diagnostic_item = "Default"] #[stable(feature = "rust1", since = "1.0.0")] +#[const_trait] +#[rustc_const_unstable(feature = "const_default", issue = "67792")] pub trait Default: Sized { /// Returns the "default value" for a type. /// @@ -149,7 +151,8 @@ pub macro Default($item:item) { macro_rules! default_impl { ($t:ty, $v:expr, $doc:tt) => { #[stable(feature = "rust1", since = "1.0.0")] - impl Default for $t { + #[rustc_const_unstable(feature = "const_default", issue = "67792")] + impl const Default for $t { #[inline(always)] #[doc = $doc] fn default() -> $t { diff --git a/library/core/src/error.rs b/library/core/src/error.rs index bfa392003b91b..88e633c9eef3f 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -347,7 +347,7 @@ impl dyn Error { /// let b = B(Some(Box::new(A))); /// /// // let err : Box = b.into(); // or - /// let err = &b as &(dyn Error); + /// let err = &b as &dyn Error; /// /// let mut iter = err.sources(); /// @@ -447,28 +447,28 @@ where /// separated by API boundaries: /// /// * Consumer - the consumer requests objects using a Request instance; eg a crate that offers -/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`. +/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`. /// /// * Producer - the producer provides objects when requested via Request; eg. a library with an -/// an `Error` implementation that automatically captures backtraces at the time instances are -/// created. +/// an `Error` implementation that automatically captures backtraces at the time instances are +/// created. /// /// The consumer only needs to know where to submit their request and are expected to handle the /// request not being fulfilled by the use of `Option` in the responses offered by the producer. /// /// * A Producer initializes the value of one of its fields of a specific type. (or is otherwise -/// prepared to generate a value requested). eg, `backtrace::Backtrace` or -/// `std::backtrace::Backtrace` +/// prepared to generate a value requested). eg, `backtrace::Backtrace` or +/// `std::backtrace::Backtrace` /// * A Consumer requests an object of a specific type (say `std::backtrace::Backtrace`). In the -/// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and -/// `request_value` to simplify obtaining an `Option` for a given type. +/// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and +/// `request_value` to simplify obtaining an `Option` for a given type. /// * The Producer, when requested, populates the given Request object which is given as a mutable -/// reference. +/// reference. /// * The Consumer extracts a value or reference to the requested type from the `Request` object -/// wrapped in an `Option`; in the case of `dyn Error` the aforementioned `request_ref` and ` -/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at -/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the -/// Producer cannot currently offer an instance of the requested type, not it can't or never will. +/// wrapped in an `Option`; in the case of `dyn Error` the aforementioned `request_ref` and ` +/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at +/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the +/// Producer cannot currently offer an instance of the requested type, not it can't or never will. /// /// # Examples /// diff --git a/library/core/src/ffi/c_char.md b/library/core/src/ffi/c_char.md index b262a3663b3c1..119b739a39e72 100644 --- a/library/core/src/ffi/c_char.md +++ b/library/core/src/ffi/c_char.md @@ -1,6 +1,6 @@ Equivalent to C's `char` type. -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes. +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addressed memory with 8-bit bytes. C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See `CStr` for more information. diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 8f7c090bc1ba2..88ad11977774d 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -5,6 +5,7 @@ use crate::ffi::c_void; #[allow(unused_imports)] use crate::fmt; +use crate::intrinsics::{va_arg, va_copy, va_end}; use crate::marker::{PhantomData, PhantomInvariantLifetime}; use crate::ops::{Deref, DerefMut}; @@ -280,20 +281,3 @@ impl<'f> Drop for VaListImpl<'f> { // This works for now, since `va_end` is a no-op on all current LLVM targets. } } - -/// Destroy the arglist `ap` after initialization with `va_start` or -/// `va_copy`. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_end(ap: &mut VaListImpl<'_>); - -/// Copies the current location of arglist `src` to the arglist `dst`. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); - -/// Loads an argument of type `T` from the `va_list` `ap` and increment the -/// argument `ap` points to. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 2be8d37bbee67..228a331e1da4d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -15,6 +15,7 @@ mod float; #[cfg(no_fp_fmt_parse)] mod nofloat; mod num; +mod num_buffer; mod rt; #[stable(feature = "fmt_flags_align", since = "1.28.0")] @@ -33,6 +34,9 @@ pub enum Alignment { Center, } +#[unstable(feature = "int_format_into", issue = "138215")] +pub use num_buffer::{NumBuffer, NumBufferTrait}; + #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[unstable(feature = "debug_closure_helpers", issue = "117729")] @@ -349,10 +353,10 @@ impl FormattingOptions { /// Sets or removes the sign (the `+` or the `-` flag). /// /// - `+`: This is intended for numeric types and indicates that the sign - /// should always be printed. By default only the negative sign of signed - /// values is printed, and the sign of positive or unsigned values is - /// omitted. This flag indicates that the correct sign (+ or -) should - /// always be printed. + /// should always be printed. By default only the negative sign of signed + /// values is printed, and the sign of positive or unsigned values is + /// omitted. This flag indicates that the correct sign (+ or -) should + /// always be printed. /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub fn sign(&mut self, sign: Option) -> &mut Self { @@ -439,9 +443,9 @@ impl FormattingOptions { /// Sets or removes the precision. /// /// - For non-numeric types, this can be considered a “maximum width”. If - /// the resulting string is longer than this width, then it is truncated - /// down to this many characters and that truncated value is emitted with - /// proper fill, alignment and width if those parameters are set. + /// the resulting string is longer than this width, then it is truncated + /// down to this many characters and that truncated value is emitted with + /// proper fill, alignment and width if those parameters are set. /// - For integral types, this is ignored. /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. @@ -2867,7 +2871,7 @@ macro_rules! tuple { maybe_tuple_doc! { $($name)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized { + impl<$($name:Debug),+> Debug for ($($name,)+) { #[allow(non_snake_case, unused_assignments)] fn fmt(&self, f: &mut Formatter<'_>) -> Result { let mut builder = f.debug_tuple(""); @@ -2898,11 +2902,6 @@ macro_rules! maybe_tuple_doc { }; } -macro_rules! last_type { - ($a:ident,) => { $a }; - ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; -} - tuple! { E, D, C, B, A, Z, Y, X, W, V, U, T, } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 42af595ae4170..e1381ace44151 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -1,5 +1,6 @@ //! Integer and floating-point number formatting +use crate::fmt::NumBuffer; use crate::mem::MaybeUninit; use crate::num::fmt as numfmt; use crate::ops::{Div, Rem, Sub}; @@ -60,7 +61,7 @@ unsafe trait GenericRadix: Sized { let zero = T::zero(); let is_nonnegative = x >= zero; let mut buf = [MaybeUninit::::uninit(); 128]; - let mut curr = buf.len(); + let mut offset = buf.len(); let base = T::from_u8(Self::BASE); if is_nonnegative { // Accumulate each digit of the number from the least significant @@ -68,8 +69,8 @@ unsafe trait GenericRadix: Sized { loop { let n = x % base; // Get the current place value. x = x / base; // Deaccumulate the number. - curr -= 1; - buf[curr].write(Self::digit(n.to_u8())); // Store the digit in the buffer. + offset -= 1; + buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer. if x == zero { // No more digits left to accumulate. break; @@ -80,27 +81,17 @@ unsafe trait GenericRadix: Sized { loop { let n = zero - (x % base); // Get the current place value. x = x / base; // Deaccumulate the number. - curr -= 1; - buf[curr].write(Self::digit(n.to_u8())); // Store the digit in the buffer. + offset -= 1; + buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer. if x == zero { // No more digits left to accumulate. break; }; } } - // SAFETY: `curr` is initialized to `buf.len()` and is only decremented, so it can't overflow. It is - // decremented exactly once for each digit. Since u128 is the widest fixed width integer format supported, - // the maximum number of digits (bits) is 128 for base-2, so `curr` won't underflow as well. - let buf = unsafe { buf.get_unchecked(curr..) }; - // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be - // valid UTF-8 - let buf = unsafe { - str::from_utf8_unchecked(slice::from_raw_parts( - MaybeUninit::slice_as_ptr(buf), - buf.len(), - )) - }; - f.pad_integral(is_nonnegative, Self::PREFIX, buf) + // SAFETY: Starting from `offset`, all elements of the slice have been set. + let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) }; + f.pad_integral(is_nonnegative, Self::PREFIX, buf_slice) } } @@ -199,6 +190,20 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; +/// This function converts a slice of ascii characters into a `&str` starting from `offset`. +/// +/// # Safety +/// +/// `buf` content starting from `offset` index MUST BE initialized and MUST BE ascii +/// characters. +unsafe fn slice_buffer_to_str(buf: &[MaybeUninit], offset: usize) -> &str { + // SAFETY: `offset` is always included between 0 and `buf`'s length. + let written = unsafe { buf.get_unchecked(offset..) }; + // SAFETY: (`assume_init_ref`) All buf content since offset is set. + // SAFETY: (`from_utf8_unchecked`) Writes use ASCII from the lookup table exclusively. + unsafe { str::from_utf8_unchecked(written.assume_init_ref()) } +} + macro_rules! impl_Display { ($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { @@ -212,7 +217,8 @@ macro_rules! impl_Display { // Buffer decimals for $unsigned with right alignment. let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; - f.pad_integral(true, "", self._fmt(&mut buf)) + // SAFETY: `buf` is always big enough to contain all the digits. + unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) } } #[cfg(feature = "optimize_for_size")] { @@ -230,7 +236,8 @@ macro_rules! impl_Display { // Buffer decimals for $unsigned with right alignment. let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; - f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) + // SAFETY: `buf` is always big enough to contain all the digits. + unsafe { f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) } } #[cfg(feature = "optimize_for_size")] { @@ -247,7 +254,14 @@ macro_rules! impl_Display { reason = "specialized method meant to only be used by `SpecToString` implementation", issue = "none" )] - pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::]) -> &'a str { + pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::]) -> &'a str { + // SAFETY: `buf` will always be big enough to contain all digits. + let offset = unsafe { self._fmt_inner(buf) }; + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(buf, offset) } + } + + unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit::]) -> usize { // Count the number of bytes in buf that are not initialized. let mut offset = buf.len(); // Consume the least-significant decimals from a working copy. @@ -309,47 +323,123 @@ macro_rules! impl_Display { // not used: remain = 0; } - // SAFETY: All buf content since offset is set. - let written = unsafe { buf.get_unchecked(offset..) }; - // SAFETY: Writes use ASCII from the lookup table exclusively. + offset + } + } + + impl $signed { + /// Allows users to write an integer (in signed decimal format) into a variable `buf` of + /// type [`NumBuffer`] that is passed by the caller by mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_format_into)] + /// use core::fmt::NumBuffer; + /// + #[doc = concat!("let n = 0", stringify!($signed), ";")] + /// let mut buf = NumBuffer::new(); + /// assert_eq!(n.format_into(&mut buf), "0"); + /// + #[doc = concat!("let n1 = 32", stringify!($signed), ";")] + /// assert_eq!(n1.format_into(&mut buf), "32"); + /// + #[doc = concat!("let n2 = ", stringify!($signed::MAX), ";")] + #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($signed::MAX), ".to_string());")] + /// ``` + #[unstable(feature = "int_format_into", issue = "138215")] + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + let mut offset; + + #[cfg(not(feature = "optimize_for_size"))] + // SAFETY: `buf` will always be big enough to contain all digits. unsafe { - str::from_utf8_unchecked(slice::from_raw_parts( - MaybeUninit::slice_as_ptr(written), - written.len(), - )) + offset = self.unsigned_abs()._fmt_inner(&mut buf.buf); } + #[cfg(feature = "optimize_for_size")] + { + offset = _inner_slow_integer_to_str(self.unsigned_abs().$conv_fn(), &mut buf.buf); + } + // Only difference between signed and unsigned are these 4 lines. + if self < 0 { + offset -= 1; + buf.buf[offset].write(b'-'); + } + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(&buf.buf, offset) } } - })* + } + + impl $unsigned { + /// Allows users to write an integer (in signed decimal format) into a variable `buf` of + /// type [`NumBuffer`] that is passed by the caller by mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_format_into)] + /// use core::fmt::NumBuffer; + /// + #[doc = concat!("let n = 0", stringify!($unsigned), ";")] + /// let mut buf = NumBuffer::new(); + /// assert_eq!(n.format_into(&mut buf), "0"); + /// + #[doc = concat!("let n1 = 32", stringify!($unsigned), ";")] + /// assert_eq!(n1.format_into(&mut buf), "32"); + /// + #[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")] + #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($unsigned::MAX), ".to_string());")] + /// ``` + #[unstable(feature = "int_format_into", issue = "138215")] + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + let offset; + + #[cfg(not(feature = "optimize_for_size"))] + // SAFETY: `buf` will always be big enough to contain all digits. + unsafe { + offset = self._fmt_inner(&mut buf.buf); + } + #[cfg(feature = "optimize_for_size")] + { + offset = _inner_slow_integer_to_str(self.$conv_fn(), &mut buf.buf); + } + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(&buf.buf, offset) } + } + } + + + )* #[cfg(feature = "optimize_for_size")] - fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const MAX_DEC_N: usize = $u::MAX.ilog10() as usize + 1; - let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; - let mut curr = MAX_DEC_N; - let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); + fn _inner_slow_integer_to_str(mut n: $u, buf: &mut [MaybeUninit::]) -> usize { + let mut curr = buf.len(); // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at // each step this is kept the same as `n` is divided. Since `n` is always // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` // is safe to access. - unsafe { - loop { - curr -= 1; - buf_ptr.add(curr).write((n % 10) as u8 + b'0'); - n /= 10; + loop { + curr -= 1; + buf[curr].write((n % 10) as u8 + b'0'); + n /= 10; - if n == 0 { - break; - } + if n == 0 { + break; } } + curr + } - // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid UTF-8 - let buf_slice = unsafe { - str::from_utf8_unchecked( - slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) - }; + #[cfg(feature = "optimize_for_size")] + fn $gen_name(n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + + let offset = _inner_slow_integer_to_str(n, &mut buf); + // SAFETY: Starting from `offset`, all elements of the slice have been set. + let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) }; f.pad_integral(is_nonnegative, "", buf_slice) } }; @@ -572,7 +662,8 @@ impl fmt::Display for u128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut buf = [MaybeUninit::::uninit(); U128_MAX_DEC_N]; - f.pad_integral(true, "", self._fmt(&mut buf)) + // SAFETY: `buf` is always big enough to contain all the digits. + unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) } } } @@ -584,12 +675,13 @@ impl fmt::Display for i128 { let mut buf = [MaybeUninit::::uninit(); U128_MAX_DEC_N]; let is_nonnegative = *self >= 0; - f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) + // SAFETY: `buf` is always big enough to contain all the digits. + unsafe { f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) } } } impl u128 { - /// Format optimized for u128. Computation of 128 bits is limited by proccessing + /// Format optimized for u128. Computation of 128 bits is limited by processing /// in batches of 16 decimals at a time. #[doc(hidden)] #[unstable( @@ -597,13 +689,21 @@ impl u128 { reason = "specialized method meant to only be used by `SpecToString` implementation", issue = "none" )] - pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit]) -> &'a str { + pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit]) -> &'a str { + // SAFETY: `buf` will always be big enough to contain all digits. + let offset = unsafe { self._fmt_inner(buf) }; + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(buf, offset) } + } + + unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit]) -> usize { // Optimize common-case zero, which would also need special treatment due to // its "leading" zero. if self == 0 { - return "0"; + let offset = buf.len() - 1; + buf[offset].write(b'0'); + return offset; } - // Take the 16 least-significant decimals. let (quot_1e16, mod_1e16) = div_rem_1e16(self); let (mut remain, mut offset) = if quot_1e16 == 0 { @@ -677,16 +777,86 @@ impl u128 { buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]); // not used: remain = 0; } + offset + } + + /// Allows users to write an integer (in signed decimal format) into a variable `buf` of + /// type [`NumBuffer`] that is passed by the caller by mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_format_into)] + /// use core::fmt::NumBuffer; + /// + /// let n = 0u128; + /// let mut buf = NumBuffer::new(); + /// assert_eq!(n.format_into(&mut buf), "0"); + /// + /// let n1 = 32u128; + /// let mut buf1 = NumBuffer::new(); + /// assert_eq!(n1.format_into(&mut buf1), "32"); + /// + /// let n2 = u128::MAX; + /// let mut buf2 = NumBuffer::new(); + /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string()); + /// ``` + #[unstable(feature = "int_format_into", issue = "138215")] + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + let diff = buf.capacity() - U128_MAX_DEC_N; + // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const + // for `fmt_u128_inner`. + // + // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned + // offset to ensure the number is correctly generated at the end of the buffer. + // SAFETY: `diff` will always be between 0 and its initial value. + unsafe { self._fmt(buf.buf.get_unchecked_mut(diff..)) } + } +} - // SAFETY: All buf content since offset is set. - let written = unsafe { buf.get_unchecked(offset..) }; - // SAFETY: Writes use ASCII from the lookup table exclusively. - unsafe { - str::from_utf8_unchecked(slice::from_raw_parts( - MaybeUninit::slice_as_ptr(written), - written.len(), - )) +impl i128 { + /// Allows users to write an integer (in signed decimal format) into a variable `buf` of + /// type [`NumBuffer`] that is passed by the caller by mutable reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_format_into)] + /// use core::fmt::NumBuffer; + /// + /// let n = 0i128; + /// let mut buf = NumBuffer::new(); + /// assert_eq!(n.format_into(&mut buf), "0"); + /// + /// let n1 = i128::MIN; + /// assert_eq!(n1.format_into(&mut buf), i128::MIN.to_string()); + /// + /// let n2 = i128::MAX; + /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string()); + /// ``` + #[unstable(feature = "int_format_into", issue = "138215")] + pub fn format_into(self, buf: &mut NumBuffer) -> &str { + let diff = buf.capacity() - U128_MAX_DEC_N; + // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const + // for `fmt_u128_inner`. + // + // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned + // offset to ensure the number is correctly generated at the end of the buffer. + let mut offset = + // SAFETY: `buf` will always be big enough to contain all digits. + unsafe { self.unsigned_abs()._fmt_inner(buf.buf.get_unchecked_mut(diff..)) }; + // We put back the offset at the right position. + offset += diff; + // Only difference between signed and unsigned are these 4 lines. + if self < 0 { + offset -= 1; + // SAFETY: `buf` will always be big enough to contain all digits plus the minus sign. + unsafe { + buf.buf.get_unchecked_mut(offset).write(b'-'); + } } + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(&buf.buf, offset) } } } diff --git a/library/core/src/fmt/num_buffer.rs b/library/core/src/fmt/num_buffer.rs new file mode 100644 index 0000000000000..474a8d20ef6c5 --- /dev/null +++ b/library/core/src/fmt/num_buffer.rs @@ -0,0 +1,60 @@ +use crate::mem::MaybeUninit; + +/// Trait used to describe the maximum number of digits in decimal base of the implemented integer. +#[unstable(feature = "int_format_into", issue = "138215")] +pub trait NumBufferTrait { + /// Maximum number of digits in decimal base of the implemented integer. + const BUF_SIZE: usize; +} + +macro_rules! impl_NumBufferTrait { + ($($signed:ident, $unsigned:ident,)*) => { + $( + #[unstable(feature = "int_format_into", issue = "138215")] + impl NumBufferTrait for $signed { + // `+ 2` and not `+ 1` to include the `-` character. + const BUF_SIZE: usize = $signed::MAX.ilog(10) as usize + 2; + } + #[unstable(feature = "int_format_into", issue = "138215")] + impl NumBufferTrait for $unsigned { + const BUF_SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; + } + )* + } +} + +impl_NumBufferTrait! { + i8, u8, + i16, u16, + i32, u32, + i64, u64, + isize, usize, + i128, u128, +} + +/// A buffer wrapper of which the internal size is based on the maximum +/// number of digits the associated integer can have. +#[unstable(feature = "int_format_into", issue = "138215")] +#[derive(Debug)] +pub struct NumBuffer { + // FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40. + pub(crate) buf: [MaybeUninit; 40], + // FIXME: Remove this field once we can actually use `T`. + phantom: core::marker::PhantomData, +} + +#[unstable(feature = "int_format_into", issue = "138215")] +impl NumBuffer { + /// Initializes internal buffer. + #[unstable(feature = "int_format_into", issue = "138215")] + pub const fn new() -> Self { + // FIXME: Once const generics feature is working, use `T::BUF_SIZE` instead of 40. + NumBuffer { buf: [MaybeUninit::::uninit(); 40], phantom: core::marker::PhantomData } + } + + /// Returns the length of the internal buffer. + #[unstable(feature = "int_format_into", issue = "138215")] + pub const fn capacity(&self) -> usize { + self.buf.len() + } +} diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index efda64791d403..a10c85640bbb6 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -886,7 +886,7 @@ mod impls { maybe_tuple_doc! { $($name)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized { + impl<$($name: Hash),+> Hash for ($($name,)+) { #[allow(non_snake_case)] #[inline] fn hash(&self, state: &mut S) { @@ -912,11 +912,6 @@ mod impls { }; } - macro_rules! last_type { - ($a:ident,) => { $a }; - ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; - } - impl_hash_tuple! {} impl_hash_tuple! { T } impl_hash_tuple! { T B } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 269857cbc7b97..d9da32707298c 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -56,6 +56,7 @@ use safety::{ensures, requires}; +use crate::ffi::va_list::{VaArgSafe, VaListImpl}; #[cfg(kani)] use crate::kani; use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; @@ -465,7 +466,7 @@ pub const fn unlikely(b: bool) -> bool { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The public form of this instrinsic is [`core::hint::select_unpredictable`]. +/// The public form of this intrinsic is [`core::hint::select_unpredictable`]. /// However unlike the public form, the intrinsic will not drop the value that /// is not selected. #[unstable(feature = "core_intrinsics", issue = "none")] @@ -478,7 +479,8 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { } /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: -/// This will statically either panic, or do nothing. +/// This will statically either panic, or do nothing. It does not *guarantee* to ever panic, +/// and should only be called if an assertion failure will imply language UB in the following code. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic_const_stable_indirect] @@ -487,7 +489,9 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { pub const fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit -/// zero-initialization: This will statically either panic, or do nothing. +/// zero-initialization: This will statically either panic, or do nothing. It does not *guarantee* +/// to ever panic, and should only be called if an assertion failure will imply language UB in the +/// following code. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic_const_stable_indirect] @@ -495,7 +499,9 @@ pub const fn assert_inhabited(); #[rustc_intrinsic] pub const fn assert_zero_valid(); -/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. +/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. It does +/// not *guarantee* to ever panic, and should only be called if an assertion failure will imply +/// language UB in the following code. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic_const_stable_indirect] @@ -2296,7 +2302,7 @@ where /// used inside the `if const`. /// Note that the two arms of this `if` really each become their own function, which is why the /// macro supports setting attributes for those functions. The runtime function is always -/// markes as `#[inline]`. +/// marked as `#[inline]`. /// /// See [`const_eval_select()`] for the rules and requirements around that intrinsic. pub(crate) macro const_eval_select { @@ -2543,7 +2549,7 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) /// Returns whether we should perform contract-checking at runtime. /// /// This is meant to be similar to the ub_checks intrinsic, in terms -/// of not prematurely commiting at compile-time to whether contract +/// of not prematurely committing at compile-time to whether contract /// checking is turned on, so that we can specify contracts in libstd /// and let an end user opt into turning them on. #[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] @@ -3217,6 +3223,28 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize ) } +/// Copies the current location of arglist `src` to the arglist `dst`. +/// +/// FIXME: document safety requirements +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); + +/// Loads an argument of type `T` from the `va_list` `ap` and increment the +/// argument `ap` points to. +/// +/// FIXME: document safety requirements +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; + +/// Destroy the arglist `ap` after initialization with `va_start` or `va_copy`. +/// +/// FIXME: document safety requirements +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn va_end(ap: &mut VaListImpl<'_>); + #[cfg(kani)] #[unstable(feature = "kani", issue = "none")] mod verify { diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 11533ab6aa498..19488082cc33d 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -160,7 +160,7 @@ pub unsafe fn simd_funnel_shl(a: T, b: T, shift: T) -> T; #[rustc_nounwind] pub unsafe fn simd_funnel_shr(a: T, b: T, shift: T) -> T; -/// "Ands" vectors elementwise. +/// "And"s vectors elementwise. /// /// `T` must be a vector of integers. #[rustc_intrinsic] @@ -522,7 +522,7 @@ pub unsafe fn simd_reduce_max(x: T) -> U; #[rustc_nounwind] pub unsafe fn simd_reduce_min(x: T) -> U; -/// Logical "ands" all elements together. +/// Logical "and"s all elements together. /// /// `T` must be a vector of integers or floats. /// diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 6bd9c18e00bdf..854e03cf18279 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -281,7 +281,7 @@ impl<'a> BorrowedCursor<'a> { /// Panics if there are less than `n` bytes initialized. #[inline] pub fn advance(&mut self, n: usize) -> &mut Self { - // The substraction cannot underflow by invariant of this type. + // The subtraction cannot underflow by invariant of this type. assert!(n <= self.buf.init - self.buf.filled); self.buf.filled += n; diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs index 3c3acceded889..309962ab70ce1 100644 --- a/library/core/src/iter/sources/empty.rs +++ b/library/core/src/iter/sources/empty.rs @@ -81,7 +81,8 @@ impl Clone for Empty { // not #[derive] because that adds a Default bound on T, // which isn't necessary. #[stable(feature = "iter_empty", since = "1.2.0")] -impl Default for Empty { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for Empty { fn default() -> Empty { Empty(marker::PhantomData) } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 815e189621566..f51fea6c61ca6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -89,7 +89,7 @@ #![allow(internal_features)] #![deny(ffi_unwind_calls)] #![warn(unreachable_pub)] -// Do not check link redundancy on bootstraping phase +// Do not check link redundancy on bootstrapping phase #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] // diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 0cc5640941a32..1c0629f259db2 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -19,6 +19,9 @@ use crate::fmt::Debug; use crate::hash::{Hash, Hasher}; use crate::pin::UnsafePinned; +// NOTE: for consistent error messages between `core` and `minicore`, all `diagnostic` attributes +// should be replicated exactly in `minicore` (if `minicore` defines the item). + /// Implements a given marker trait for multiple types at the same time. /// /// The basic syntax looks like this: @@ -208,8 +211,8 @@ pub trait PointeeSized { /// - The type is sized. /// - The type outlives `'a`. /// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize>` -/// where any number of (type and const) parameters may be changed if all of these conditions -/// are met: +/// where any number of (type and const) parameters may be changed if all of these conditions +/// are met: /// - Only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`. /// - All other parameters of the struct are equal. /// - `Field: Unsize>`, where `Field<...>` stands for the actual @@ -855,7 +858,8 @@ impl Clone for PhantomData { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for PhantomData { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for PhantomData { fn default() -> Self { Self } @@ -1063,37 +1067,6 @@ pub trait Destruct {} #[rustc_do_not_implement_via_object] pub trait Tuple {} -/// A marker for pointer-like types. -/// -/// This trait can only be implemented for types that are certain to have -/// the same size and alignment as a [`usize`] or [`*const ()`](pointer). -/// To ensure this, there are special requirements on implementations -/// of `PointerLike` (other than the already-provided implementations -/// for built-in types): -/// -/// * The type must have `#[repr(transparent)]`. -/// * The type’s sole non-zero-sized field must itself implement `PointerLike`. -#[unstable(feature = "pointer_like_trait", issue = "none")] -#[lang = "pointer_like"] -#[diagnostic::on_unimplemented( - message = "`{Self}` needs to have the same ABI as a pointer", - label = "`{Self}` needs to be a pointer-like type" -)] -#[rustc_do_not_implement_via_object] -pub trait PointerLike {} - -marker_impls! { - #[unstable(feature = "pointer_like_trait", issue = "none")] - PointerLike for - isize, - usize, - {T} &T, - {T} &mut T, - {T} *const T, - {T} *mut T, - {T: PointerLike} crate::pin::Pin, -} - /// A marker for types which can be used as types of `const` generic parameters. /// /// These types must have a proper equivalence relation (`Eq`) and it must be automatically diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 63a479ed8dd4e..fc35e54bb0dcc 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -616,7 +616,9 @@ impl MaybeUninit { // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - ManuallyDrop::into_inner(self.value) + // We do this via a raw ptr read instead of `ManuallyDrop::into_inner` so that there's + // no trace of `ManuallyDrop` in Miri's error messages here. + (&raw const self.value).cast::().read() } } diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs index 5bf0faf0bc910..21aabdc8addb4 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/dec2flt/float.rs @@ -109,7 +109,7 @@ pub trait RawFloat: /// Round-to-even only happens for negative values of q /// when q ≥ −4 in the 64-bit case and when q ≥ −17 in - /// the 32-bitcase. + /// the 32-bit case. /// /// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we /// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have @@ -119,7 +119,7 @@ pub trait RawFloat: /// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case) /// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64 /// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11 - /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase). + /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bit case). /// /// Thus we have that we only need to round ties to even when /// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10] @@ -143,7 +143,7 @@ pub trait RawFloat: /// smaller than `10^SMALLEST_POWER_OF_TEN`, which will round to zero. /// /// The smallest power of ten is represented by `⌊log10(2^-n / (2^64 - 1))⌋`, where `n` is - /// the smallest power of two. The `2^64 - 1)` denomenator comes from the number of values + /// the smallest power of two. The `2^64 - 1)` denominator comes from the number of values /// that are representable by the intermediate storage format. I don't actually know _why_ /// the storage format is relevant here. /// diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 6ef2fdd14c149..a5242d60bf14d 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -79,7 +79,7 @@ pub struct ParseIntError { /// # } /// ``` #[stable(feature = "int_error_matching", since = "1.55.0")] -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] #[non_exhaustive] pub enum IntErrorKind { /// Value being parsed is empty. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 68a1688680688..0a8a767858717 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -949,7 +949,7 @@ impl f64 { /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::max`] which only returns NaN when *both* arguments are NaN. /// - /// ```ignore-arm-unknown-linux-gnueabihf (see https://github.com/rust-lang/rust/issues/141087) + /// ``` /// #![feature(float_minimum_maximum)] /// let x = 1.0_f64; /// let y = 2.0_f64; @@ -976,7 +976,7 @@ impl f64 { /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::min`] which only returns NaN when *both* arguments are NaN. /// - /// ```ignore-arm-unknown-linux-gnueabihf (see https://github.com/rust-lang/rust/issues/141087) + /// ``` /// #![feature(float_minimum_maximum)] /// let x = 1.0_f64; /// let y = 2.0_f64; diff --git a/library/core/src/num/fmt.rs b/library/core/src/num/fmt.rs index ed61197157bf5..0e4b2844d8192 100644 --- a/library/core/src/num/fmt.rs +++ b/library/core/src/num/fmt.rs @@ -22,19 +22,7 @@ impl<'a> Part<'a> { pub fn len(&self) -> usize { match *self { Part::Zero(nzeroes) => nzeroes, - Part::Num(v) => { - if v < 1_000 { - if v < 10 { - 1 - } else if v < 100 { - 2 - } else { - 3 - } - } else { - if v < 10_000 { 4 } else { 5 } - } - } + Part::Num(v) => v.checked_ilog10().unwrap_or_default() as usize + 1, Part::Copy(buf) => buf.len(), } } @@ -82,21 +70,14 @@ pub struct Formatted<'a> { impl<'a> Formatted<'a> { /// Returns the exact byte length of combined formatted result. pub fn len(&self) -> usize { - let mut len = self.sign.len(); - for part in self.parts { - len += part.len(); - } - len + self.sign.len() + self.parts.iter().map(|part| part.len()).sum::() } /// Writes all formatted parts into the supplied buffer. /// Returns the number of written bytes, or `None` if the buffer is not enough. /// (It may still leave partially written bytes in the buffer; do not rely on that.) pub fn write(&self, out: &mut [u8]) -> Option { - if out.len() < self.sign.len() { - return None; - } - out[..self.sign.len()].copy_from_slice(self.sign.as_bytes()); + out.get_mut(..self.sign.len())?.copy_from_slice(self.sign.as_bytes()); let mut written = self.sign.len(); for part in self.parts { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 125c1f925d204..0d82ced890719 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -115,6 +115,15 @@ impl_zeroable_primitive!( /// ``` /// /// [null pointer optimization]: crate::option#representation +/// +/// # Note on generic usage +/// +/// `NonZero` can only be used with some standard library primitive types +/// (such as `u8`, `i32`, and etc.). The type parameter `T` must implement the +/// internal trait [`ZeroablePrimitive`], which is currently permanently unstable +/// and cannot be implemented by users. Therefore, you cannot use `NonZero` +/// with your own types, nor can you implement traits for all `NonZero`, +/// only for concrete types. #[stable(feature = "generic_nonzero", since = "1.79.0")] #[repr(transparent)] #[rustc_nonnull_optimization_guaranteed] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 4dcde883cd8a7..eb3de36512198 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -788,12 +788,12 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(2), None);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(-2), Some(3));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_sub_signed(-4), None);")] /// ``` - #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1940,12 +1940,12 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(2), 0);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(-2), 3);")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_sub_signed(-4), ", stringify!($SelfT), "::MAX);")] /// ``` - #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2088,12 +2088,12 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(2), ", stringify!($SelfT), "::MAX);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(-2), 3);")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_sub_signed(-4), 1);")] /// ``` - #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2551,12 +2551,12 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(2), (", stringify!($SelfT), "::MAX, true));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(-2), (3, false));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_sub_signed(-4), (1, true));")] /// ``` - #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")] + #[stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "mixed_integer_ops_unsigned_sub", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2583,7 +2583,7 @@ macro_rules! uint_impl { if size_of::() == 1 { // Trick LLVM into generating the psadbw instruction when SSE2 // is available and this function is autovectorized for u8's. - (self as i32).wrapping_sub(other as i32).abs() as Self + (self as i32).wrapping_sub(other as i32).unsigned_abs() as Self } else { if self < other { other - self diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 7ffde233da342..e53c128efe069 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -627,7 +627,7 @@ macro_rules! rem_impl_float { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ops", issue = "90080")] - impl Rem for $t { + impl const Rem for $t { type Output = $t; #[inline] diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index 5d040804a8d1c..bbef702320715 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -11,7 +11,7 @@ /// This destructor consists of two components: /// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type. /// - The automatically generated "drop glue" which recursively calls the destructors -/// of all the fields of this value. +/// of all the fields of this value. /// /// As Rust automatically calls the destructors of all contained fields, /// you don't have to implement `Drop` in most cases. But there are some cases where diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 1935268cda891..ad3b6439a6105 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1211,7 +1211,7 @@ pub enum OneSidedRangeBound { /// Types that implement `OneSidedRange` must return `Bound::Unbounded` /// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`. #[unstable(feature = "one_sided_range", issue = "69780")] -pub trait OneSidedRange: RangeBounds { +pub trait OneSidedRange: RangeBounds { /// An internal-only helper function for `split_off` and /// `split_off_mut` that returns the bound of the one-sided range. fn bound(self) -> (OneSidedRangeBound, T); diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f833cb470bbbd..cbb1c7c7d8f00 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -125,6 +125,7 @@ //! `Option::::None` //! - `transmute::<_, [u8; size_of::()]>(Option::::None)` is sound and produces //! `[0u8; size_of::()]` +//! //! These cases are identified by the second column: //! //! | `T` | Transmuting between `[0u8; size_of::()]` and `Option::::None` sound? | @@ -2111,7 +2112,8 @@ where impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} #[stable(feature = "rust1", since = "1.0.0")] -impl Default for Option { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for Option { /// Returns [`None`][Option::None]. /// /// # Examples diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index b6d5f848ef039..14bf7ba90150e 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -137,10 +137,10 @@ //! 2. An operation causes the value to depend on its own address not changing //! * e.g. calling [`poll`] for the first time on the produced [`Future`] //! 3. Further pieces of the safe interface of the type use internal [`unsafe`] operations which -//! assume that the address of the value is stable +//! assume that the address of the value is stable //! * e.g. subsequent calls to [`poll`] //! 4. Before the value is invalidated (e.g. deallocated), it is *dropped*, giving it a chance to -//! notify anything with pointers to itself that those pointers will be invalidated +//! notify anything with pointers to itself that those pointers will be invalidated //! * e.g. [`drop`]ping the [`Future`] [^pin-drop-future] //! //! There are two possible ways to ensure the invariants required for 2. and 3. above (which @@ -148,8 +148,8 @@ //! //! 1. Have the value detect when it is moved and update all the pointers that point to itself. //! 2. Guarantee that the address of the value does not change (and that memory is not re-used -//! for anything else) during the time that the pointers to it are expected to be valid to -//! dereference. +//! for anything else) during the time that the pointers to it are expected to be valid to +//! dereference. //! //! Since, as we discussed, Rust can move values without notifying them that they have moved, the //! first option is ruled out. @@ -160,11 +160,11 @@ //! be able to enforce this invariant in Rust: //! //! 1. Offer a wholly `unsafe` API to interact with the object, thus requiring every caller to -//! uphold the invariant themselves +//! uphold the invariant themselves //! 2. Store the value that must not be moved behind a carefully managed pointer internal to -//! the object +//! the object //! 3. Leverage the type system to encode and enforce this invariant by presenting a restricted -//! API surface to interact with *any* object that requires these invariants +//! API surface to interact with *any* object that requires these invariants //! //! The first option is quite obviously undesirable, as the [`unsafe`]ty of the interface will //! become viral throughout all code that interacts with the object. @@ -530,7 +530,7 @@ //! but it also implies that, //! //! 2. The memory location that stores the value must not get invalidated or otherwise repurposed -//! during the lifespan of the pinned value until its [`drop`] returns or panics +//! during the lifespan of the pinned value until its [`drop`] returns or panics //! //! This point is subtle but required for intrusive data structures to be implemented soundly. //! @@ -792,7 +792,7 @@ //! //! 1. *Structural [`Unpin`].* A struct can be [`Unpin`] only if all of its //! structurally-pinned fields are, too. This is [`Unpin`]'s behavior by default. -//! However, as a libray author, it is your responsibility not to write something like +//! However, as a library author, it is your responsibility not to write something like //! impl\ [Unpin] for Struct\ {} and then offer a method that provides //! structural pinning to an inner field of `T`, which may not be [`Unpin`]! (Adding *any* //! projection operation requires unsafe code, so the fact that [`Unpin`] is a safe trait does diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs index 17f7bcd306b05..b18b5d7c9ec0d 100644 --- a/library/core/src/pin/unsafe_pinned.rs +++ b/library/core/src/pin/unsafe_pinned.rs @@ -1,5 +1,5 @@ use crate::cell::UnsafeCell; -use crate::marker::{PointerLike, Unpin}; +use crate::marker::Unpin; use crate::ops::{CoerceUnsized, DispatchFromDyn}; use crate::pin::Pin; use crate::{fmt, ptr}; @@ -178,8 +178,4 @@ impl, U> CoerceUnsized> for UnsafePinned // #[unstable(feature = "unsafe_pinned", issue = "125735")] impl, U> DispatchFromDyn> for UnsafePinned {} -#[unstable(feature = "pointer_like_trait", issue = "none")] -// #[unstable(feature = "unsafe_pinned", issue = "125735")] -impl PointerLike for UnsafePinned {} - // FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned? diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index f55bdfeb3540d..2c77c55745b46 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -304,14 +304,12 @@ mod prim_bool {} /// This is what is known as "never type fallback". /// /// Historically, the fallback type was [`()`], causing confusing behavior where `!` spontaneously -/// coerced to `()`, even when it would not infer `()` without the fallback. There are plans to -/// change it in the [2024 edition] (and possibly in all editions on a later date); see -/// [Tracking Issue for making `!` fall back to `!`][fallback-ti]. +/// coerced to `()`, even when it would not infer `()` without the fallback. The fallback was changed +/// to `!` in the [2024 edition], and will be changed in all editions at a later date. /// /// [coercion site]: /// [`()`]: prim@unit -/// [fallback-ti]: -/// [2024 edition]: +/// [2024 edition]: /// #[unstable(feature = "never_type", issue = "35121")] mod prim_never {} diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index d0f61813b7c30..9e811666fa462 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -255,7 +255,8 @@ impl hash::Hash for Alignment { /// Returns [`Alignment::MIN`], which is valid for any type. #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl Default for Alignment { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for Alignment { fn default() -> Alignment { Alignment::MIN } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 690aadc06125a..61e88e7a00583 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -33,7 +33,7 @@ impl *const T { if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] { match (ptr).guaranteed_eq(null_mut()) { Some(res) => res, - // To remain maximally convervative, we stop execution when we don't + // To remain maximally conservative, we stop execution when we don't // know whether the pointer is null or not. // We can *not* return `false` here, that would be unsound in `NonNull::new`! None => panic!("null-ness of this pointer cannot be determined in const context"), @@ -53,7 +53,7 @@ impl *const T { self as _ } - /// Try to cast to a pointer of another type by checking aligment. + /// Try to cast to a pointer of another type by checking alignment. /// /// If the pointer is properly aligned to the target type, it will be /// cast to the target type. Otherwise, `None` is returned. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 2792432146adc..c1bd14c8b630c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -36,7 +36,7 @@ impl *mut T { self as _ } - /// Try to cast to a pointer of another type by checking aligment. + /// Try to cast to a pointer of another type by checking alignment. /// /// If the pointer is properly aligned to the target type, it will be /// cast to the target type. Otherwise, `None` is returned. diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 06976f9d47eeb..53ee523693a7b 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -100,8 +100,8 @@ impl NonNull { /// For more details, see the equivalent method on a raw pointer, [`ptr::without_provenance_mut`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. - #[stable(feature = "nonnull_provenance", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonnull_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonnull_provenance", since = "1.89.0")] + #[rustc_const_stable(feature = "nonnull_provenance", since = "1.89.0")] #[must_use] #[inline] pub const fn without_provenance(addr: NonZero) -> Self { @@ -145,7 +145,7 @@ impl NonNull { /// For more details, see the equivalent method on a raw pointer, [`ptr::with_exposed_provenance_mut`]. /// /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. - #[stable(feature = "nonnull_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonnull_provenance", since = "1.89.0")] #[inline] pub fn with_exposed_provenance(addr: NonZero) -> Self { // SAFETY: we know `addr` is non-zero. @@ -284,8 +284,8 @@ impl NonNull { } /// Converts a reference to a `NonNull` pointer. - #[stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "non_null_from_ref", since = "1.89.0")] + #[rustc_const_stable(feature = "non_null_from_ref", since = "1.89.0")] #[inline] pub const fn from_ref(r: &T) -> Self { // SAFETY: A reference cannot be null. @@ -293,8 +293,8 @@ impl NonNull { } /// Converts a mutable reference to a `NonNull` pointer. - #[stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "non_null_from_ref", since = "1.89.0")] + #[rustc_const_stable(feature = "non_null_from_ref", since = "1.89.0")] #[inline] pub const fn from_mut(r: &mut T) -> Self { // SAFETY: A mutable reference cannot be null. @@ -354,7 +354,7 @@ impl NonNull { /// For more details, see the equivalent method on a raw pointer, [`pointer::expose_provenance`]. /// /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. - #[stable(feature = "nonnull_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonnull_provenance", since = "1.89.0")] pub fn expose_provenance(self) -> NonZero { // SAFETY: The pointer is guaranteed by the type to be non-null, // meaning that the address will be non-zero. @@ -527,7 +527,7 @@ impl NonNull { unsafe { NonNull { pointer: self.as_ptr() as *mut U } } } - /// Try to cast to a pointer of another type by checking aligment. + /// Try to cast to a pointer of another type by checking alignment. /// /// If the pointer is properly aligned to the target type, it will be /// cast to the target type. Otherwise, `None` is returned. @@ -1828,9 +1828,6 @@ impl DispatchFromDyn> for NonNull PinCoerceUnsized for NonNull {} -#[unstable(feature = "pointer_like_trait", issue = "none")] -impl core::marker::PointerLike for NonNull {} - #[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 3a84ea66ad4b2..7f3f296498544 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1740,9 +1740,9 @@ impl Result, E> { /// assert_eq!(Ok("hello"), x.flatten().flatten()); /// ``` #[inline] - #[stable(feature = "result_flattening", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "result_flattening", since = "1.89.0")] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] - #[rustc_const_stable(feature = "result_flattening", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "result_flattening", since = "1.89.0")] pub const fn flatten(self) -> Result { // FIXME(const-hack): could be written with `and_then` match self { diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 222ecfa58d0d6..3d5702992f52f 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -54,7 +54,7 @@ impl [u8] { /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_eq_ignore_ascii_case", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_eq_ignore_ascii_case", since = "1.89.0")] #[must_use] #[inline] pub const fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 52d791b890072..421959a74e8ec 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3428,7 +3428,7 @@ where #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "slice_group_by_clone", since = "1.89.0")] impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { fn clone(&self) -> Self { Self { slice: self.slice, predicate: self.predicate.clone() } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3a3f44c6b8546..479fe0f1554de 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1316,7 +1316,7 @@ impl [T] { assert_unsafe_precondition!( check_language_ub, "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0, + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { exact_div(self.len(), N) }; @@ -1512,7 +1512,7 @@ impl [T] { assert_unsafe_precondition!( check_language_ub, "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - (n: usize = N, len: usize = self.len()) => n != 0 && len % n == 0 + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { exact_div(self.len(), N) }; @@ -4866,7 +4866,7 @@ impl [T] { let byte_offset = elem_start.wrapping_sub(self_start); - if byte_offset % size_of::() != 0 { + if !byte_offset.is_multiple_of(size_of::()) { return None; } @@ -4920,7 +4920,7 @@ impl [T] { let byte_start = subslice_start.wrapping_sub(self_start); - if byte_start % size_of::() != 0 { + if !byte_start.is_multiple_of(size_of::()) { return None; } @@ -5158,7 +5158,8 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for &[T] { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for &[T] { /// Creates an empty slice. fn default() -> Self { &[] @@ -5166,7 +5167,8 @@ impl Default for &[T] { } #[stable(feature = "mut_slice_default", since = "1.5.0")] -impl Default for &mut [T] { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for &mut [T] { /// Creates a mutable empty slice. fn default() -> Self { &mut [] diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 4280f7570db4c..400daba16c1b8 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -823,7 +823,7 @@ unsafe fn bidirectional_merge bool>( let right_end = right_rev.wrapping_add(1); // Odd length, so one element is left unconsumed in the input. - if len % 2 != 0 { + if !len.is_multiple_of(2) { let left_nonempty = left < left_end; let last_src = if left_nonempty { left } else { right }; ptr::copy_nonoverlapping(last_src, dst, 1); diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs index cf1df1e91a50d..1edffe095a89d 100644 --- a/library/core/src/slice/sort/stable/drift.rs +++ b/library/core/src/slice/sort/stable/drift.rs @@ -158,7 +158,7 @@ fn merge_tree_scale_factor(n: usize) -> u64 { panic!("Platform not supported"); } - ((1 << 62) + n as u64 - 1) / n as u64 + (1u64 << 62).div_ceil(n as u64) } // Note: merge_tree_depth output is < 64 when left < right as f*x and f*y must @@ -182,7 +182,7 @@ fn sqrt_approx(n: usize) -> usize { // Finally we note that the exponentiation / division can be done directly // with shifts. We OR with 1 to avoid zero-checks in the integer log. let ilog = (n | 1).ilog2(); - let shift = (1 + ilog) / 2; + let shift = ilog.div_ceil(2); ((1 << shift) + (n >> shift)) / 2 } diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index 452403b23dee1..f59ad3e66b43b 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -52,7 +52,7 @@ fn do_count_chars(s: &str) -> usize { // Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required // for correctness. const _: () = assert!(CHUNK_SIZE < 256); - const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0); + const _: () = assert!(CHUNK_SIZE.is_multiple_of(UNROLL_INNER)); // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size // differences which are handled by `align_to`. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..bcf886484add4 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -102,7 +102,7 @@ impl<'a> Iterator for Chars<'a> { // `(len + 3)` can't overflow, because we know that the `slice::Iter` // belongs to a slice in memory which has a maximum length of // `isize::MAX` (that's well below `usize::MAX`). - ((len + 3) / 4, Some(len)) + (len.div_ceil(4), Some(len)) } #[inline] @@ -1532,11 +1532,11 @@ impl<'a> Iterator for EncodeUtf16<'a> { // belongs to a slice in memory which has a maximum length of // `isize::MAX` (that's well below `usize::MAX`) if self.extra == 0 { - ((len + 2) / 3, Some(len)) + (len.div_ceil(3), Some(len)) } else { // We're in the middle of a surrogate pair, so add the remaining // surrogate to the bounds. - ((len + 2) / 3 + 1, Some(len + 1)) + (len.div_ceil(3) + 1, Some(len + 1)) } } } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index d250e1478d80a..32a2298817538 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -446,7 +446,7 @@ impl str { #[unstable(feature = "round_char_boundary", issue = "93743")] #[inline] pub fn ceil_char_boundary(&self, index: usize) -> usize { - if index > self.len() { + if index >= self.len() { self.len() } else { let upper_bound = Ord::min(index + 4, self.len()); @@ -2754,7 +2754,7 @@ impl str { /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_eq_ignore_ascii_case", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_eq_ignore_ascii_case", since = "1.89.0")] #[must_use] #[inline] pub const fn eq_ignore_ascii_case(&self, other: &str) -> bool { @@ -3072,7 +3072,8 @@ impl AsRef<[u8]> for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for &str { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for &str { /// Creates an empty str #[inline] fn default() -> Self { @@ -3081,7 +3082,8 @@ impl Default for &str { } #[stable(feature = "default_mut_str", since = "1.28.0")] -impl Default for &mut str { +#[rustc_const_unstable(feature = "const_default", issue = "67792")] +impl const Default for &mut str { /// Creates an empty mutable str #[inline] fn default() -> Self { diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index c5a3fdf360674..a5d5bf31f352a 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -222,7 +222,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // Ascii case, try to skip forward quickly. // When the pointer is aligned, read 2 words of data per iteration // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 { + if align != usize::MAX && align.wrapping_sub(index).is_multiple_of(USIZE_BYTES) { let ptr = v.as_ptr(); #[safety::loop_invariant(index <= blocks_end + ascii_block_size && align.wrapping_sub(index) % USIZE_BYTES == 0)] while index < blocks_end { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 6327c41f052c9..9cf08e74ff692 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,7 +1,7 @@ // See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; -use crate::marker::{ConstParamTy_, PointeeSized, StructuralPartialEq, UnsizedConstParamTy}; +use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; use crate::ops::ControlFlow::{self, Break, Continue}; use crate::random::{Random, RandomSource}; @@ -24,10 +24,7 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: PartialEq),+> PartialEq for ($($T,)+) - where - last_type!($($T,)+): PointeeSized - { + impl<$($T: PartialEq),+> PartialEq for ($($T,)+) { #[inline] fn eq(&self, other: &($($T,)+)) -> bool { $( ${ignore($T)} self.${index()} == other.${index()} )&&+ @@ -43,8 +40,6 @@ macro_rules! tuple_impls { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: Eq),+> Eq for ($($T,)+) - where - last_type!($($T,)+): PointeeSized {} } @@ -73,8 +68,6 @@ macro_rules! tuple_impls { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+) - where - last_type!($($T,)+): PointeeSized { #[inline] fn partial_cmp(&self, other: &($($T,)+)) -> Option { @@ -119,8 +112,6 @@ macro_rules! tuple_impls { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: Ord),+> Ord for ($($T,)+) - where - last_type!($($T,)+): PointeeSized { #[inline] fn cmp(&self, other: &($($T,)+)) -> Ordering { @@ -245,9 +236,4 @@ macro_rules! lexical_cmp { ($a:expr, $b:expr) => { ($a).cmp(&$b) }; } -macro_rules! last_type { - ($a:ident,) => { $a }; - ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; -} - tuple_impls!(E D C B A Z Y X W V U T); diff --git a/library/coretests/tests/bool.rs b/library/coretests/tests/bool.rs index bcd6dc2abac6c..eb5f0f50663e1 100644 --- a/library/coretests/tests/bool.rs +++ b/library/coretests/tests/bool.rs @@ -105,3 +105,11 @@ fn test_bool_to_option() { assert_eq!(D, Some(0)); */ } + +#[test] +fn test_bool_to_result() { + assert_eq!(false.ok_or(0), Err(0)); + assert_eq!(true.ok_or(0), Ok(())); + assert_eq!(false.ok_or_else(|| 0), Err(0)); + assert_eq!(true.ok_or_else(|| 0), Ok(())); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0c54609260ff7..fdef736c0c0f7 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(async_iter_from_iter)] #![feature(async_iterator)] #![feature(bigint_helper_methods)] +#![feature(bool_to_result)] #![feature(bstr)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_max_len)] diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 2407ba50ca31c..193d5887749ab 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -23,7 +23,7 @@ fn test_f16_integer_decode() { fn test_f32_integer_decode() { assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - // Set 2^100 directly instead of using powf, because it doesn't guarentee precision + // Set 2^100 directly instead of using powf, because it doesn't guarantee precision assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1)); assert_eq!(0f32.integer_decode(), (0, -150, 1)); assert_eq!((-0f32).integer_decode(), (0, -150, -1)); @@ -40,7 +40,7 @@ fn test_f32_integer_decode() { fn test_f64_integer_decode() { assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - // Set 2^100 directly instead of using powf, because it doesn't guarentee precision + // Set 2^100 directly instead of using powf, because it doesn't guarantee precision assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1)); assert_eq!(0f64.integer_decode(), (0, -1075, 1)); assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs index 280b27bc9bc6f..bbdfd5f5f3ed3 100644 --- a/library/portable-simd/crates/core_simd/src/lane_count.rs +++ b/library/portable-simd/crates/core_simd/src/lane_count.rs @@ -8,7 +8,7 @@ pub struct LaneCount; impl LaneCount { /// The number of bytes in a bitmask with this many lanes. - pub const BITMASK_LEN: usize = (N + 7) / 8; + pub const BITMASK_LEN: usize = N.div_ceil(8); } /// Statically guarantees that a lane count is marked as supported. diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index 0e915b92697f1..62d247fafb7ad 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -21,18 +21,12 @@ #![allow(internal_features)] #![warn(unreachable_pub)] -#[cfg(not(bootstrap))] #[lang = "pointee_sized"] pub trait PointeeSized {} -#[cfg(not(bootstrap))] #[lang = "meta_sized"] pub trait MetaSized: PointeeSized {} -#[cfg(bootstrap)] -#[lang = "sized"] -pub trait Sized {} -#[cfg(not(bootstrap))] #[lang = "sized"] pub trait Sized: MetaSized {} @@ -43,19 +37,8 @@ trait Copy {} #[lang = "freeze"] auto trait Freeze {} -#[cfg(bootstrap)] -impl Copy for *mut T {} -#[cfg(not(bootstrap))] impl Copy for *mut T {} -#[cfg(bootstrap)] -#[lang = "drop_in_place"] -#[inline] -#[allow(unconditional_recursion)] -pub unsafe fn drop_in_place(to_drop: *mut T) { - drop_in_place(to_drop); -} -#[cfg(not(bootstrap))] #[lang = "drop_in_place"] #[inline] #[allow(unconditional_recursion)] diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index 75f9212695d1f..d763971445069 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -8,18 +8,12 @@ #![allow(internal_features)] #![warn(unreachable_pub)] -#[cfg(not(bootstrap))] #[lang = "pointee_sized"] pub trait PointeeSized {} -#[cfg(not(bootstrap))] #[lang = "meta_sized"] pub trait MetaSized: PointeeSized {} -#[cfg(bootstrap)] -#[lang = "sized"] -pub trait Sized {} -#[cfg(not(bootstrap))] #[lang = "sized"] pub trait Sized: MetaSized {} @@ -31,19 +25,8 @@ trait Copy {} #[lang = "freeze"] auto trait Freeze {} -#[cfg(bootstrap)] -impl Copy for *mut T {} -#[cfg(not(bootstrap))] impl Copy for *mut T {} -#[cfg(bootstrap)] -#[lang = "drop_in_place"] -#[inline] -#[allow(unconditional_recursion)] -pub unsafe fn drop_in_place(to_drop: *mut T) { - drop_in_place(to_drop); -} -#[cfg(not(bootstrap))] #[lang = "drop_in_place"] #[inline] #[allow(unconditional_recursion)] diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml index bd318fc2f9e9c..1ddc112380f16 100644 --- a/library/rustc-std-workspace-core/Cargo.toml +++ b/library/rustc-std-workspace-core/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["public-dependency"] + [package] name = "rustc-std-workspace-core" version = "1.99.0" @@ -11,5 +13,7 @@ edition = "2024" path = "lib.rs" [dependencies] -core = { path = "../core" } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] } +core = { path = "../core", public = true } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = [ + "compiler-builtins", +] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index faba0961516fc..e941eb577a47c 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -158,8 +158,6 @@ test = true [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - # #[cfg(bootstrap)] loongarch32 - 'cfg(target_arch, values("loongarch32"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index d154f17ed1f86..506ae9e2a9a69 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -360,10 +360,10 @@ fn default_alloc_error_hook(layout: Layout) { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. #[rustc_std_internal_symbol] - static __rust_alloc_error_handler_should_panic: u8; + fn __rust_alloc_error_handler_should_panic_v2() -> u8; } - if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } { panic!("memory allocation of {} bytes failed", layout.size()); } else { // This is the default path taken on OOM, and the only path taken on stable with std. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 3cc225004ea39..8d7edc732aff3 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -568,7 +568,7 @@ impl OsString { /// However, keep in mind that trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_os_str`]: Self::into_boxed_os_str - #[stable(feature = "os_string_pathbuf_leak", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_string_pathbuf_leak", since = "1.89.0")] #[inline] pub fn leak<'a>(self) -> &'a mut OsStr { OsStr::from_inner_mut(self.inner.leak()) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index ea342ec9c128d..72ad7c244eeba 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -4,6 +4,27 @@ //! filesystem. All methods in this module represent cross-platform filesystem //! operations. Extra platform-specific functionality can be found in the //! extension traits of `std::os::$platform`. +//! +//! # Time of Check to Time of Use (TOCTOU) +//! +//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use" +//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions) +//! and then uses the result of that check to make a decision, but the condition may have changed +//! between the check and the use. +//! +//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to +//! TOCTOU - another process could create the file between your check and creation attempt. +//! +//! Another example is with symbolic links: when removing a directory, if another process replaces +//! the directory with a symbolic link between the check and the removal operation, the removal +//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use +//! atomic operations to prevent such race conditions. +//! +//! To avoid TOCTOU issues: +//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by +//! changes made by other processes. +//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating). +//! - Keep file open for the duration of operations. #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] @@ -121,7 +142,7 @@ pub struct File { /// /// [`try_lock`]: File::try_lock /// [`try_lock_shared`]: File::try_lock_shared -#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "file_lock", since = "1.89.0")] pub enum TryLockError { /// The lock could not be acquired due to an I/O error on the file. The standard library will /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] @@ -366,10 +387,10 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result inner(path.as_ref(), contents.as_ref()) } -#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "file_lock", since = "1.89.0")] impl error::Error for TryLockError {} -#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "file_lock", since = "1.89.0")] impl fmt::Debug for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -379,7 +400,7 @@ impl fmt::Debug for TryLockError { } } -#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "file_lock", since = "1.89.0")] impl fmt::Display for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -390,7 +411,7 @@ impl fmt::Display for TryLockError { } } -#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "file_lock", since = "1.89.0")] impl From for io::Error { fn from(err: TryLockError) -> io::Error { match err { @@ -548,13 +569,14 @@ impl File { /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking whether a file - /// exists and creating a new one, the file may have been created by another process (a TOCTOU + /// exists and creating a new one, the file may have been created by another process (a [TOCTOU] /// race condition / attack). /// /// This can also be written using /// `File::options().read(true).write(true).create_new(true).open(...)`. /// /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists + /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// /// # Examples /// @@ -721,7 +743,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "file_lock", since = "1.89.0")] pub fn lock(&self) -> io::Result<()> { self.inner.lock() } @@ -773,7 +795,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "file_lock", since = "1.89.0")] pub fn lock_shared(&self) -> io::Result<()> { self.inner.lock_shared() } @@ -837,7 +859,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "file_lock", since = "1.89.0")] pub fn try_lock(&self) -> Result<(), TryLockError> { self.inner.try_lock() } @@ -901,7 +923,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "file_lock", since = "1.89.0")] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.inner.try_lock_shared() } @@ -938,7 +960,7 @@ impl File { /// Ok(()) /// } /// ``` - #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "file_lock", since = "1.89.0")] pub fn unlock(&self) -> io::Result<()> { self.inner.unlock() } @@ -1610,7 +1632,7 @@ impl OpenOptions { /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been - /// created by another process (a TOCTOU race condition / attack). + /// created by another process (a [TOCTOU] race condition / attack). /// /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are /// ignored. @@ -1621,6 +1643,7 @@ impl OpenOptions { /// [`.create()`]: OpenOptions::create /// [`.truncate()`]: OpenOptions::truncate /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists + /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// /// # Examples /// @@ -2954,17 +2977,17 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`. /// /// ## Time-of-check to time-of-use (TOCTOU) race conditions -/// On a few platforms there is no way to remove a directory's contents without following symlinks -/// unless you perform a check and then operate on paths based on that directory. -/// This allows concurrently-running code to replace the directory with a symlink after the check, -/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race. -/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms -/// except the following. It should not be used in security-sensitive contexts on these platforms: -/// - Miri: Even when emulating targets where the underlying implementation will protect against -/// TOCTOU races, Miri will not do so. -/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement -/// the required platform support to do so. +/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou). +/// +/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default. +/// However, on the following platforms, this protection is not provided and the function should +/// not be used in security-sensitive contexts: +/// - **Miri**: Even when emulating targets where the underlying implementation will protect against +/// TOCTOU races, Miri will not do so. +/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement +/// the required platform support to do so. /// +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou /// [changes]: io#platform-specific-behavior /// /// # Errors @@ -3091,7 +3114,7 @@ pub fn read_dir>(path: P) -> io::Result { /// On UNIX-like systems, this function will update the permission bits /// of the file pointed to by the symlink. /// -/// Note that this behavior can lead to privalage escalation vulnerabilites, +/// Note that this behavior can lead to privalage escalation vulnerabilities, /// where the ability to create a symlink in one directory allows you to /// cause the permissions of another file or directory to be modified. /// @@ -3238,7 +3261,7 @@ impl AsInnerMut for DirBuilder { /// permission is denied on one of the parent directories. /// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not -/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios +/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// /// # Examples @@ -3251,6 +3274,7 @@ impl AsInnerMut for DirBuilder { /// ``` /// /// [`Path::exists`]: crate::path::Path::exists +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou #[stable(feature = "fs_try_exists", since = "1.81.0")] #[inline] pub fn exists>(path: P) -> io::Result { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a9a24681e7c8f..17c32d7a571c8 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -3128,7 +3128,7 @@ impl SizeHint for Take { } } -#[stable(feature = "seek_io_take", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "seek_io_take", since = "1.89.0")] impl Seek for Take { fn seek(&mut self, pos: SeekFrom) -> Result { let new_position = match pos { diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs index 3a459ed8aeea1..95c3a74c4890a 100644 --- a/library/std/src/os/android/net.rs +++ b/library/std/src/os/android/net.rs @@ -6,5 +6,5 @@ pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use crate::os::net::linux_ext::socket::UnixSocketExt; -#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "tcp_quickack", since = "1.89.0")] pub use crate::os::net::linux_ext::tcp::TcpStreamExt; diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs index c14aba13bd153..ee56dafdbfda2 100644 --- a/library/std/src/os/linux/net.rs +++ b/library/std/src/os/linux/net.rs @@ -6,5 +6,5 @@ pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use crate::os::net::linux_ext::socket::UnixSocketExt; -#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "tcp_quickack", since = "1.89.0")] pub use crate::os::net::linux_ext::tcp::TcpStreamExt; diff --git a/library/std/src/os/net/linux_ext/mod.rs b/library/std/src/os/net/linux_ext/mod.rs index bb9dfae2623e1..3c9afe35479df 100644 --- a/library/std/src/os/net/linux_ext/mod.rs +++ b/library/std/src/os/net/linux_ext/mod.rs @@ -8,7 +8,7 @@ pub(crate) mod addr; #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub(crate) mod socket; -#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "tcp_quickack", since = "1.89.0")] pub(crate) mod tcp; #[cfg(test)] diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index 167cfa6253165..fde53ec4257bd 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -9,7 +9,7 @@ use crate::{io, net}; /// Os-specific extensions for [`TcpStream`] /// /// [`TcpStream`]: net::TcpStream -#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "tcp_quickack", since = "1.89.0")] pub trait TcpStreamExt: Sealed { /// Enable or disable `TCP_QUICKACK`. /// @@ -33,7 +33,7 @@ pub trait TcpStreamExt: Sealed { /// .expect("Couldn't connect to the server..."); /// stream.set_quickack(true).expect("set_quickack call failed"); /// ``` - #[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "tcp_quickack", since = "1.89.0")] fn set_quickack(&self, quickack: bool) -> io::Result<()>; /// Gets the value of the `TCP_QUICKACK` option on this socket. @@ -54,7 +54,7 @@ pub trait TcpStreamExt: Sealed { /// stream.set_quickack(true).expect("set_quickack call failed"); /// assert_eq!(stream.quickack().unwrap_or(false), true); /// ``` - #[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "tcp_quickack", since = "1.89.0")] fn quickack(&self) -> io::Result; /// A socket listener will be awakened solely when data arrives. @@ -103,10 +103,10 @@ pub trait TcpStreamExt: Sealed { fn deferaccept(&self) -> io::Result; } -#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "tcp_quickack", since = "1.89.0")] impl Sealed for net::TcpStream {} -#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "tcp_quickack", since = "1.89.0")] impl TcpStreamExt for net::TcpStream { fn set_quickack(&self, quickack: bool) -> io::Result<()> { self.as_inner().as_inner().set_quickack(quickack) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 3f4fe2e56ec31..466b134d8faee 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -385,7 +385,7 @@ pub trait ChildExt: Sealed { /// # Errors /// /// This function will return an error if the signal is invalid. The integer values associated - /// with signals are implemenation-specific, so it's encouraged to use a crate that provides + /// with signals are implementation-specific, so it's encouraged to use a crate that provides /// posix bindings. /// /// # Examples diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 07f212b113564..d9c34d4fa0451 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1244,7 +1244,7 @@ impl PathBuf { /// /// The caller has free choice over the returned lifetime, including 'static. /// Indeed, this function is ideally used for data that lives for the remainder of - /// the program’s life, as dropping the returned reference will cause a memory leak. + /// the program's life, as dropping the returned reference will cause a memory leak. /// /// It does not reallocate or shrink the `PathBuf`, so the leaked allocation may include /// unused capacity that is not part of the returned slice. If you want to discard excess @@ -1252,7 +1252,7 @@ impl PathBuf { /// However, keep in mind that trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_path`]: Self::into_boxed_path - #[stable(feature = "os_string_pathbuf_leak", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_string_pathbuf_leak", since = "1.89.0")] #[inline] pub fn leak<'a>(self) -> &'a mut Path { Path::from_inner_mut(self.inner.leak()) @@ -3028,7 +3028,7 @@ impl Path { /// /// This function always resolves `..` to the "lexical" parent. /// That is "a/b/../c" will always resolve to `a/c` which can change the meaning of the path. - /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn’t `a`. + /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn't `a`. /// /// /// @@ -3127,7 +3127,7 @@ impl Path { /// Returns `true` if the path points at an existing entity. /// /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! - /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs. + /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -3148,6 +3148,7 @@ impl Path { /// check errors, call [`Path::try_exists`]. /// /// [`try_exists()`]: Self::try_exists + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou #[stable(feature = "path_ext", since = "1.5.0")] #[must_use] #[inline] @@ -3167,7 +3168,7 @@ impl Path { /// permission is denied on one of the parent directories. /// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not - /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios + /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// /// This is an alias for [`std::fs::exists`](crate::fs::exists). @@ -3180,6 +3181,7 @@ impl Path { /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err()); /// ``` /// + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou /// [`exists()`]: Self::exists #[stable(feature = "path_try_exists", since = "1.63.0")] #[inline] diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 82e5fe05db5e3..eba849d16dacd 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -313,7 +313,7 @@ impl T> Deref for LazyLock { } } -#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "lazy_deref_mut", since = "1.89.0")] impl T> DerefMut for LazyLock { #[inline] fn deref_mut(&mut self) -> &mut T { diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 8712332dd2767..673033034eff5 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -187,7 +187,7 @@ use crate::time::{Duration, Instant}; /// sender.send(expensive_computation()).unwrap(); /// }); /// -/// // Do some useful work for awhile +/// // Do some useful work for a while /// /// // Let's see what that answer was /// println!("{:?}", receiver.recv().unwrap()); diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index f942937c14d11..41d1dd3ce674b 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -509,7 +509,7 @@ pub enum TrySendError { /// sender.send(expensive_computation()).unwrap(); /// }); /// -/// // Do some useful work for awhile +/// // Do some useful work for a while /// /// // Let's see what that answer was /// println!("{:?}", receiver.recv().unwrap()); diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index cc1d0b30152a1..571f0d14248e1 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -13,7 +13,7 @@ //! depend on the primitive. See [#Overview] bellow. //! //! For the alternative implementations that do not employ poisoning, -//! see `std::sys::nonpoisoning`. +//! see `std::sync::nonpoisoning`. //! //! # Overview //! diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index 73c2583187207..c77c50fece1a9 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -140,7 +140,7 @@ impl Socket { 0 => {} _ => { // WASI poll does not return POLLHUP or POLLERR in revents. Check if the - // connnection actually succeeded and return ok only when the socket is + // connection actually succeeded and return ok only when the socket is // ready and no errors were found. if let Some(e) = self.take_error()? { return Err(e); diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 46d67c8e51019..6835ba44ee242 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -7,7 +7,7 @@ use crate::time::Duration; mod tcp; pub(crate) mod tcp4; -pub struct TcpStream(#[expect(dead_code)] tcp::Tcp); +pub struct TcpStream(tcp::Tcp); impl TcpStream { pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { @@ -38,28 +38,30 @@ impl TcpStream { unsupported() } - pub fn read(&self, _: &mut [u8]) -> io::Result { - unsupported() + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) } - pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { - unsupported() + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) } - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - unsupported() + pub fn read_vectored(&self, buf: &mut [IoSliceMut<'_>]) -> io::Result { + // FIXME: UEFI does support vectored read, so implement that. + crate::io::default_read_vectored(|b| self.read(b), buf) } pub fn is_read_vectored(&self) -> bool { false } - pub fn write(&self, _: &[u8]) -> io::Result { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) } - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - unsupported() + pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result { + // FIXME: UEFI does support vectored write, so implement that. + crate::io::default_write_vectored(|b| self.write(b), buf) } pub fn is_write_vectored(&self) -> bool { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index f87accdc41de8..55b6dbf2490bd 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -3,7 +3,7 @@ use crate::io; use crate::net::SocketAddr; pub(crate) enum Tcp { - V4(#[expect(dead_code)] tcp4::Tcp4), + V4(tcp4::Tcp4), } impl Tcp { @@ -18,4 +18,16 @@ impl Tcp { SocketAddr::V6(_) => todo!(), } } + + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + match self { + Self::V4(client) => client.write(buf), + } + } + + pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + match self { + Self::V4(client) => client.read(buf), + } + } } diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index f7ca373b52b5a..af1ba2be47adb 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -88,6 +88,85 @@ impl Tcp4 { } } + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); + + let fragment = tcp4::FragmentData { + fragment_length: data_len, + fragment_buffer: buf.as_ptr().cast::().cast_mut(), + }; + let mut tx_data = tcp4::TransmitData { + push: r_efi::efi::Boolean::FALSE, + urgent: r_efi::efi::Boolean::FALSE, + data_length: data_len, + fragment_count: 1, + fragment_table: [fragment], + }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { + completion_token, + packet: tcp4::IoTokenPacket { + tx_data: (&raw mut tx_data).cast::>(), + }, + }; + + let r = unsafe { ((*protocol).transmit)(protocol, &mut token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + self.wait_for_flag(); + + if completion_token.status.is_error() { + Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) + } else { + Ok(data_len as usize) + } + } + + pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); + + let fragment = tcp4::FragmentData { + fragment_length: data_len, + fragment_buffer: buf.as_mut_ptr().cast::(), + }; + let mut tx_data = tcp4::ReceiveData { + urgent_flag: r_efi::efi::Boolean::FALSE, + data_length: data_len, + fragment_count: 1, + fragment_table: [fragment], + }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { + completion_token, + packet: tcp4::IoTokenPacket { + rx_data: (&raw mut tx_data).cast::>(), + }, + }; + + let r = unsafe { ((*protocol).receive)(protocol, &mut token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + self.wait_for_flag(); + + if completion_token.status.is_error() { + Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) + } else { + Ok(data_len as usize) + } + } + unsafe fn create_evt(&self) -> io::Result { self.flag.store(false, Ordering::Relaxed); helpers::OwnedEvent::new( diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index bb68a824fc313..9bc5a16b80023 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -4,7 +4,7 @@ use super::hermit_abi; use crate::ffi::CStr; use crate::mem::ManuallyDrop; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, ptr}; pub type Tid = hermit_abi::Tid; @@ -86,6 +86,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { unsafe { let _ = hermit_abi::join(self.tid); diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index a974f4f17ae67..813e1cbcd58fb 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -10,7 +10,7 @@ use crate::mem::ManuallyDrop; use crate::num::NonZero; use crate::ptr::NonNull; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{hint, io}; pub struct Thread { @@ -205,6 +205,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { // Safety: `ThreadInner` is alive at this point let inner = unsafe { self.p_inner.as_ref() }; diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs index 219ef1b7a9897..85f6dcd96b4a5 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/pal/sgx/thread.rs @@ -5,7 +5,7 @@ use super::unsupported; use crate::ffi::CStr; use crate::io; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(task_queue::JoinHandle); @@ -132,6 +132,14 @@ impl Thread { usercalls::wait_timeout(0, dur, || true); } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { self.0.wait(); } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index e3b4908f85863..b9cdc7a2a58bb 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -2,7 +2,7 @@ use crate::ffi::CStr; use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; use crate::sys::os; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{cmp, io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024; @@ -109,6 +109,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + /// must join, because no pthread_detach supported pub fn join(self) { let id = self.into_id(); diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index e47263348dbdb..420481648a7d5 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -487,7 +487,7 @@ impl OwnedProtocol { let protocol: *mut T = Box::into_raw(Box::new(protocol)); let mut handle: r_efi::efi::Handle = crate::ptr::null_mut(); - // FIXME: Move into r-efi once extended_varargs_abi_support is stablized + // FIXME: Move into r-efi once extended_varargs_abi_support is stabilized let func: BootInstallMultipleProtocolInterfaces = unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) }; @@ -521,7 +521,7 @@ impl Drop for OwnedProtocol { // Do not deallocate a runtime protocol if let Some(bt) = boot_services() { let bt: NonNull = bt.cast(); - // FIXME: Move into r-efi once extended_varargs_abi_support is stablized + // FIXME: Move into r-efi once extended_varargs_abi_support is stabilized let func: BootUninstallMultipleProtocolInterfaces = unsafe { crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces) }; @@ -645,7 +645,7 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result, diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs index 7d4006ff4b2f7..e4776ec42fbba 100644 --- a/library/std/src/sys/pal/uefi/thread.rs +++ b/library/std/src/sys/pal/uefi/thread.rs @@ -3,7 +3,7 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::ptr::NonNull; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(!); @@ -39,6 +39,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { self.0 } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index d8b189413f4a3..53f0d1eeda5bf 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -6,7 +6,7 @@ use crate::sys::weak::dlsym; #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))] use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{cmp, io, ptr}; #[cfg(not(any( target_os = "l4re", @@ -296,6 +296,76 @@ impl Thread { } } + // Any unix that has clock_nanosleep + // If this list changes update the MIRI chock_nanosleep shim + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", + ))] + pub fn sleep_until(deadline: Instant) { + let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else { + // The deadline is further in the future then can be passed to + // clock_nanosleep. We have to use Self::sleep instead. This might + // happen on 32 bit platforms, especially closer to 2038. + let now = Instant::now(); + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + return; + }; + + unsafe { + // When we get interrupted (res = EINTR) call clock_nanosleep again + loop { + let res = libc::clock_nanosleep( + super::time::Instant::CLOCK_ID, + libc::TIMER_ABSTIME, + &ts, + core::ptr::null_mut(), // not required with TIMER_ABSTIME + ); + + if res == 0 { + break; + } else { + assert_eq!( + res, + libc::EINTR, + "timespec is in range, + clockid is valid and kernel should support it" + ); + } + } + } + } + + // Any unix that does not have clock_nanosleep + #[cfg(not(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", + )))] + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { let id = self.into_id(); let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 0074d7674741b..bd7f74fea6a9c 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -261,6 +261,10 @@ pub struct Instant { } impl Instant { + #[cfg(target_vendor = "apple")] + pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW; + #[cfg(not(target_vendor = "apple"))] + pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC; pub fn now() -> Instant { // https://www.manpagez.com/man/3/clock_gettime/ // @@ -273,11 +277,7 @@ impl Instant { // // Instant on macos was historically implemented using mach_absolute_time; // we preserve this value domain out of an abundance of caution. - #[cfg(target_vendor = "apple")] - const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; - #[cfg(not(target_vendor = "apple"))] - const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; - Instant { t: Timespec::now(clock_id) } + Instant { t: Timespec::now(Self::CLOCK_ID) } } pub fn checked_sub_instant(&self, other: &Instant) -> Option { @@ -291,6 +291,14 @@ impl Instant { pub fn checked_sub_duration(&self, other: &Duration) -> Option { Some(Instant { t: self.t.checked_sub_duration(other)? }) } + + #[cfg_attr( + not(target_os = "linux"), + allow(unused, reason = "needed by the `sleep_until` on some unix platforms") + )] + pub(crate) fn into_timespec(self) -> Timespec { + self.t + } } impl fmt::Debug for Instant { diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs index 89f8bad7026ee..8a3119fa292d1 100644 --- a/library/std/src/sys/pal/unsupported/thread.rs +++ b/library/std/src/sys/pal/unsupported/thread.rs @@ -2,7 +2,7 @@ use super::unsupported; use crate::ffi::CStr; use crate::io; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(!); @@ -26,6 +26,10 @@ impl Thread { panic!("can't sleep"); } + pub fn sleep_until(_deadline: Instant) { + panic!("can't sleep"); + } + pub fn join(self) { self.0 } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index cc569bb3daf68..5f21a553673a3 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -2,7 +2,7 @@ use crate::ffi::CStr; use crate::num::NonZero; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, mem}; cfg_if::cfg_if! { @@ -171,6 +171,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index dd5aff391fd8b..44ce3eab109f4 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -2,7 +2,7 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::sys::unsupported; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread(!); @@ -41,6 +41,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) {} } diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 45e52cf4d047f..147851717553a 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -8,7 +8,7 @@ use crate::os::windows::io::{AsRawHandle, HandleOrNull}; use crate::sys::handle::Handle; use crate::sys::{c, stack_overflow}; use crate::sys_common::FromInner; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -106,6 +106,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn handle(&self) -> &Handle { &self.handle } diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs index 0ebb46dc19faa..1b344e984dc36 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/pal/xous/thread.rs @@ -8,7 +8,7 @@ use crate::os::xous::ffi::{ map_memory, update_memory_flags, }; use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub struct Thread { tid: ThreadId, @@ -128,6 +128,14 @@ impl Thread { } } + pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + pub fn join(self) { join_thread(self.tid).unwrap(); } diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index e90372805bbf9..da0982384b0e6 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -10,7 +10,7 @@ pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' } -/// Cygwin allways prefers `/` over `\`, and it always converts all `/` to `\` +/// Cygwin always prefers `/` over `\`, and it always converts all `/` to `\` /// internally when calling Win32 APIs. Therefore, the server component of path /// `\\?\UNC\localhost/share` is `localhost/share` on Win32, but `localhost` /// on Cygwin. diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 18196fae28bee..53e2f1da67537 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -15,7 +15,7 @@ //! bytes, while the non-blocking pool, once initialized using the blocking //! pool, uses a CPRNG to return an unlimited number of random bytes. With a //! strong enough CPRNG however, the entropy estimation didn't contribute that -//! much towards security while being an excellent vector for DoS attacs. Thus, +//! much towards security while being an excellent vector for DoS attacks. Thus, //! the blocking pool was removed in kernel version 5.6.[^2] That patch did not //! magically increase the quality of the non-blocking pool, however, so we can //! safely consider it strong enough even in older kernel versions and use it @@ -30,7 +30,7 @@ //! data the system has available at the time. //! //! So in conclusion, we always want the output of the non-blocking pool, but -//! may need to wait until it is initalized. The default behavior of `getrandom` +//! may need to wait until it is initialized. The default behavior of `getrandom` //! is to wait until the non-blocking pool is initialized and then draw from there, //! so if `getrandom` is available, we use its default to generate the bytes. For //! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs index d68ce4a9e8703..894409b395abb 100644 --- a/library/std/src/sys/random/unsupported.rs +++ b/library/std/src/sys/random/unsupported.rs @@ -6,7 +6,7 @@ pub fn fill_bytes(_: &mut [u8]) { pub fn hashmap_random_keys() -> (u64, u64) { // Use allocation addresses for a bit of randomness. This isn't - // particularily secure, but there isn't really an alternative. + // particularly secure, but there isn't really an alternative. let stack = 0u8; let heap = Box::new(0u8); let k1 = ptr::from_ref(&stack).addr() as u64; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 26b2fb4472436..6075173db47f4 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -897,8 +897,31 @@ pub fn sleep(dur: Duration) { /// /// # Platform-specific behavior /// -/// This function uses [`sleep`] internally, see its platform-specific behavior. +/// In most cases this function will call an OS specific function. Where that +/// is not supported [`sleep`] is used. Those platforms are referred to as other +/// in the table below. /// +/// # Underlying System calls +/// +/// The following system calls are [currently] being used: +/// +/// | Platform | System call | +/// |-----------|----------------------------------------------------------------------| +/// | Linux | [clock_nanosleep] (Monotonic clock) | +/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] | +/// | Android | [clock_nanosleep] (Monotonic Clock)] | +/// | Solaris | [clock_nanosleep] (Monotonic Clock)] | +/// | Illumos | [clock_nanosleep] (Monotonic Clock)] | +/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] | +/// | Hurd | [clock_nanosleep] (Monotonic Clock)] | +/// | Fuchsia | [clock_nanosleep] (Monotonic Clock)] | +/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] | +/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself | +/// +/// [currently]: crate::io#platform-specific-behavior +/// [clock_nanosleep]: https://linux.die.net/man/3/clock_nanosleep +/// +/// **Disclaimer:** These system calls might change over time. /// /// # Examples /// @@ -923,9 +946,9 @@ pub fn sleep(dur: Duration) { /// } /// ``` /// -/// A slow api we must not call too fast and which takes a few +/// A slow API we must not call too fast and which takes a few /// tries before succeeding. By using `sleep_until` the time the -/// api call takes does not influence when we retry or when we give up +/// API call takes does not influence when we retry or when we give up /// /// ```no_run /// #![feature(thread_sleep_until)] @@ -960,11 +983,7 @@ pub fn sleep(dur: Duration) { /// ``` #[unstable(feature = "thread_sleep_until", issue = "113752")] pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - sleep(delay); - } + imp::Thread::sleep_until(deadline) } /// Used to ensure that `park` and `park_timeout` do not unwind, as that can diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 98f471ad54b2e..c8a7bcf55c14e 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -6,7 +6,7 @@ use crate::thread::Thread; crate::thread_local! { /// A thread local linked list of spawn hooks. /// - /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads. + /// It is a linked list of Arcs, such that it can very cheaply be inherited by spawned threads. /// /// (That technically makes it a set of linked lists with shared tails, so a linked tree.) static SPAWN_HOOKS: Cell = const { Cell::new(SpawnHooks { first: None }) }; diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 03af35e809c91..cd0683f44c998 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -95,10 +95,10 @@ use crate::sys_common::{FromInner, IntoInner}; /// let now = Instant::now(); /// let days_per_10_millennia = 365_2425; /// let solar_seconds_per_day = 60 * 60 * 24; -/// let millenium_in_solar_seconds = 31_556_952_000; -/// assert_eq!(millenium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10); +/// let millennium_in_solar_seconds = 31_556_952_000; +/// assert_eq!(millennium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10); /// -/// let duration = Duration::new(millenium_in_solar_seconds, 0); +/// let duration = Duration::new(millennium_in_solar_seconds, 0); /// println!("{:?}", now + duration); /// ``` /// @@ -407,6 +407,15 @@ impl Instant { pub fn checked_sub(&self, duration: Duration) -> Option { self.0.checked_sub_duration(&duration).map(Instant) } + + // Used by platform specific `sleep_until` implementations such as the one used on Linux. + #[cfg_attr( + not(target_os = "linux"), + allow(unused, reason = "not every platform has a specific `sleep_until`") + )] + pub(crate) fn into_inner(self) -> time::Instant { + self.0 + } } #[stable(feature = "time2", since = "1.8.0")] diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 1bb17d149fa10..32561dd6ab6a3 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -1,7 +1,8 @@ +#![feature(thread_sleep_until)] use std::cell::{Cell, RefCell}; use std::sync::{Arc, Mutex}; use std::thread; -use std::time::Duration; +use std::time::{Duration, Instant}; #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads @@ -17,6 +18,17 @@ fn sleep_very_long() { assert_eq!(*finished.lock().unwrap(), false); } +#[test] +fn sleep_until() { + let now = Instant::now(); + let period = Duration::from_millis(100); + let deadline = now + period; + thread::sleep_until(deadline); + + let elapsed = now.elapsed(); + assert!(elapsed >= period); +} + #[test] fn thread_local_containing_const_statements() { // This exercises the `const $init:block` cases of the thread_local macro. diff --git a/library/std/tests/thread_local/tests.rs b/library/std/tests/thread_local/tests.rs index e8278361d9337..5df1a0e25ee51 100644 --- a/library/std/tests/thread_local/tests.rs +++ b/library/std/tests/thread_local/tests.rs @@ -348,7 +348,7 @@ fn join_orders_after_tls_destructors() { // // The test won't currently work without target_thread_local, aka with slow tls. // The runtime tries very hard to drop last the TLS variable that keeps the information about the -// current thread, by using several tricks like deffering the drop to a later round of TLS destruction. +// current thread, by using several tricks like deferring the drop to a later round of TLS destruction. // However, this only seems to work with fast tls. // // With slow TLS, it seems that multiple libc implementations will just set the value to null the first diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 71b1830dd394b..bd9f86aee7475 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,5 +2,5 @@ # standard library we currently track. [toolchain] -channel = "nightly-2025-07-02" +channel = "nightly-2025-07-10" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] diff --git a/tool_config/kani-version.toml b/tool_config/kani-version.toml index acda371ae8c66..004d4645e4e5f 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 = "12386811f934e7eb76e794bea787a1030f934735" +commit = "533403efc3a2eef94e13d67f214ee25a6fb21b41" diff --git a/verifast-proofs/alloc/collections/linked_list.rs-negative/original/linked_list.rs b/verifast-proofs/alloc/collections/linked_list.rs-negative/original/linked_list.rs index d03c1969b5b70..70c344e49b76a 100644 --- a/verifast-proofs/alloc/collections/linked_list.rs-negative/original/linked_list.rs +++ b/verifast-proofs/alloc/collections/linked_list.rs-negative/original/linked_list.rs @@ -1031,7 +1031,7 @@ impl LinkedList { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// In other words, remove all elements `e` for which `f(&mut e)` returns false. /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. /// @@ -1047,7 +1047,7 @@ impl LinkedList { /// d.push_front(2); /// d.push_front(3); /// - /// d.retain(|&x| x % 2 == 0); + /// d.retain(|&mut x| x % 2 == 0); /// /// assert_eq!(d.pop_front(), Some(2)); /// assert_eq!(d.pop_front(), None); @@ -1074,41 +1074,6 @@ impl LinkedList { /// ``` #[unstable(feature = "linked_list_retain", issue = "114135")] pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.retain_mut(|elem| f(elem)); - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` for which `f(&mut e)` returns false. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_retain)] - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// - /// d.push_front(1); - /// d.push_front(2); - /// d.push_front(3); - /// - /// d.retain_mut(|x| if *x % 2 == 0 { - /// *x += 1; - /// true - /// } else { - /// false - /// }); - /// assert_eq!(d.pop_front(), Some(3)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[unstable(feature = "linked_list_retain", issue = "114135")] - pub fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, { diff --git a/verifast-proofs/alloc/collections/linked_list.rs-negative/verified/linked_list.rs b/verifast-proofs/alloc/collections/linked_list.rs-negative/verified/linked_list.rs index dbf88b37f6a2b..80eaadddd2e31 100644 --- a/verifast-proofs/alloc/collections/linked_list.rs-negative/verified/linked_list.rs +++ b/verifast-proofs/alloc/collections/linked_list.rs-negative/verified/linked_list.rs @@ -1196,7 +1196,7 @@ impl LinkedList { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// In other words, remove all elements `e` for which `f(&mut e)` returns false. /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. /// @@ -1212,7 +1212,7 @@ impl LinkedList { /// d.push_front(2); /// d.push_front(3); /// - /// d.retain(|&x| x % 2 == 0); + /// d.retain(|&mut x| x % 2 == 0); /// /// assert_eq!(d.pop_front(), Some(2)); /// assert_eq!(d.pop_front(), None); @@ -1239,41 +1239,6 @@ impl LinkedList { /// ``` #[unstable(feature = "linked_list_retain", issue = "114135")] pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.retain_mut(|elem| f(elem)); - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` for which `f(&mut e)` returns false. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_retain)] - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// - /// d.push_front(1); - /// d.push_front(2); - /// d.push_front(3); - /// - /// d.retain_mut(|x| if *x % 2 == 0 { - /// *x += 1; - /// true - /// } else { - /// false - /// }); - /// assert_eq!(d.pop_front(), Some(3)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[unstable(feature = "linked_list_retain", issue = "114135")] - pub fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, { diff --git a/verifast-proofs/alloc/collections/linked_list.rs/original/linked_list.rs b/verifast-proofs/alloc/collections/linked_list.rs/original/linked_list.rs index d03c1969b5b70..70c344e49b76a 100644 --- a/verifast-proofs/alloc/collections/linked_list.rs/original/linked_list.rs +++ b/verifast-proofs/alloc/collections/linked_list.rs/original/linked_list.rs @@ -1031,7 +1031,7 @@ impl LinkedList { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// In other words, remove all elements `e` for which `f(&mut e)` returns false. /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. /// @@ -1047,7 +1047,7 @@ impl LinkedList { /// d.push_front(2); /// d.push_front(3); /// - /// d.retain(|&x| x % 2 == 0); + /// d.retain(|&mut x| x % 2 == 0); /// /// assert_eq!(d.pop_front(), Some(2)); /// assert_eq!(d.pop_front(), None); @@ -1074,41 +1074,6 @@ impl LinkedList { /// ``` #[unstable(feature = "linked_list_retain", issue = "114135")] pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.retain_mut(|elem| f(elem)); - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` for which `f(&mut e)` returns false. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_retain)] - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// - /// d.push_front(1); - /// d.push_front(2); - /// d.push_front(3); - /// - /// d.retain_mut(|x| if *x % 2 == 0 { - /// *x += 1; - /// true - /// } else { - /// false - /// }); - /// assert_eq!(d.pop_front(), Some(3)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[unstable(feature = "linked_list_retain", issue = "114135")] - pub fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, { diff --git a/verifast-proofs/alloc/collections/linked_list.rs/verified/linked_list.rs b/verifast-proofs/alloc/collections/linked_list.rs/verified/linked_list.rs index a6aa7d5ec4a00..8613e9b456571 100644 --- a/verifast-proofs/alloc/collections/linked_list.rs/verified/linked_list.rs +++ b/verifast-proofs/alloc/collections/linked_list.rs/verified/linked_list.rs @@ -1196,7 +1196,7 @@ impl LinkedList { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// In other words, remove all elements `e` for which `f(&mut e)` returns false. /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. /// @@ -1212,7 +1212,7 @@ impl LinkedList { /// d.push_front(2); /// d.push_front(3); /// - /// d.retain(|&x| x % 2 == 0); + /// d.retain(|&mut x| x % 2 == 0); /// /// assert_eq!(d.pop_front(), Some(2)); /// assert_eq!(d.pop_front(), None); @@ -1239,41 +1239,6 @@ impl LinkedList { /// ``` #[unstable(feature = "linked_list_retain", issue = "114135")] pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.retain_mut(|elem| f(elem)); - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` for which `f(&mut e)` returns false. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_retain)] - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// - /// d.push_front(1); - /// d.push_front(2); - /// d.push_front(3); - /// - /// d.retain_mut(|x| if *x % 2 == 0 { - /// *x += 1; - /// true - /// } else { - /// false - /// }); - /// assert_eq!(d.pop_front(), Some(3)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[unstable(feature = "linked_list_retain", issue = "114135")] - pub fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, {