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/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 95b0962b08241..541c99c828dc0 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -195,6 +195,25 @@ jobs: run: ./ci/update-musl.sh - run: cargo clippy --workspace --all-targets + build-custom: + name: Build custom target + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add rust-src + - uses: Swatinem/rust-cache@v2 + - run: | + # Ensure we can build with custom target.json files (these can interact + # poorly with build scripts) + cargo build -p compiler_builtins -p libm \ + --target etc/thumbv7em-none-eabi-renamed.json \ + -Zbuild-std=core + benchmarks: name: Benchmarks timeout-minutes: 20 @@ -331,6 +350,7 @@ jobs: success: needs: - benchmarks + - build-custom - clippy - extensive - miri diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs index 89b126ff2b2ed..b82581262f7b0 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/build.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -6,6 +6,5 @@ fn main() { println!("cargo::rerun-if-changed=../configure.rs"); let target = builtins_configure::Target::from_env(); - builtins_configure::configure_f16_f128(&target); builtins_configure::configure_aliases(&target); } diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index 87a89efb5a4fe..da29b5d313263 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -177,6 +177,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: cmp_f128_gt, sig: (a: f128, b: f128) -> CmpResult, @@ -189,6 +190,7 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] float_bench! { name: cmp_f128_unord, sig: (a: f128, b: f128) -> CmpResult, diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs index e8f4eb4dd22eb..5b2dcd12ef86f 100644 --- a/library/compiler-builtins/builtins-test/build.rs +++ b/library/compiler-builtins/builtins-test/build.rs @@ -116,5 +116,4 @@ fn main() { } builtins_configure::configure_aliases(&target); - builtins_configure::configure_f16_f128(&target); } diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs index 491915d9bb172..7d729364faefb 100644 --- a/library/compiler-builtins/builtins-test/tests/conv.rs +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -118,7 +118,7 @@ mod i_to_f { i128, __floattidf; } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), u32, __floatunsitf; @@ -129,7 +129,7 @@ mod i_to_f { i128, __floattitf; } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), u32, __floatunsikf; diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index 5ae653cc90cc4..e8327f9b4b865 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -147,7 +147,7 @@ mod float_div { f64, __divdf3, Double, all(); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] float! { f128, __divtf3, Quad, @@ -156,7 +156,7 @@ mod float_div { not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] float! { f128, __divkf3, Quad, not(feature = "no-sys-f128"); diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 27b9686eac644..8b7965bb2056d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -54,29 +54,26 @@ symcheck=(cargo run -p symbol-check --release) [[ "$target" = "wasm"* ]] && symcheck+=(--features wasm) symcheck+=(-- build-and-check) -"${symcheck[@]}" -p compiler_builtins --target "$target" -"${symcheck[@]}" -p compiler_builtins --target "$target" --release -"${symcheck[@]}" -p compiler_builtins --target "$target" --features c -"${symcheck[@]}" -p compiler_builtins --target "$target" --features c --release -"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-asm -"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-asm --release -"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 -"${symcheck[@]}" -p compiler_builtins --target "$target" --features no-f16-f128 --release +"${symcheck[@]}" "$target" -- -p compiler_builtins +"${symcheck[@]}" "$target" -- -p compiler_builtins --release +"${symcheck[@]}" "$target" -- -p compiler_builtins --features c +"${symcheck[@]}" "$target" -- -p compiler_builtins --features c --release +"${symcheck[@]}" "$target" -- -p compiler_builtins --features no-asm +"${symcheck[@]}" "$target" -- -p compiler_builtins --features no-asm --release +"${symcheck[@]}" "$target" -- -p compiler_builtins --features no-f16-f128 +"${symcheck[@]}" "$target" -- -p compiler_builtins --features no-f16-f128 --release run_intrinsics_test() { - args=( - --target "$target" --verbose \ - --manifest-path builtins-test-intrinsics/Cargo.toml - ) - args+=( "$@" ) + build_args=(--verbose --manifest-path builtins-test-intrinsics/Cargo.toml) + build_args+=("$@") # symcheck also checks the results of builtins-test-intrinsics - "${symcheck[@]}" "${args[@]}" + "${symcheck[@]}" "$target" -- "${build_args[@]}" # FIXME: we get access violations on Windows, our entrypoint may need to # be tweaked. if [ "${BUILD_ONLY:-}" != "1" ] && ! [[ "$target" = *"windows"* ]]; then - cargo run "${args[@]}" + cargo run --target "$target" "${build_args[@]}" fi } diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index c5446cd76e326..3ccb05f73fb84 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -19,6 +19,8 @@ links = "compiler-rt" bench = false doctest = false test = false +# make sure this crate isn't included in public standard library docs +doc = false [dependencies] core = { path = "../../core", optional = true } diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 018899faf1d44..8f51c12b535dc 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -2,7 +2,7 @@ mod configure; use std::env; -use configure::{Target, configure_aliases, configure_f16_f128}; +use configure::{Target, configure_aliases}; fn main() { println!("cargo::rerun-if-changed=build.rs"); @@ -12,7 +12,6 @@ fn main() { let cwd = env::current_dir().unwrap(); configure_check_cfg(); - configure_f16_f128(&target); configure_aliases(&target); configure_libm(&target); diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index d825f35a9aa05..9721ddf090c6f 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -1,6 +1,7 @@ // Configuration that is shared between `compiler_builtins` and `builtins_test`. -use std::env; +use std::process::{Command, Stdio}; +use std::{env, str}; #[derive(Debug)] #[allow(dead_code)] @@ -16,6 +17,8 @@ pub struct Target { pub pointer_width: u8, pub little_endian: bool, pub features: Vec, + pub reliable_f128: bool, + pub reliable_f16: bool, } impl Target { @@ -32,6 +35,26 @@ impl Target { .map(|s| s.to_lowercase().replace("_", "-")) .collect(); + // Query rustc for options that Cargo does not provide env for. The bootstrap hack is used + // to get consistent output regardless of channel (`f16`/`f128` config options are hidden + // on stable otherwise). + let mut cmd = Command::new(env::var("RUSTC").unwrap()); + cmd.args(["--print=cfg", "--target", &triple]) + .env("RUSTC_BOOTSTRAP", "1") + .stderr(Stdio::inherit()); + let out = cmd + .output() + .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}")); + let rustc_cfg = str::from_utf8(&out.stdout).unwrap(); + + // If we couldn't query `rustc` (e.g. a custom JSON target was used), make the safe + // choice and leave `f16` and `f128` disabled. + let rustc_output_ok = out.status.success(); + let reliable_f128 = + rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f128"); + let reliable_f16 = + rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f16"); + Self { triple, triple_split, @@ -51,6 +74,8 @@ impl Target { .split(",") .map(ToOwned::to_owned) .collect(), + reliable_f128, + reliable_f16, } } @@ -74,63 +99,24 @@ pub fn configure_aliases(target: &Target) { if target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base" { println!("cargo:rustc-cfg=thumb_1") } -} - -/// Configure whether or not `f16` and `f128` support should be enabled. -pub fn configure_f16_f128(target: &Target) { - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types and generates code that can be called - // without crashing (no infinite recursion). This does not mean that the platform doesn't have - // ABI or other bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let f16_enabled = match target.arch.as_str() { - // Unsupported - "arm64ec" => false, - // Selection failure - "s390x" => false, - // Infinite recursion - "csky" => false, - "hexagon" => false, - "powerpc" | "powerpc64" => false, - "sparc" | "sparc64" => false, - "wasm32" | "wasm64" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - let f128_enabled = match target.arch.as_str() { - // Unsupported (libcall is not supported) - "amdgpu" => false, - // Unsupported - "arm64ec" => false, - // FIXME(llvm20): fixed by - "mips64" | "mips64r6" => false, - // Selection failure - "nvptx64" => false, - // Selection failure - "powerpc64" if &target.os == "aix" => false, - // Selection failure - "sparc" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; + /* Not all backends support `f16` and `f128` to the same level on all architectures, so we + * need to disable things if the compiler may crash. See configuration at: + * * https://github.com/rust-lang/rust/blob/c65dccabacdfd6c8a7f7439eba13422fdd89b91e/compiler/rustc_codegen_llvm/src/llvm_util.rs#L367-L432 + * * https://github.com/rust-lang/rustc_codegen_gcc/blob/4b5c44b14166083eef8d71f15f5ea1f53fc976a0/src/lib.rs#L496-L507 + * * https://github.com/rust-lang/rustc_codegen_cranelift/blob/c713ffab3c6e28ab4b4dd4e392330f786ea657ad/src/lib.rs#L196-L226 + */ - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + // If the feature is set, disable both of these types. + let no_f16_f128 = target.cargo_features.iter().any(|s| s == "no-f16-f128"); println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - - if f16_enabled && !disable_both { + if target.reliable_f16 && !no_f16_f128 { println!("cargo::rustc-cfg=f16_enabled"); } - if f128_enabled && !disable_both { + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + if target.reliable_f128 && !no_f16_f128 { println!("cargo::rustc-cfg=f128_enabled"); } } diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs index 80392187c89b4..a72b30d29f0ba 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -5,7 +5,7 @@ use core::intrinsics; intrinsics! { #[unsafe(naked)] #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] - pub unsafe extern "C" fn __chkstk() { + pub unsafe extern "custom" fn __chkstk() { core::arch::naked_asm!( ".p2align 2", "lsl x16, x15, #4", diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index a7d84e49b3493..fbec93ca4312e 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -9,11 +9,10 @@ unsafe extern "C" { } // SAFETY: these are defined in compiler-builtins -// FIXME(extern_custom), this isn't always the correct ABI -unsafe extern "aapcs" { +unsafe extern "custom" { // AAPCS is not always the correct ABI for these intrinsics, but we only use this to // forward another `__aeabi_` call so it doesn't matter. - fn __aeabi_idiv(a: i32, b: i32) -> i32; + fn __aeabi_idiv(); } intrinsics! { @@ -21,7 +20,7 @@ intrinsics! { // custom calling convention which can't be implemented using a normal Rust function. #[unsafe(naked)] #[cfg(not(target_env = "msvc"))] - pub unsafe extern "C" fn __aeabi_uidivmod() { + pub unsafe extern "custom" fn __aeabi_uidivmod() { core::arch::naked_asm!( "push {{lr}}", "sub sp, sp, #4", @@ -35,7 +34,7 @@ intrinsics! { } #[unsafe(naked)] - pub unsafe extern "C" fn __aeabi_uldivmod() { + pub unsafe extern "custom" fn __aeabi_uldivmod() { core::arch::naked_asm!( "push {{r4, lr}}", "sub sp, sp, #16", @@ -51,7 +50,7 @@ intrinsics! { } #[unsafe(naked)] - pub unsafe extern "C" fn __aeabi_idivmod() { + pub unsafe extern "custom" fn __aeabi_idivmod() { core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", "bl {trampoline}", @@ -64,7 +63,7 @@ intrinsics! { } #[unsafe(naked)] - pub unsafe extern "C" fn __aeabi_ldivmod() { + pub unsafe extern "custom" fn __aeabi_ldivmod() { core::arch::naked_asm!( "push {{r4, lr}}", "sub sp, sp, #16", @@ -135,8 +134,8 @@ intrinsics! { /// eight bytes. #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dst: *mut u8, src: *const u8, n: usize) { - debug_assert!(dst.addr() & 7 == 0); - debug_assert!(src.addr() & 7 == 0); + debug_assert!(dst.addr().is_multiple_of(8)); + debug_assert!(src.addr().is_multiple_of(8)); // SAFETY: memcpy preconditions apply, less strict alignment. unsafe { __aeabi_memcpy4(dst, src, n) }; @@ -161,8 +160,8 @@ intrinsics! { /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove4(dst: *mut u8, src: *const u8, n: usize) { - debug_assert!(dst.addr() & 3 == 0); - debug_assert!(src.addr() & 3 == 0); + debug_assert!(dst.addr().is_multiple_of(4)); + debug_assert!(src.addr().is_multiple_of(4)); // SAFETY: same preconditions, less strict aligment. unsafe { __aeabi_memmove(dst, src, n) }; @@ -176,8 +175,8 @@ intrinsics! { /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove8(dst: *mut u8, src: *const u8, n: usize) { - debug_assert!(dst.addr() & 7 == 0); - debug_assert!(src.addr() & 7 == 0); + debug_assert!(dst.addr().is_multiple_of(8)); + debug_assert!(src.addr().is_multiple_of(8)); // SAFETY: memmove preconditions apply, less strict alignment. unsafe { __aeabi_memmove(dst, src, n) }; @@ -236,7 +235,7 @@ intrinsics! { /// eight bytes. #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset8(dst: *mut u8, n: usize, c: i32) { - debug_assert!(dst.addr() & 7 == 0); + debug_assert!(dst.addr().is_multiple_of(8)); // SAFETY: memset preconditions apply, less strict alignment. unsafe { __aeabi_memset4(dst, n, c) }; @@ -261,7 +260,7 @@ intrinsics! { /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut u8, n: usize) { - debug_assert!(dst.addr() & 3 == 0); + debug_assert!(dst.addr().is_multiple_of(4)); // SAFETY: memclr preconditions apply, less strict alignment. unsafe { __aeabi_memset4(dst, n, 0) }; @@ -275,7 +274,7 @@ intrinsics! { /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut u8, n: usize) { - debug_assert!(dst.addr() & 7 == 0); + debug_assert!(dst.addr().is_multiple_of(8)); // SAFETY: memclr preconditions apply, less strict alignment. unsafe { __aeabi_memset4(dst, n, 0) }; diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index b9dee63c4cc7a..017a81ac91490 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -44,7 +44,7 @@ intrinsics! { } #[unsafe(naked)] - pub unsafe extern "C" fn __udivmodqi4() { + pub unsafe extern "custom" fn __udivmodqi4() { // compute unsigned 8-bit `n / d` and `n % d`. // // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 1cec39d8b41bb..fe0ad81dd3a3d 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -1,11 +1,13 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![cfg_attr(all(target_family = "wasm"), feature(wasm_numeric_instr))] +#![feature(abi_custom)] #![feature(abi_unadjusted)] #![feature(asm_experimental_arch)] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] +#![feature(asm_cfg)] #![feature(naked_functions)] #![feature(repr_simd)] #![feature(macro_metavar_expr_concat)] diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs index 1441fd73b8d6f..f4105dde57e66 100644 --- a/library/compiler-builtins/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -52,36 +52,12 @@ // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // -// FIXME(abi_custom): This function is unsafe because it uses a custom ABI, -// it does not actually match `extern "C"`. -// // The ABI here is that the stack frame size is located in `%rax`. Upon // return we're not supposed to modify `%rsp` or `%rax`. #[cfg(target_arch = "x86_64")] #[unsafe(naked)] #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_probestack() { - #[cfg(not(all(target_env = "sgx", target_vendor = "fortanix")))] - macro_rules! ret { - () => { - "ret" - }; - } - - #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] - macro_rules! ret { - // for this target, [manually patch for LVI]. - // - // [manually patch for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions - () => { - " - pop %r11 - lfence - jmp *%r11 - " - }; - } - +pub unsafe extern "custom" fn __rust_probestack() { core::arch::naked_asm!( " .cfi_startproc @@ -131,8 +107,18 @@ pub unsafe extern "C" fn __rust_probestack() { .cfi_def_cfa_register %rsp .cfi_adjust_cfa_offset -8 ", - ret!(), - " + #[cfg(not(all(target_env = "sgx", target_vendor = "fortanix")))] + " ret", + #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] + " + // for this target, [manually patch for LVI]. + // + // [manually patch for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions + pop %r11 + lfence + jmp *%r11 + ", + " .cfi_endproc ", options(att_syntax) @@ -144,13 +130,10 @@ pub unsafe extern "C" fn __rust_probestack() { // that on Unix we're expected to restore everything as it was, this // function basically can't tamper with anything. // -// FIXME(abi_custom): This function is unsafe because it uses a custom ABI, -// it does not actually match `extern "C"`. -// // The ABI here is the same as x86_64, except everything is 32-bits large. #[unsafe(naked)] #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_probestack() { +pub unsafe extern "custom" fn __rust_probestack() { core::arch::naked_asm!( " .cfi_startproc @@ -192,9 +175,6 @@ pub unsafe extern "C" fn __rust_probestack() { // probestack function will also do things like _chkstk in MSVC. // So we need to sub %ax %sp in probestack when arch is x86. // -// FIXME(abi_custom): This function is unsafe because it uses a custom ABI, -// it does not actually match `extern "C"`. -// // REF: Rust commit(74e80468347) // rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805 // Comments in LLVM: @@ -203,7 +183,7 @@ pub unsafe extern "C" fn __rust_probestack() { // themselves. #[unsafe(naked)] #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_probestack() { +pub unsafe extern "custom" fn __rust_probestack() { core::arch::naked_asm!( " .cfi_startproc diff --git a/library/compiler-builtins/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs index 01152d9c79869..16e50922a9454 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86.rs @@ -2,7 +2,7 @@ use core::intrinsics; -// NOTE These functions are implemented using assembly because they using a custom +// NOTE These functions are implemented using assembly because they use a custom // calling convention which can't be implemented using a normal Rust function // NOTE These functions are never mangled as they are not tested against compiler-rt @@ -13,10 +13,10 @@ intrinsics! { any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] - pub unsafe extern "C" fn __chkstk() { + pub unsafe extern "custom" fn __chkstk() { core::arch::naked_asm!( - "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" - options(att_syntax) + "jmp {}", // Jump to __alloca since fallthrough may be unreliable" + sym crate::x86::_alloca::_alloca, ); } @@ -25,7 +25,7 @@ intrinsics! { any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] - pub unsafe extern "C" fn _alloca() { + pub unsafe extern "custom" fn _alloca() { // __chkstk and _alloca are the same function core::arch::naked_asm!( "push %ecx", diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs index fc1190f79b237..9b7133b482e4e 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -2,7 +2,7 @@ use core::intrinsics; -// NOTE These functions are implemented using assembly because they using a custom +// NOTE These functions are implemented using assembly because they use a custom // calling convention which can't be implemented using a normal Rust function // NOTE These functions are never mangled as they are not tested against compiler-rt @@ -17,7 +17,7 @@ intrinsics! { ), not(feature = "no-asm") ))] - pub unsafe extern "C" fn ___chkstk_ms() { + pub unsafe extern "custom" fn ___chkstk_ms() { core::arch::naked_asm!( "push %rcx", "push %rax", diff --git a/library/compiler-builtins/crates/josh-sync/Cargo.toml b/library/compiler-builtins/crates/josh-sync/Cargo.toml index 1f3bb376d6d91..8e2e891db5426 100644 --- a/library/compiler-builtins/crates/josh-sync/Cargo.toml +++ b/library/compiler-builtins/crates/josh-sync/Cargo.toml @@ -5,3 +5,4 @@ publish = false [dependencies] directories = "6.0.0" +regex-lite = "0.1.6" diff --git a/library/compiler-builtins/crates/josh-sync/src/sync.rs b/library/compiler-builtins/crates/josh-sync/src/sync.rs index 003cf187d8301..2d89d2d1cea2f 100644 --- a/library/compiler-builtins/crates/josh-sync/src/sync.rs +++ b/library/compiler-builtins/crates/josh-sync/src/sync.rs @@ -1,8 +1,11 @@ +use std::borrow::Cow; use std::net::{SocketAddr, TcpStream}; use std::process::{Command, Stdio, exit}; use std::time::Duration; use std::{env, fs, process, thread}; +use regex_lite::Regex; + const JOSH_PORT: u16 = 42042; const DEFAULT_PR_BRANCH: &str = "update-builtins"; @@ -77,6 +80,7 @@ impl GitSync { "--depth=1", ]); let new_summary = check_output(["git", "log", "-1", "--format=%h %s", &new_upstream_base]); + let new_summary = replace_references(&new_summary, &self.upstream_repo); // Update rust-version file. As a separate commit, since making it part of // the merge has confused the heck out of josh in the past. @@ -297,6 +301,13 @@ fn check_output_cfg(prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) -> String::from_utf8(out.stdout.trim_ascii().to_vec()).expect("non-UTF8 output") } +/// Replace `#1234`-style issue/PR references with `repo#1234` to ensure links work across +/// repositories. +fn replace_references<'a>(s: &'a str, repo: &str) -> Cow<'a, str> { + let re = Regex::new(r"\B(?P#\d+)\b").unwrap(); + re.replace(s, &format!("{repo}$id")) +} + /// Create a wrapper that stops Josh on drop. pub struct Josh(process::Child); @@ -369,3 +380,22 @@ impl Drop for Josh { self.0.kill().expect("failed to SIGKILL josh-proxy"); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_replace() { + assert_eq!(replace_references("#1234", "r-l/rust"), "r-l/rust#1234"); + assert_eq!(replace_references("#1234x", "r-l/rust"), "#1234x"); + assert_eq!( + replace_references("merge #1234", "r-l/rust"), + "merge r-l/rust#1234" + ); + assert_eq!( + replace_references("foo/bar#1234", "r-l/rust"), + "foo/bar#1234" + ); + } +} diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 482da974ca89f..7efa1488f570e 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(let_chains)] - mod enums; mod parse; mod shared; diff --git a/library/compiler-builtins/crates/symbol-check/src/main.rs b/library/compiler-builtins/crates/symbol-check/src/main.rs index d83cd318d6a95..1312a71797032 100644 --- a/library/compiler-builtins/crates/symbol-check/src/main.rs +++ b/library/compiler-builtins/crates/symbol-check/src/main.rs @@ -8,7 +8,9 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use object::read::archive::{ArchiveFile, ArchiveMember}; -use object::{Object, ObjectSymbol, Symbol, SymbolKind, SymbolScope, SymbolSection}; +use object::{ + File as ObjFile, Object, ObjectSymbol, Symbol, SymbolKind, SymbolScope, SymbolSection, +}; use serde_json::Value; const CHECK_LIBRARIES: &[&str] = &["compiler_builtins", "builtins_test_intrinsics"]; @@ -16,10 +18,12 @@ const CHECK_EXTENSIONS: &[Option<&str>] = &[Some("rlib"), Some("a"), Some("exe") const USAGE: &str = "Usage: - symbol-check build-and-check CARGO_ARGS ... + symbol-check build-and-check [TARGET] -- CARGO_BUILD_ARGS ... -Cargo will get invoked with `CARGO_ARGS` and all output +Cargo will get invoked with `CARGO_ARGS` and the specified target. All output `compiler_builtins*.rlib` files will be checked. + +If TARGET is not specified, the host target is used. "; fn main() { @@ -28,13 +32,13 @@ fn main() { let args_ref = args.iter().map(String::as_str).collect::>(); match &args_ref[1..] { - ["build-and-check", rest @ ..] if !rest.is_empty() => { - let paths = exec_cargo_with_args(rest); - for path in paths { - println!("Checking {}", path.display()); - verify_no_duplicates(&path); - verify_core_symbols(&path); - } + ["build-and-check", target, "--", args @ ..] if !args.is_empty() => { + check_cargo_args(args); + run_build_and_check(target, args); + } + ["build-and-check", "--", args @ ..] if !args.is_empty() => { + check_cargo_args(args); + run_build_and_check(&host_target(), args); } _ => { println!("{USAGE}"); @@ -43,14 +47,54 @@ fn main() { } } +/// Make sure `--target` isn't passed to avoid confusion (since it should be proivded only once, +/// positionally). +fn check_cargo_args(args: &[&str]) { + for arg in args { + assert!( + !arg.contains("--target"), + "target must be passed positionally. {USAGE}" + ); + } +} + +fn run_build_and_check(target: &str, args: &[&str]) { + let paths = exec_cargo_with_args(target, args); + for path in paths { + println!("Checking {}", path.display()); + let archive = Archive::from_path(&path); + + verify_no_duplicates(&archive); + verify_core_symbols(&archive); + } +} + +fn host_target() -> String { + let out = Command::new("rustc") + .arg("--version") + .arg("--verbose") + .output() + .unwrap(); + assert!(out.status.success()); + let out = String::from_utf8(out.stdout).unwrap(); + out.lines() + .find_map(|s| s.strip_prefix("host: ")) + .unwrap() + .to_owned() +} + /// Run `cargo build` with the provided additional arguments, collecting the list of created /// libraries. -fn exec_cargo_with_args(args: &[&str]) -> Vec { +fn exec_cargo_with_args(target: &str, args: &[&str]) -> Vec { let mut cmd = Command::new("cargo"); - cmd.arg("build") - .arg("--message-format=json") - .args(args) - .stdout(Stdio::piped()); + cmd.args([ + "build", + "--target", + target, + "--message-format=json-diagnostic-rendered-ansi", + ]) + .args(args) + .stdout(Stdio::piped()); println!("running: {cmd:?}"); let mut child = cmd.spawn().expect("failed to launch Cargo"); @@ -61,11 +105,21 @@ fn exec_cargo_with_args(args: &[&str]) -> Vec { for line in reader.lines() { let line = line.expect("failed to read line"); - println!("{line}"); // tee to stdout - - // Select only steps that create files let j: Value = serde_json::from_str(&line).expect("failed to deserialize"); - if j["reason"] != "compiler-artifact" { + let reason = &j["reason"]; + + // Forward output that is meant to be user-facing + if reason == "compiler-message" { + println!("{}", j["message"]["rendered"].as_str().unwrap()); + } else if reason == "build-finished" { + println!("build finshed. success: {}", j["success"]); + } else if reason == "build-script-executed" { + let pretty = serde_json::to_string_pretty(&j).unwrap(); + println!("build script output: {pretty}",); + } + + // Only interested in the artifact list now + if reason != "compiler-artifact" { continue; } @@ -133,12 +187,12 @@ impl SymInfo { /// Note that this will also locate cases where a symbol is weakly defined in more than one place. /// Technically there are no linker errors that will come from this, but it keeps our binary more /// straightforward and saves some distribution size. -fn verify_no_duplicates(path: &Path) { +fn verify_no_duplicates(archive: &Archive) { let mut syms = BTreeMap::::new(); let mut dups = Vec::new(); let mut found_any = false; - for_each_symbol(path, |symbol, member| { + archive.for_each_symbol(|symbol, member| { // Only check defined globals if !symbol.is_global() || symbol.is_undefined() { return; @@ -185,12 +239,12 @@ fn verify_no_duplicates(path: &Path) { } /// Ensure that there are no references to symbols from `core` that aren't also (somehow) defined. -fn verify_core_symbols(path: &Path) { +fn verify_core_symbols(archive: &Archive) { let mut defined = BTreeSet::new(); let mut undefined = Vec::new(); let mut has_symbols = false; - for_each_symbol(path, |symbol, member| { + archive.for_each_symbol(|symbol, member| { has_symbols = true; // Find only symbols from `core` @@ -219,14 +273,40 @@ fn verify_core_symbols(path: &Path) { println!(" success: no undefined references to core found"); } -/// For a given archive path, do something with each symbol. -fn for_each_symbol(path: &Path, mut f: impl FnMut(Symbol, &ArchiveMember)) { - let data = fs::read(path).expect("reading file failed"); - let archive = ArchiveFile::parse(data.as_slice()).expect("archive parse failed"); - for member in archive.members() { - let member = member.expect("failed to access member"); - let obj_data = member.data(&*data).expect("failed to access object"); - let obj = object::File::parse(obj_data).expect("failed to parse object"); - obj.symbols().for_each(|sym| f(sym, &member)); +/// Thin wrapper for owning data used by `object`. +struct Archive { + data: Vec, +} + +impl Archive { + fn from_path(path: &Path) -> Self { + Self { + data: fs::read(path).expect("reading file failed"), + } + } + + fn file(&self) -> ArchiveFile<'_> { + ArchiveFile::parse(self.data.as_slice()).expect("archive parse failed") + } + + /// For a given archive, do something with each object file. + fn for_each_object(&self, mut f: impl FnMut(ObjFile, &ArchiveMember)) { + let archive = self.file(); + + for member in archive.members() { + let member = member.expect("failed to access member"); + let obj_data = member + .data(self.data.as_slice()) + .expect("failed to access object"); + let obj = ObjFile::parse(obj_data).expect("failed to parse object"); + f(obj, &member); + } + } + + /// For a given archive, do something with each symbol. + fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ArchiveMember)) { + self.for_each_object(|obj, member| { + obj.symbols().for_each(|sym| f(sym, member)); + }); } } diff --git a/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json b/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json new file mode 100644 index 0000000000000..81273d44e4965 --- /dev/null +++ b/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json @@ -0,0 +1,23 @@ +{ + "abi": "eabi", + "arch": "arm", + "c-enum-min-bits": 8, + "crt-objects-fallback": "false", + "data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + "emit-debug-gdb-scripts": false, + "frame-pointer": "always", + "linker": "rust-lld", + "linker-flavor": "gnu-lld", + "llvm-floatabi": "soft", + "llvm-target": "thumbv7em-none-eabi", + "max-atomic-width": 32, + "metadata": { + "description": "Bare ARMv7E-M", + "host_tools": false, + "std": false, + "tier": 2 + }, + "panic-strategy": "abort", + "relocation-model": "static", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index a0928a29f9992..02ee13f804f16 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -119,6 +119,22 @@ fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { } } +#[library_benchmark] +#[bench::linspace(setup_u256_add())] +fn icount_bench_u256_sub(cases: Vec<(u256, u256)>) { + for (x, y) in cases.iter().copied() { + black_box(black_box(x) - black_box(y)); + } +} + +#[library_benchmark] +#[bench::linspace(setup_u256_shift())] +fn icount_bench_u256_shl(cases: Vec<(u256, u32)>) { + for (x, y) in cases.iter().copied() { + black_box(black_box(x) << black_box(y)); + } +} + #[library_benchmark] #[bench::linspace(setup_u256_shift())] fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { @@ -129,7 +145,7 @@ fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { library_benchmark_group!( name = icount_bench_u128_group; - benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_add, icount_bench_u256_shr + benchmarks = icount_bench_u128_widen_mul, icount_bench_u256_add, icount_bench_u256_sub, icount_bench_u256_shl, icount_bench_u256_shr ); #[library_benchmark] diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs index 8cbb3ad226f67..d1c5cfbcc586d 100644 --- a/library/compiler-builtins/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -111,12 +111,54 @@ fn mp_u256_add() { let y = random_u256(&mut rng); assign_bigint(&mut bx, x); assign_bigint(&mut by, y); - let actual = x + y; + let actual = if u256::MAX - x >= y { + x + y + } else { + // otherwise (u256::MAX - x) < y, so the wrapped result is + // (x + y) - (u256::MAX + 1) == y - (u256::MAX - x) - 1 + y - (u256::MAX - x) - 1_u128.widen() + }; bx += &by; check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); } } +#[test] +fn mp_u256_sub() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + + // since the operators (may) panic on overflow, + // we should test something that doesn't + let actual = if x >= y { x - y } else { y - x }; + bx -= &by; + bx.abs_mut(); + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_shl() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let shift: u32 = rng.random_range(0..256); + assign_bigint(&mut bx, x); + let actual = x << shift; + bx <<= shift; + check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); + } +} + #[test] fn mp_u256_shr() { let mut rng = ChaCha8Rng::from_seed(*SEED); @@ -124,7 +166,7 @@ fn mp_u256_shr() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); - let shift: u32 = rng.random_range(0..255); + let shift: u32 = rng.random_range(0..256); assign_bigint(&mut bx, x); let actual = x >> shift; bx >>= shift; diff --git a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs index f2ba6a4a0e3e6..e04e00c6d743a 100644 --- a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs @@ -197,15 +197,15 @@ impl Progress { fn update(&self, completed: u64, input: impl fmt::Debug) { // Infrequently update the progress bar. - if completed % 20_000 == 0 { + if completed.is_multiple_of(20_000) { self.pb.set_position(completed); } - if completed % 500_000 == 0 { + if completed.is_multiple_of(500_000) { self.pb.set_message(format!("input: {input:<24?}")); } - if !self.is_tty && completed % 5_000_000 == 0 { + if !self.is_tty && completed.is_multiple_of(5_000_000) { let len = self.pb.length().unwrap_or_default(); eprintln!( "[{elapsed:3?}s {percent:3.0}%] {name} \ diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 2a497c7b11790..f9100d2d58b26 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -1,7 +1,8 @@ // Configuration shared with both libm and libm-test -use std::env; use std::path::PathBuf; +use std::process::{Command, Stdio}; +use std::{env, str}; #[allow(dead_code)] pub struct Config { @@ -9,6 +10,7 @@ pub struct Config { pub out_dir: PathBuf, pub opt_level: String, pub cargo_features: Vec, + pub target_triple: String, pub target_arch: String, pub target_env: String, pub target_family: Option, @@ -16,10 +18,13 @@ pub struct Config { pub target_string: String, pub target_vendor: String, pub target_features: Vec, + pub reliable_f128: bool, + pub reliable_f16: bool, } impl Config { pub fn from_env() -> Self { + let target_triple = env::var("TARGET").unwrap(); let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); @@ -28,7 +33,28 @@ impl Config { .map(|s| s.to_lowercase().replace("_", "-")) .collect(); + // Query rustc for options that Cargo does not provide env for. The bootstrap hack is used + // to get consistent output regardless of channel (`f16`/`f128` config options are hidden + // on stable otherwise). + let mut cmd = Command::new(env::var("RUSTC").unwrap()); + cmd.args(["--print=cfg", "--target", &target_triple]) + .env("RUSTC_BOOTSTRAP", "1") + .stderr(Stdio::inherit()); + let out = cmd + .output() + .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}")); + let rustc_cfg = str::from_utf8(&out.stdout).unwrap(); + + // If we couldn't query `rustc` (e.g. a custom JSON target was used), make the safe + // choice and leave `f16` and `f128` disabled. + let rustc_output_ok = out.status.success(); + let reliable_f128 = + rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f128"); + let reliable_f16 = + rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f16"); + Self { + target_triple, manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), opt_level: env::var("OPT_LEVEL").unwrap(), @@ -40,6 +66,8 @@ impl Config { target_string: env::var("TARGET").unwrap(), target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), target_features, + reliable_f128, + reliable_f16, } } } @@ -128,62 +156,18 @@ fn emit_f16_f128_cfg(cfg: &Config) { return; } - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types and generates code that can be called - // without crashing (no infinite recursion). This does not mean that the platform doesn't have - // ABI or other bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let f16_enabled = match cfg.target_arch.as_str() { - // Unsupported - "arm64ec" => false, - // Selection failure - "s390x" => false, - // Infinite recursion - // FIXME(llvm): loongarch fixed by - "csky" => false, - "hexagon" => false, - "loongarch64" => false, - "mips" | "mips64" | "mips32r6" | "mips64r6" => false, - "powerpc" | "powerpc64" => false, - "sparc" | "sparc64" => false, - "wasm32" | "wasm64" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - let f128_enabled = match cfg.target_arch.as_str() { - // Unsupported (libcall is not supported) - "amdgpu" => false, - // Unsupported - "arm64ec" => false, - // Selection failure - "mips64" | "mips64r6" => false, - // Selection failure - "nvptx64" => false, - // Selection failure - "powerpc64" if &cfg.target_os == "aix" => false, - // Selection failure - "sparc" => false, - // Most everything else works as of LLVM 19 - _ => true, - }; - - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + /* See the compiler-builtins configure file for info about the meaning of these options */ - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + // If the feature is set, disable both of these types. + let no_f16_f128 = cfg.cargo_features.iter().any(|s| s == "no-f16-f128"); - if f16_enabled && !disable_both { + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + if cfg.reliable_f16 && !no_f16_f128 { println!("cargo:rustc-cfg=f16_enabled"); } - if f128_enabled && !disable_both { + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + if cfg.reliable_f128 && !no_f16_f128 { println!("cargo:rustc-cfg=f128_enabled"); } } diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index 8a52d86cc9827..b7f1285424956 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -11,10 +11,10 @@ const U128_LO_MASK: u128 = u64::MAX as u128; /// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)] pub struct u256 { - pub lo: u128, pub hi: u128, + pub lo: u128, } impl u256 { @@ -28,17 +28,17 @@ impl u256 { pub fn signed(self) -> i256 { i256 { lo: self.lo, - hi: self.hi, + hi: self.hi as i128, } } } /// A 256-bit signed integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)] pub struct i256 { + pub hi: i128, pub lo: u128, - pub hi: u128, } impl i256 { @@ -47,7 +47,7 @@ impl i256 { pub fn unsigned(self) -> u256 { u256 { lo: self.lo, - hi: self.hi, + hi: self.hi as u128, } } } @@ -73,17 +73,17 @@ impl MinInt for i256 { type Unsigned = u256; - const SIGNED: bool = false; + const SIGNED: bool = true; const BITS: u32 = 256; const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; const MIN: Self = Self { - lo: 0, - hi: 1 << 127, + lo: u128::MIN, + hi: i128::MIN, }; const MAX: Self = Self { lo: u128::MAX, - hi: u128::MAX >> 1, + hi: i128::MAX, }; } @@ -109,60 +109,86 @@ macro_rules! impl_common { } } - impl ops::Shl for $ty { + impl ops::Add for $ty { type Output = Self; - fn shl(self, _rhs: u32) -> Self::Output { - unimplemented!("only used to meet trait bounds") + fn add(self, rhs: Self) -> Self::Output { + let (lo, carry) = self.lo.overflowing_add(rhs.lo); + let (hi, of) = Int::carrying_add(self.hi, rhs.hi, carry); + debug_assert!(!of, "attempt to add with overflow"); + Self { lo, hi } } } - }; -} -impl_common!(i256); -impl_common!(u256); + impl ops::Sub for $ty { + type Output = Self; -impl ops::Add for u256 { - type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + let (lo, borrow) = self.lo.overflowing_sub(rhs.lo); + let (hi, of) = Int::borrowing_sub(self.hi, rhs.hi, borrow); + debug_assert!(!of, "attempt to subtract with overflow"); + Self { lo, hi } + } + } - fn add(self, rhs: Self) -> Self::Output { - let (lo, carry) = self.lo.overflowing_add(rhs.lo); - let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); + impl ops::Shl for $ty { + type Output = Self; - Self { lo, hi } - } -} + fn shl(mut self, rhs: u32) -> Self::Output { + debug_assert!(rhs < Self::BITS, "attempt to shift left with overflow"); -impl ops::Shr for u256 { - type Output = Self; + let half_bits = Self::BITS / 2; + let low_mask = half_bits - 1; + let s = rhs & low_mask; - fn shr(mut self, rhs: u32) -> Self::Output { - debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); - if rhs >= Self::BITS { - return Self::ZERO; - } + let lo = self.lo; + let hi = self.hi; - if rhs == 0 { - return self; - } + self.lo = lo << s; - if rhs < 128 { - self.lo >>= rhs; - self.lo |= self.hi << (128 - rhs); - } else { - self.lo = self.hi >> (rhs - 128); + if rhs & half_bits == 0 { + self.hi = (lo >> (low_mask ^ s) >> 1) as _; + self.hi |= hi << s; + } else { + self.hi = self.lo as _; + self.lo = 0; + } + self + } } - if rhs < 128 { - self.hi >>= rhs; - } else { - self.hi = 0; - } + impl ops::Shr for $ty { + type Output = Self; - self - } + fn shr(mut self, rhs: u32) -> Self::Output { + debug_assert!(rhs < Self::BITS, "attempt to shift right with overflow"); + + let half_bits = Self::BITS / 2; + let low_mask = half_bits - 1; + let s = rhs & low_mask; + + let lo = self.lo; + let hi = self.hi; + + self.hi = hi >> s; + + #[allow(unused_comparisons)] + if rhs & half_bits == 0 { + self.lo = (hi << (low_mask ^ s) << 1) as _; + self.lo |= lo >> s; + } else { + self.lo = self.hi as _; + self.hi = if hi < 0 { !0 } else { 0 }; + } + self + } + } + }; } +impl_common!(i256); +impl_common!(u256); + impl HInt for u128 { type D = u256; @@ -200,7 +226,7 @@ impl HInt for u128 { } fn widen_hi(self) -> Self::D { - self.widen() << ::BITS + u256 { lo: 0, hi: self } } } @@ -208,11 +234,10 @@ impl HInt for i128 { type D = i256; fn widen(self) -> Self::D { - let mut ret = self.unsigned().zero_widen().signed(); - if self.is_negative() { - ret.hi = u128::MAX; + i256 { + lo: self as u128, + hi: if self < 0 { -1 } else { 0 }, } - ret } fn zero_widen(self) -> Self::D { @@ -228,7 +253,7 @@ impl HInt for i128 { } fn widen_hi(self) -> Self::D { - self.widen() << ::BITS + i256 { lo: 0, hi: self } } } @@ -252,6 +277,6 @@ impl DInt for i256 { } fn hi(self) -> Self::H { - self.hi as i128 + self.hi } } diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index d2010f0216e35..d54706c726072 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -36,7 +36,7 @@ fn widen_i128() { (LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, - hi: u128::MAX + hi: -1, } ); assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); @@ -275,3 +275,64 @@ fn shr_u256_overflow() { assert_eq!(u256::MAX >> 257, u256::ZERO); assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); } + +#[test] +fn u256_ord() { + let _1 = u256::ONE; + let _2 = _1 + _1; + for x in u8::MIN..u8::MAX { + let y = x + 1; + let wx = (x as u128).widen_hi(); + let wy = (y as u128).widen_hi(); + assert!([wx, wx + _1, wx + _2, wy, wy + _1, wy + _2].is_sorted()); + } +} +#[test] +fn i256_ord() { + let _1 = i256::ONE; + let _2 = _1 + _1; + for x in i8::MIN..i8::MAX { + let y = x + 1; + let wx = (x as i128).widen_hi(); + let wy = (y as i128).widen_hi(); + assert!([wx, wx + _1, wx + _2, wy - _2, wy - _1, wy].is_sorted()); + } +} + +#[test] +fn u256_shifts() { + let _1 = u256::ONE; + for k in 0..255 { + let x = _1 << k; + let x2 = _1 << (k + 1); + assert!(x < x2); + assert_eq!(x << 1, x2); + assert_eq!(x + x, x2); + assert_eq!(x >> k, _1); + assert_eq!(x2 >> (k + 1), _1); + } +} +#[test] +fn i256_shifts() { + let _1 = i256::ONE; + for k in 0..254 { + let x = _1 << k; + let x2 = _1 << (k + 1); + assert!(x < x2); + assert_eq!(x << 1, x2); + assert_eq!(x + x, x2); + assert_eq!(x >> k, _1); + assert_eq!(x2 >> (k + 1), _1); + } + + let min = _1 << 255; + assert_eq!(min, i256::MIN); + let mut x = min; + for k in 0..255 { + assert_eq!(x, min >> k); + let y = x >> 1; + assert_eq!(y + y, x); + assert!(x < y); + x = y; + } +} diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 9b29e2f4561d5..9d8826dfed3fe 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -37,8 +37,6 @@ pub trait Int: + fmt::Display + fmt::Binary + fmt::LowerHex - + PartialEq - + PartialOrd + ops::AddAssign + ops::SubAssign + ops::MulAssign @@ -102,7 +100,10 @@ pub trait Int: fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn overflowing_sub(self, other: Self) -> (Self, bool); + fn carrying_add(self, other: Self, carry: bool) -> (Self, bool); + fn borrowing_sub(self, other: Self, borrow: bool) -> (Self, bool); fn leading_zeros(self) -> u32; + fn trailing_zeros(self) -> u32; fn ilog2(self) -> u32; } @@ -168,12 +169,30 @@ macro_rules! int_impl_common { ::leading_zeros(self) } + fn trailing_zeros(self) -> u32 { + ::trailing_zeros(self) + } + fn ilog2(self) -> u32 { // On our older MSRV, this resolves to the trait method. Which won't actually work, // but this is only called behind other gates. #[allow(clippy::incompatible_msrv)] ::ilog2(self) } + + fn carrying_add(self, other: Self, carry: bool) -> (Self, bool) { + let (ab, of1) = self.overflowing_add(other); + let (abc, of2) = ab.overflowing_add(Self::from_bool(carry)); + // `of1 && of2` is possible with signed integers if a negative sum + // overflows to `MAX` and adding the carry overflows again back to `MIN` + (abc, of1 ^ of2) + } + + fn borrowing_sub(self, other: Self, borrow: bool) -> (Self, bool) { + let (ab, of1) = self.overflowing_sub(other); + let (abc, of2) = ab.overflowing_sub(Self::from_bool(borrow)); + (abc, of1 ^ of2) + } }; } diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json deleted file mode 100644 index ac736eae686b4..0000000000000 --- a/library/compiler-builtins/thumbv6m-linux-eabi.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "abi-blacklist": [ - "stdcall", - "fastcall", - "vectorcall", - "win64", - "sysv64" - ], - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "env": "", - "executables": true, - "features": "+strict-align", - "linker": "arm-none-eabi-gcc", - "linker-flavor": "gcc", - "llvm-target": "thumbv6m-none-eabi", - "max-atomic-width": 0, - "os": "linux", - "panic-strategy": "abort", - "pre-link-args": { - "gcc": ["-nostartfiles"] - }, - "relocation-model": "static", - "target-endian": "little", - "target-pointer-width": "32", - "target-c-int-width": "32", - "vendor": "" -} diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json deleted file mode 100644 index b6d4a6bda7bac..0000000000000 --- a/library/compiler-builtins/thumbv7em-linux-eabi.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "abi-blacklist": [ - "stdcall", - "fastcall", - "vectorcall", - "win64", - "sysv64" - ], - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "env": "", - "executables": true, - "linker": "arm-none-eabi-gcc", - "linker-flavor": "gcc", - "llvm-target": "thumbv7em-none-eabi", - "max-atomic-width": 32, - "os": "linux", - "panic-strategy": "abort", - "pre-link-args": { - "gcc": ["-nostartfiles"] - }, - "relocation-model": "static", - "target-endian": "little", - "target-pointer-width": "32", - "target-c-int-width": "32", - "vendor": "" -} diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json deleted file mode 100644 index 81cfcd48d56ce..0000000000000 --- a/library/compiler-builtins/thumbv7em-linux-eabihf.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "abi-blacklist": [ - "stdcall", - "fastcall", - "vectorcall", - "win64", - "sysv64" - ], - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "env": "", - "executables": true, - "features": "+vfp4,+d16,+fp-only-sp", - "linker": "arm-none-eabi-gcc", - "linker-flavor": "gcc", - "llvm-target": "thumbv7em-none-eabihf", - "max-atomic-width": 32, - "os": "linux", - "panic-strategy": "abort", - "pre-link-args": { - "gcc": ["-nostartfiles"] - }, - "relocation-model": "static", - "target-endian": "little", - "target-pointer-width": "32", - "target-c-int-width": "32", - "vendor": "" -} diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json deleted file mode 100644 index abe037c5bef88..0000000000000 --- a/library/compiler-builtins/thumbv7m-linux-eabi.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "abi-blacklist": [ - "stdcall", - "fastcall", - "vectorcall", - "win64", - "sysv64" - ], - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "env": "", - "executables": true, - "linker": "arm-none-eabi-gcc", - "linker-flavor": "gcc", - "llvm-target": "thumbv7m-none-eabi", - "max-atomic-width": 32, - "os": "linux", - "panic-strategy": "abort", - "pre-link-args": { - "gcc": ["-nostartfiles"] - }, - "relocation-model": "static", - "target-endian": "little", - "target-pointer-width": "32", - "target-c-int-width": "32", - "vendor": "" -} diff --git a/library/compiler-builtins/triagebot.toml b/library/compiler-builtins/triagebot.toml new file mode 100644 index 0000000000000..ecc05da019517 --- /dev/null +++ b/library/compiler-builtins/triagebot.toml @@ -0,0 +1,21 @@ +## See for documentation +## of these features. + +# Warns when a PR contains merge commits +# Documentation at: https://forge.rust-lang.org/triagebot/no-merge.html +[no-merges] +exclude_titles = ["Update from"] + +# Canonicalize issue numbers to avoid closing the wrong issue +# when commits are included in subtrees, as well as warning links in commits. +# Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html +[issue-links] +check-commits = false + +# Prevents mentions in commits to avoid users being spammed +# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html +[no-mentions] + +# Enable issue transfers within the org +# Documentation at: https://forge.rust-lang.org/triagebot/transfer.html +[transfer] diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 8fffe185ea146..e676e88f4d4d8 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -26,14 +26,10 @@ optimize_for_size = [] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = [] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -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/any.rs b/library/core/src/any.rs index 01dce114592a1..39cdf6efda07a 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -707,19 +707,52 @@ impl dyn Any + Send + Sync { /// ``` #[derive(Clone, Copy, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] +#[lang = "type_id"] pub struct TypeId { - // We avoid using `u128` because that imposes higher alignment requirements on many platforms. - // See issue #115620 for more information. - t: (u64, u64), - #[cfg(feature = "debug_typeid")] - name: &'static str, + /// This needs to be an array of pointers, since there is provenance + /// in the first array field. This provenance knows exactly which type + /// the TypeId actually is, allowing CTFE and miri to operate based off it. + /// At runtime all the pointers in the array contain bits of the hash, making + /// the entire `TypeId` actually just be a `u128` hash of the type. + pub(crate) data: [*const (); 16 / size_of::<*const ()>()], } +// SAFETY: the raw pointer is always an integer #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for TypeId { +unsafe impl Send for TypeId {} +// SAFETY: the raw pointer is always an integer +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for TypeId {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +impl const PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { - self.t == other.t + #[cfg(miri)] + return crate::intrinsics::type_id_eq(*self, *other); + #[cfg(not(miri))] + { + let this = self; + crate::intrinsics::const_eval_select!( + @capture { this: &TypeId, other: &TypeId } -> bool: + if const { + crate::intrinsics::type_id_eq(*this, *other) + } else { + // Ideally we would just invoke `type_id_eq` unconditionally here, + // but since we do not MIR inline intrinsics, because backends + // may want to override them (and miri does!), MIR opts do not + // clean up this call sufficiently for LLVM to turn repeated calls + // of `TypeId` comparisons against one specific `TypeId` into + // a lookup table. + // SAFETY: We know that at runtime none of the bits have provenance and all bits + // are initialized. So we can just convert the whole thing to a `u128` and compare that. + unsafe { + crate::mem::transmute::<_, u128>(*this) == crate::mem::transmute::<_, u128>(*other) + } + } + ) + } } } @@ -742,19 +775,19 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { - let t: u128 = const { intrinsics::type_id::() }; - let t1 = (t >> 64) as u64; - let t2 = t as u64; - - TypeId { - t: (t1, t2), - #[cfg(feature = "debug_typeid")] - name: type_name::(), - } + const { intrinsics::type_id::() } } fn as_u128(self) -> u128 { - u128::from(self.t.0) << 64 | u128::from(self.t.1) + let mut bytes = [0; 16]; + + // This is a provenance-stripping memcpy. + for (i, chunk) in self.data.iter().copied().enumerate() { + let chunk = chunk.expose_provenance().to_ne_bytes(); + let start = i * chunk.len(); + bytes[start..(start + chunk.len())].copy_from_slice(&chunk); + } + u128::from_ne_bytes(bytes) } } @@ -774,22 +807,19 @@ impl hash::Hash for TypeId { // - It is correct to do so -- only hashing a subset of `self` is still // compatible with an `Eq` implementation that considers the entire // value, as ours does. - self.t.1.hash(state); + let data = + // SAFETY: The `offset` stays in-bounds, it just moves the pointer to the 2nd half of the `TypeId`. + // Only the first ptr-sized chunk ever has provenance, so that second half is always + // fine to read at integer type. + unsafe { crate::ptr::read_unaligned(self.data.as_ptr().cast::().offset(1)) }; + data.hash(state); } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TypeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - #[cfg(feature = "debug_typeid")] - { - write!(f, "TypeId({:#034x} = {})", self.as_u128(), self.name)?; - } - #[cfg(not(feature = "debug_typeid"))] - { - write!(f, "TypeId({:#034x})", self.as_u128())?; - } - Ok(()) + write!(f, "TypeId({:#034x})", self.as_u128()) } } 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..f1d7cf32969ce 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -54,10 +54,14 @@ )] #![allow(missing_docs)] +<<<<<<< HEAD use safety::{ensures, requires}; #[cfg(kani)] use crate::kani; +======= +use crate::ffi::va_list::{VaArgSafe, VaListImpl}; +>>>>>>> subtree/library use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; use crate::ptr; #[cfg(kani)] @@ -465,7 +469,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 +482,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 +492,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 +502,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] @@ -2279,7 +2288,7 @@ pub const fn const_eval_select( ) -> RET where G: FnOnce, - F: FnOnce; + F: const FnOnce; /// A macro to make it easier to invoke const_eval_select. Use as follows: /// ```rust,ignore (just a macro example) @@ -2296,7 +2305,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 +2552,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 */)] @@ -2743,7 +2752,20 @@ pub const fn type_name() -> &'static str; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_id() -> u128; +pub const fn type_id() -> crate::any::TypeId; + +/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the +/// same type. This is necessary because at const-eval time the actual discriminating +/// data is opaque and cannot be inspected directly. +/// +/// The stabilized version of this intrinsic is the [PartialEq] impl for [`core::any::TypeId`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_do_not_const_check] +pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { + a.data == b.data +} /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// @@ -3217,6 +3239,7 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize ) } +<<<<<<< HEAD #[cfg(kani)] #[unstable(feature = "kani", issue = "none")] mod verify { @@ -3898,3 +3921,26 @@ mod verify { status != AllocationStatus::Dangling && status != AllocationStatus::DeadObject } } +======= +/// 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<'_>); +>>>>>>> subtree/library 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 b59260d18cb3b..66bfb757daff9 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..6531d3ec766a9 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: @@ -207,9 +210,14 @@ pub trait PointeeSized { /// - `Trait` is dyn-compatible[^1]. /// - The type is sized. /// - The type outlives `'a`. +/// - Trait objects `dyn TraitA + AutoA... + 'a` implement `Unsize` +/// if all of these conditions are met: +/// - `TraitB` is a supertrait of `TraitA`. +/// - `AutoB...` is a subset of `AutoA...`. +/// - `'a` outlives `'b`. /// - 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 +863,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 +1072,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 e557161525152..f26aeaef249a6 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/function.rs b/library/core/src/ops/function.rs index df48c104410ca..763b60d88e510 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -72,7 +72,8 @@ use crate::marker::Tuple; )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(const_trait_impl) #[const_trait] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait Fn: FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -159,7 +160,8 @@ pub trait Fn: FnMut { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(const_trait_impl) #[const_trait] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait FnMut: FnOnce { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -238,7 +240,8 @@ pub trait FnMut: FnOnce { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(const_trait_impl) #[const_trait] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait FnOnce { /// The returned type after the call operator is used. #[lang = "fn_once_output"] @@ -254,9 +257,10 @@ mod impls { use crate::marker::Tuple; #[stable(feature = "rust1", since = "1.0.0")] - impl Fn for &F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const Fn for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -264,9 +268,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnMut for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -274,9 +279,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnOnce for &F where - F: Fn, + F: ~const Fn, { type Output = F::Output; @@ -286,9 +292,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &mut F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnMut for &mut F where - F: FnMut, + F: ~const FnMut, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -296,9 +303,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &mut F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnOnce for &mut F where - F: FnMut, + F: ~const FnMut, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { 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..db31bd2bbfb91 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1120,6 +1120,9 @@ impl [T] { /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the /// slice. /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1137,6 +1140,7 @@ impl [T] { /// /// [`chunks_exact`]: slice::chunks_exact /// [`rchunks`]: slice::rchunks + /// [`as_chunks`]: slice::as_chunks #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1156,6 +1160,9 @@ impl [T] { /// exactly `chunk_size` elements, and [`rchunks_mut`] for the same iterator but starting at /// the end of the slice. /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1177,6 +1184,7 @@ impl [T] { /// /// [`chunks_exact_mut`]: slice::chunks_exact_mut /// [`rchunks_mut`]: slice::rchunks_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1199,6 +1207,9 @@ impl [T] { /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the slice. /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1216,6 +1227,7 @@ impl [T] { /// /// [`chunks`]: slice::chunks /// [`rchunks_exact`]: slice::rchunks_exact + /// [`as_chunks`]: slice::chunks #[stable(feature = "chunks_exact", since = "1.31.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1239,6 +1251,9 @@ impl [T] { /// smaller chunk, and [`rchunks_exact_mut`] for the same iterator but starting at the end of /// the slice. /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1260,6 +1275,7 @@ impl [T] { /// /// [`chunks_mut`]: slice::chunks_mut /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut #[stable(feature = "chunks_exact", since = "1.31.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1316,7 +1332,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 +1528,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) }; @@ -1707,6 +1723,9 @@ impl [T] { /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning /// of the slice. /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1724,6 +1743,7 @@ impl [T] { /// /// [`rchunks_exact`]: slice::rchunks_exact /// [`chunks`]: slice::chunks + /// [`as_rchunks`]: slice::as_rchunks #[stable(feature = "rchunks", since = "1.31.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1743,6 +1763,9 @@ impl [T] { /// exactly `chunk_size` elements, and [`chunks_mut`] for the same iterator but starting at the /// beginning of the slice. /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1764,6 +1787,7 @@ impl [T] { /// /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut /// [`chunks_mut`]: slice::chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut #[stable(feature = "rchunks", since = "1.31.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1787,6 +1811,9 @@ impl [T] { /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the /// slice. /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1805,6 +1832,7 @@ impl [T] { /// [`chunks`]: slice::chunks /// [`rchunks`]: slice::rchunks /// [`chunks_exact`]: slice::chunks_exact + /// [`as_rchunks`]: slice::as_rchunks #[stable(feature = "rchunks", since = "1.31.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -1828,6 +1856,9 @@ impl [T] { /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning /// of the slice. /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// /// # Panics /// /// Panics if `chunk_size` is zero. @@ -1850,6 +1881,7 @@ impl [T] { /// [`chunks_mut`]: slice::chunks_mut /// [`rchunks_mut`]: slice::rchunks_mut /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut #[stable(feature = "rchunks", since = "1.31.0")] #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] #[inline] @@ -4866,7 +4898,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 +4952,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 +5190,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 +5199,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/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 25b9c6e0e0e94..b57234bbee9a2 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -82,7 +82,7 @@ unsafe fn skip_search( let needle = needle as u32; let last_idx = - match short_offset_runs.binary_search_by_key(&(needle << 11), |header| (header.0 << 11)) { + match short_offset_runs.binary_search_by_key(&(needle << 11), |header| header.0 << 11) { Ok(idx) => idx + 1, Err(idx) => idx, }; diff --git a/library/coretests/tests/any.rs b/library/coretests/tests/any.rs index 117ef0042380d..25002617d0bbd 100644 --- a/library/coretests/tests/any.rs +++ b/library/coretests/tests/any.rs @@ -118,14 +118,6 @@ fn any_unsized() { is_any::<[i32]>(); } -#[cfg(feature = "debug_typeid")] -#[test] -fn debug_typeid_includes_name() { - let type_id = TypeId::of::<[usize; 2]>(); - let debug_str = format!("{type_id:?}"); - assert!(debug_str.ends_with("= [usize; 2])"), "{debug_str:?} did not match"); -} - #[test] fn distinct_type_names() { // https://github.com/rust-lang/rust/issues/84666 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/floats/f128.rs b/library/coretests/tests/floats/f128.rs index cf78e8796a030..38df09a91c103 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -55,20 +55,6 @@ fn test_num_f128() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_nan() { - let nan: f128 = f128::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert!(!nan.is_normal()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f128::MANTISSA_DIGITS - 2)) != 0); -} - #[test] fn test_infinity() { let inf: f128 = f128::INFINITY; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 9e91b654304b6..f6749d796cca9 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -51,20 +51,6 @@ fn test_num_f16() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_nan() { - let nan: f16 = f16::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert!(!nan.is_normal()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f16::MANTISSA_DIGITS - 2)) != 0); -} - #[test] fn test_infinity() { let inf: f16 = f16::INFINITY; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index d2724d12e3927..f5d5723fea455 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -35,20 +35,6 @@ fn test_num_f32() { super::test_num(10f32, 2f32); } -#[test] -fn test_nan() { - let nan: f32 = f32::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f32::MANTISSA_DIGITS - 2)) != 0); -} - #[test] fn test_infinity() { let inf: f32 = f32::INFINITY; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index b2b2393a5279c..34af87c241e91 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -30,20 +30,6 @@ fn test_num_f64() { super::test_num(10f64, 2f64); } -#[test] -fn test_nan() { - let nan: f64 = f64::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f64::MANTISSA_DIGITS - 2)) != 0); -} - #[test] fn test_infinity() { let inf: f64 = f64::INFINITY; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 6b4f586fa9b6b..36743a7d6df9e 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; /// Set the default tolerance for float comparison based on the type. @@ -187,6 +188,8 @@ macro_rules! float_test { mod const_ { #[allow(unused)] use super::Approx; + #[allow(unused)] + use std::num::FpCategory as Fp; // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] use $crate::floats::{ @@ -250,6 +253,26 @@ mod f16; mod f32; mod f64; +float_test! { + name: nan, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert!(matches!(nan.classify(), Fp::Nan)); + // Ensure the quiet bit is set. + assert!(nan.to_bits() & (1 << (Float::MANTISSA_DIGITS - 2)) != 0); + } +} + float_test! { name: min, attrs: { 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/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 003ac4f0cd37f..668e988abff39 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -61,6 +61,7 @@ struct Exception { // and its destructor is executed by the C++ runtime. When we take the Box // out of the exception, we need to leave the exception in a valid state // for its destructor to run without double-dropping the Box. + // We also construct this as None for copies of the exception. data: Option>, } @@ -264,7 +265,11 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { // runtime under a try/catch block and the panic that we generate here will be // used as the result of the exception copy. This is used by the C++ runtime to // support capturing exceptions with std::exception_ptr, which we can't support -// because Box isn't clonable. +// because Box isn't clonable. Thus we throw an exception without data, +// which the C++ runtime will attempt to copy, which will once again fail, and +// a std::bad_exception instance ends up in the std::exception_ptr instance. +// The lack of data doesn't matter because the exception will never be rethrown +// - it is purely used to signal to the C++ runtime that copying failed. macro_rules! define_cleanup { ($abi:tt $abi2:tt) => { unsafe extern $abi fn exception_cleanup(e: *mut Exception) { @@ -278,7 +283,9 @@ macro_rules! define_cleanup { unsafe extern $abi2 fn exception_copy( _dest: *mut Exception, _src: *mut Exception ) -> *mut Exception { - panic!("Rust panics cannot be copied"); + unsafe { + throw_exception(None); + } } } } @@ -291,6 +298,10 @@ cfg_if::cfg_if! { } pub(crate) unsafe fn panic(data: Box) -> u32 { + unsafe { throw_exception(Some(data)) } +} + +unsafe fn throw_exception(data: Option>) -> ! { use core::intrinsics::{AtomicOrdering, atomic_store}; // _CxxThrowException executes entirely on this stack frame, so there's no @@ -300,8 +311,7 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { // The ManuallyDrop is needed here since we don't want Exception to be // dropped when unwinding. Instead it will be dropped by exception_cleanup // which is invoked by the C++ runtime. - let mut exception = - ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data: Some(data) }); + let mut exception = ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data }); let throw_ptr = (&raw mut exception) as *mut _; // This... may seems surprising, and justifiably so. On 32-bit MSVC the 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/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index 6a1cecd69fb5f..57ca7db9fcdd7 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -33,7 +33,7 @@ impl Symbol { /// Validates and normalizes before converting it to a symbol. pub(crate) fn new_ident(string: &str, is_raw: bool) -> Self { // Fast-path: check if this is a valid ASCII identifier - if Self::is_valid_ascii_ident(string.as_bytes()) { + if Self::is_valid_ascii_ident(string.as_bytes()) || string == "$crate" { if is_raw && !Self::can_be_raw(string) { panic!("`{}` cannot be a raw identifier", string); } @@ -79,7 +79,7 @@ impl Symbol { // Mimics the behavior of `Symbol::can_be_raw` from `rustc_span` fn can_be_raw(string: &str) -> bool { match string { - "_" | "super" | "self" | "Self" | "crate" => false, + "_" | "super" | "self" | "Self" | "crate" | "$crate" => false, _ => true, } } 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..7a20d8bc919e7 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -114,8 +114,6 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] # Make `RefCell` store additional debugging information, which is printed out when # a borrow error occurs debug_refcell = ["core/debug_refcell"] -# Make `TypeId` store a reference to the name of the type, so that it can print that name. -debug_typeid = ["core/debug_typeid"] # Enable std_detect default features for stdarch/crates/std_detect: @@ -158,8 +156,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/fs/unix.rs b/library/std/src/sys/fs/unix.rs index dc278274f00f4..b310db2dac485 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1491,7 +1491,6 @@ impl File { target_os = "redox", target_os = "espidf", target_os = "horizon", - target_os = "vxworks", target_os = "nuttx", )))] let to_timespec = |time: Option| match time { 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..e4f5520d8a33e 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", @@ -222,7 +222,7 @@ impl Thread { #[cfg(target_os = "vxworks")] pub fn set_name(name: &CStr) { - let mut name = truncate_cstr::<{ libc::VX_TASK_RENAME_LENGTH - 1 }>(name); + let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name); let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) }; debug_assert_eq!(res, libc::OK); } @@ -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/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 3adc022497167..290c2eeed44c6 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -5,6 +5,10 @@ name = "sysroot" version = "0.0.0" edition = "2024" +[lib] +# make sure this crate isn't included in public standard library docs +doc = false + # this is a dummy crate to ensure that all required crates appear in the sysroot [dependencies] proc_macro = { path = "../proc_macro", public = true } @@ -22,7 +26,6 @@ compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] compiler-builtins-no-f16-f128 = ["std/compiler-builtins-no-f16-f128"] compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] debug_refcell = ["std/debug_refcell"] -debug_typeid = ["std/debug_typeid"] llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 71b1830dd394b..fed6a6a6c8410 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-14" 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..1bb147295b98a 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 = "d49a9ff8f7df7aa347c7fd570971097cf89f69e2" 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, {