From 30e3308711559f11e6f75502f25cc90bc4947123 Mon Sep 17 00:00:00 2001 From: "Crom (Thibaut CHARLES)" Date: Sun, 24 Nov 2024 14:36:55 +0100 Subject: [PATCH 001/481] Added a doc test for std::path::strip_prefix --- std/src/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/path.rs b/std/src/path.rs index b0291e3aa196f..7ffb11b6aedbd 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -2504,6 +2504,7 @@ impl Path { /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// /// assert!(path.strip_prefix("test").is_err()); + /// assert!(path.strip_prefix("/te").is_err()); /// assert!(path.strip_prefix("/haha").is_err()); /// /// let prefix = PathBuf::from("/test/"); From 1329581f0f3481fc23ff9f88ff31a07ec17acbe5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2024 18:29:36 +0100 Subject: [PATCH 002/481] std::thread: avoid leading whitespace in some panic messages --- std/src/thread/current.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/src/thread/current.rs b/std/src/thread/current.rs index b9b959f98946b..1048ef973560e 100644 --- a/std/src/thread/current.rs +++ b/std/src/thread/current.rs @@ -243,17 +243,17 @@ fn init_current(current: *mut ()) -> Thread { // a particular API should be entirely allocation-free, feel free to open // an issue on the Rust repository, we'll see what we can do. rtabort!( - "\n - Attempted to access thread-local data while allocating said data.\n - Do not access functions that allocate in the global allocator!\n - This is a bug in the global allocator.\n - " + "\n\ + Attempted to access thread-local data while allocating said data.\n\ + Do not access functions that allocate in the global allocator!\n\ + This is a bug in the global allocator.\n\ + " ) } else { debug_assert_eq!(current, DESTROYED); panic!( - "use of std::thread::current() is not possible after the thread's - local data has been destroyed" + "use of std::thread::current() is not possible after the thread's \ + local data has been destroyed" ) } } From 66770149e8a4024965551aed0eb808d660bffd6e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 14 Nov 2024 09:15:49 -0800 Subject: [PATCH 003/481] btree: add `{Entry,VacantEntry}::insert_entry` This matches the recently-stabilized methods on `HashMap` entries. I've reused tracking issue #65225 for now, but we may want to split it. --- alloc/src/collections/btree/map/entry.rs | 105 ++++++++++++++++------- alloc/src/collections/btree/node.rs | 2 +- 2 files changed, 76 insertions(+), 31 deletions(-) diff --git a/alloc/src/collections/btree/map/entry.rs b/alloc/src/collections/btree/map/entry.rs index 75bb86916a887..0da6af54bc22b 100644 --- a/alloc/src/collections/btree/map/entry.rs +++ b/alloc/src/collections/btree/map/entry.rs @@ -269,6 +269,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { Vacant(entry) => Vacant(entry), } } + + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_entry_insert)] + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let entry = map.entry("poneyland").insert_entry("hoho".to_string()); + /// + /// assert_eq!(entry.key(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "btree_entry_insert", issue = "65225")] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { + match self { + Occupied(mut entry) => { + entry.insert(value); + entry + } + Vacant(entry) => entry.insert_entry(value), + } + } } impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> { @@ -348,41 +373,61 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push", "put")] - pub fn insert(mut self, value: V) -> &'a mut V { - let out_ptr = match self.handle { + pub fn insert(self, value: V) -> &'a mut V { + self.insert_entry(value).into_mut() + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_entry_insert)] + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// let entry = o.insert_entry(37); + /// assert_eq!(entry.get(), &37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[unstable(feature = "btree_entry_insert", issue = "65225")] + pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> { + let handle = match self.handle { None => { // SAFETY: There is no tree yet so no reference to it exists. - let map = unsafe { self.dormant_map.awaken() }; - let mut root = NodeRef::new_leaf(self.alloc.clone()); - let val_ptr = root.borrow_mut().push(self.key, value); - map.root = Some(root.forget_type()); - map.length = 1; - val_ptr - } - Some(handle) => { - let new_handle = - handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| { - drop(ins.left); - // SAFETY: Pushing a new root node doesn't invalidate - // handles to existing nodes. - let map = unsafe { self.dormant_map.reborrow() }; - let root = map.root.as_mut().unwrap(); // same as ins.left - root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right) - }); - - // Get the pointer to the value - let val_ptr = new_handle.into_val_mut(); - - // SAFETY: We have consumed self.handle. - let map = unsafe { self.dormant_map.awaken() }; - map.length += 1; - val_ptr + let map = unsafe { self.dormant_map.reborrow() }; + let root = map.root.insert(NodeRef::new_leaf(self.alloc.clone()).forget_type()); + // SAFETY: We *just* created the root as a leaf, and we're + // stacking the new handle on the original borrow lifetime. + unsafe { + let mut leaf = root.borrow_mut().cast_to_leaf_unchecked(); + leaf.push_with_handle(self.key, value) + } } + Some(handle) => handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| { + drop(ins.left); + // SAFETY: Pushing a new root node doesn't invalidate + // handles to existing nodes. + let map = unsafe { self.dormant_map.reborrow() }; + let root = map.root.as_mut().unwrap(); // same as ins.left + root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) + }), }; - // Now that we have finished growing the tree using borrowed references, - // dereference the pointer to a part of it, that we picked up along the way. - unsafe { &mut *out_ptr } + // SAFETY: modifying the length doesn't invalidate handles to existing nodes. + unsafe { self.dormant_map.reborrow().length += 1 }; + + OccupiedEntry { + handle: handle.forget_node_type(), + dormant_map: self.dormant_map, + alloc: self.alloc, + _marker: PhantomData, + } } } diff --git a/alloc/src/collections/btree/node.rs b/alloc/src/collections/btree/node.rs index 64a13bb6a0b3a..0c93eff0d20fa 100644 --- a/alloc/src/collections/btree/node.rs +++ b/alloc/src/collections/btree/node.rs @@ -739,7 +739,7 @@ impl NodeRef { impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. - unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { + pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { debug_assert!(self.height == 0); NodeRef { height: self.height, node: self.node, _marker: PhantomData } } From 274a1d2d20bbba5bb01277646876c466e5825304 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 17 Nov 2024 21:26:15 +0200 Subject: [PATCH 004/481] Support ranges in `<[T]>::get_many_mut()` I implemented that with a separate trait and not within `SliceIndex`, because doing that via `SliceIndex` requires adding support for range types that are (almost) always overlapping e.g. `RangeFrom`, and also adding fake support code for `impl SliceIndex`. An inconvenience that I ran into was that slice indexing takes the index by value, but I only have it by reference. I could change slice indexing to take by ref, but this is pretty much the hottest code ever so I'm afraid to touch it. Instead I added a requirement for `Clone` (which all index types implement anyway) and cloned. This is an internal requirement the user won't see and the clone should always be optimized away. I also implemented `Clone`, `PartialEq` and `Eq` for the error type, since I noticed it does not do that when writing the tests and other errors in std seem to implement them. I didn't implement `Copy` because maybe we will want to put something non-`Copy` there. --- core/src/slice/mod.rs | 198 ++++++++++++++++++++++++++++++++++++++---- core/tests/slice.rs | 70 ++++++++++++++- 2 files changed, 249 insertions(+), 19 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index c855f963771ed..b3defba5a9823 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -10,10 +10,10 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub}; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ops::{Bound, OneSidedRange, Range, RangeBounds}; +use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive}; use crate::simd::{self, Simd}; use crate::ub_checks::assert_unsafe_precondition; -use crate::{fmt, hint, ptr, slice}; +use crate::{fmt, hint, ptr, range, slice}; #[unstable( feature = "slice_internals", @@ -4469,6 +4469,12 @@ impl [T] { /// Returns mutable references to many indices at once, without doing any checks. /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// /// For a safe alternative see [`get_many_mut`]. /// /// # Safety @@ -4489,30 +4495,49 @@ impl [T] { /// *b *= 100; /// } /// assert_eq!(x, &[10, 2, 400]); + /// + /// unsafe { + /// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]); + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(x, &[8, 88, 888]); + /// + /// unsafe { + /// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]); + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(x, &[1, 11, 111]); /// ``` /// /// [`get_many_mut`]: slice::get_many_mut /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[unstable(feature = "get_many_mut", issue = "104642")] #[inline] - pub unsafe fn get_many_unchecked_mut( + pub unsafe fn get_many_unchecked_mut( &mut self, - indices: [usize; N], - ) -> [&mut T; N] { + indices: [I; N], + ) -> [&mut I::Output; N] + where + I: GetManyMutIndex + SliceIndex, + { // NB: This implementation is written as it is because any variation of // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, // or generate worse code otherwise. This is also why we need to go // through a raw pointer here. let slice: *mut [T] = self; - let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit(); + let mut arr: mem::MaybeUninit<[&mut I::Output; N]> = mem::MaybeUninit::uninit(); let arr_ptr = arr.as_mut_ptr(); // SAFETY: We expect `indices` to contain disjunct values that are // in bounds of `self`. unsafe { for i in 0..N { - let idx = *indices.get_unchecked(i); - *(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx); + let idx = indices.get_unchecked(i).clone(); + arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx)); } arr.assume_init() } @@ -4520,8 +4545,18 @@ impl [T] { /// Returns mutable references to many indices at once. /// - /// Returns an error if any index is out-of-bounds, or if the same index was - /// passed more than once. + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// Returns an error if any index is out-of-bounds, or if there are overlapping indices. + /// An empty range is not considered to overlap if it is located at the beginning or at + /// the end of another range, but is considered to overlap if it is located in the middle. + /// + /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful + /// when passing many indices. /// /// # Examples /// @@ -4534,13 +4569,30 @@ impl [T] { /// *b = 612; /// } /// assert_eq!(v, &[413, 2, 612]); + /// + /// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) { + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(v, &[8, 88, 888]); + /// + /// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) { + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(v, &[1, 11, 111]); /// ``` #[unstable(feature = "get_many_mut", issue = "104642")] #[inline] - pub fn get_many_mut( + pub fn get_many_mut( &mut self, - indices: [usize; N], - ) -> Result<[&mut T; N], GetManyMutError> { + indices: [I; N], + ) -> Result<[&mut I::Output; N], GetManyMutError> + where + I: GetManyMutIndex + SliceIndex, + { if !get_many_check_valid(&indices, self.len()) { return Err(GetManyMutError { _private: () }); } @@ -4885,14 +4937,15 @@ impl SlicePattern for [T; N] { /// /// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` /// comparison operations. -fn get_many_check_valid(indices: &[usize; N], len: usize) -> bool { +#[inline] +fn get_many_check_valid(indices: &[I; N], len: usize) -> bool { // NB: The optimizer should inline the loops into a sequence // of instructions without additional branching. let mut valid = true; - for (i, &idx) in indices.iter().enumerate() { - valid &= idx < len; - for &idx2 in &indices[..i] { - valid &= idx != idx2; + for (i, idx) in indices.iter().enumerate() { + valid &= idx.is_in_bounds(len); + for idx2 in &indices[..i] { + valid &= !idx.is_overlapping(idx2); } } valid @@ -4916,6 +4969,7 @@ fn get_many_check_valid(indices: &[usize; N], len: usize) -> boo #[unstable(feature = "get_many_mut", issue = "104642")] // NB: The N here is there to be forward-compatible with adding more details // to the error type at a later point +#[derive(Clone, PartialEq, Eq)] pub struct GetManyMutError { _private: (), } @@ -4933,3 +4987,111 @@ impl fmt::Display for GetManyMutError { fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f) } } + +mod private_get_many_mut_index { + use super::{Range, RangeInclusive, range}; + + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + pub trait Sealed {} + + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + impl Sealed for usize {} + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + impl Sealed for Range {} + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + impl Sealed for RangeInclusive {} + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + impl Sealed for range::Range {} + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + impl Sealed for range::RangeInclusive {} +} + +/// A helper trait for `<[T]>::get_many_mut()`. +/// +/// # Safety +/// +/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`, +/// it must be safe to index the slice with the indices. +#[unstable(feature = "get_many_mut_helpers", issue = "none")] +pub unsafe trait GetManyMutIndex: Clone + private_get_many_mut_index::Sealed { + /// Returns `true` if `self` is in bounds for `len` slice elements. + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + fn is_in_bounds(&self, len: usize) -> bool; + + /// Returns `true` if `self` overlaps with `other`. + /// + /// Note that we don't consider zero-length ranges to overlap at the beginning or the end, + /// but do consider them to overlap in the middle. + #[unstable(feature = "get_many_mut_helpers", issue = "none")] + fn is_overlapping(&self, other: &Self) -> bool; +} + +#[unstable(feature = "get_many_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetManyMutIndex for usize { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + *self < len + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + *self == *other + } +} + +#[unstable(feature = "get_many_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetManyMutIndex for Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end <= len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start < other.end) & (other.start < self.end) + } +} + +#[unstable(feature = "get_many_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetManyMutIndex for RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end < len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start <= other.end) & (other.start <= self.end) + } +} + +#[unstable(feature = "get_many_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetManyMutIndex for range::Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + Range::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + Range::from(*self).is_overlapping(&Range::from(*other)) + } +} + +#[unstable(feature = "get_many_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetManyMutIndex for range::RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + RangeInclusive::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other)) + } +} diff --git a/core/tests/slice.rs b/core/tests/slice.rs index 9ae2bcc852649..510dd4967c961 100644 --- a/core/tests/slice.rs +++ b/core/tests/slice.rs @@ -2,6 +2,7 @@ use core::cell::Cell; use core::cmp::Ordering; use core::mem::MaybeUninit; use core::num::NonZero; +use core::ops::{Range, RangeInclusive}; use core::slice; #[test] @@ -2553,6 +2554,14 @@ fn test_get_many_mut_normal_2() { *a += 10; *b += 100; assert_eq!(v, vec![101, 2, 3, 14, 5]); + + let [a, b] = v.get_many_mut([0..=1, 2..=2]).unwrap(); + assert_eq!(a, &mut [101, 2][..]); + assert_eq!(b, &mut [3][..]); + a[0] += 10; + a[1] += 20; + b[0] += 100; + assert_eq!(v, vec![111, 22, 103, 14, 5]); } #[test] @@ -2563,12 +2572,23 @@ fn test_get_many_mut_normal_3() { *b += 100; *c += 1000; assert_eq!(v, vec![11, 2, 1003, 4, 105]); + + let [a, b, c] = v.get_many_mut([0..1, 4..5, 1..4]).unwrap(); + assert_eq!(a, &mut [11][..]); + assert_eq!(b, &mut [105][..]); + assert_eq!(c, &mut [2, 1003, 4][..]); + a[0] += 10; + b[0] += 100; + c[0] += 1000; + assert_eq!(v, vec![21, 1002, 1003, 4, 205]); } #[test] fn test_get_many_mut_empty() { let mut v = vec![1, 2, 3, 4, 5]; - let [] = v.get_many_mut([]).unwrap(); + let [] = v.get_many_mut::([]).unwrap(); + let [] = v.get_many_mut::, 0>([]).unwrap(); + let [] = v.get_many_mut::, 0>([]).unwrap(); assert_eq!(v, vec![1, 2, 3, 4, 5]); } @@ -2606,6 +2626,54 @@ fn test_get_many_mut_duplicate() { assert!(v.get_many_mut([1, 3, 3, 4]).is_err()); } +#[test] +fn test_get_many_mut_range_oob() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([0..6]).is_err()); + assert!(v.get_many_mut([5..6]).is_err()); + assert!(v.get_many_mut([6..6]).is_err()); + assert!(v.get_many_mut([0..=5]).is_err()); + assert!(v.get_many_mut([0..=6]).is_err()); + assert!(v.get_many_mut([5..=5]).is_err()); +} + +#[test] +fn test_get_many_mut_range_overlapping() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([0..1, 0..2]).is_err()); + assert!(v.get_many_mut([0..1, 1..2, 0..1]).is_err()); + assert!(v.get_many_mut([0..3, 1..1]).is_err()); + assert!(v.get_many_mut([0..3, 1..2]).is_err()); + assert!(v.get_many_mut([0..=0, 2..=2, 0..=1]).is_err()); + assert!(v.get_many_mut([0..=4, 0..=0]).is_err()); + assert!(v.get_many_mut([4..=4, 0..=0, 3..=4]).is_err()); +} + +#[test] +fn test_get_many_mut_range_empty_at_edge() { + let mut v = vec![1, 2, 3, 4, 5]; + assert_eq!( + v.get_many_mut([0..0, 0..5, 5..5]), + Ok([&mut [][..], &mut [1, 2, 3, 4, 5], &mut []]), + ); + assert_eq!( + v.get_many_mut([0..0, 0..1, 1..1, 1..2, 2..2, 2..3, 3..3, 3..4, 4..4, 4..5, 5..5]), + Ok([ + &mut [][..], + &mut [1], + &mut [], + &mut [2], + &mut [], + &mut [3], + &mut [], + &mut [4], + &mut [], + &mut [5], + &mut [], + ]), + ); +} + #[test] fn test_slice_from_raw_parts_in_const() { static FANCY: i32 = 4; From 148053a37ce32b7c5daa4b192cc441376e3c1d83 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 21 Nov 2024 03:46:59 -0500 Subject: [PATCH 005/481] Shorten the `MaybeUninit` `Debug` implementation Currently the `Debug` implementation for `MaybeUninit` winds up being pretty verbose. This struct: #[derive(Debug)] pub struct Foo { pub a: u32, pub b: &'static str, pub c: MaybeUninit, pub d: MaybeUninit, } Prints as: Foo { a: 0, b: "hello", c: core::mem::maybe_uninit::MaybeUninit, d: core::mem::maybe_uninit::MaybeUninit, } The goal is just to be a standin for content so the path prefix doesn't add any useful information. Change the implementation to trim `MaybeUninit`'s leading path, meaning the new result is now: Foo { a: 0, b: "hello", c: MaybeUninit, d: MaybeUninit, } --- core/src/mem/maybe_uninit.rs | 6 +++++- core/tests/fmt/mod.rs | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 58315cb74f0a1..27273e4eedf3a 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -255,7 +255,11 @@ impl Clone for MaybeUninit { #[stable(feature = "maybe_uninit_debug", since = "1.41.0")] impl fmt::Debug for MaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad(type_name::()) + // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>"). + // This needs to be adjusted if `MaybeUninit` moves modules. + let full_name = type_name::(); + let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1; + f.pad(short_name) } } diff --git a/core/tests/fmt/mod.rs b/core/tests/fmt/mod.rs index 704d246139947..f7512abae3820 100644 --- a/core/tests/fmt/mod.rs +++ b/core/tests/fmt/mod.rs @@ -43,3 +43,10 @@ fn pad_integral_resets() { assert_eq!(format!("{Bar:<03}"), "1 0051 "); } + +#[test] +fn test_maybe_uninit_short() { + // Ensure that the trimmed `MaybeUninit` Debug implementation doesn't break + let x = core::mem::MaybeUninit::new(0u32); + assert_eq!(format!("{x:?}"), "MaybeUninit"); +} From d3aa5563bc1fd112172ddf3e39599616178a0d2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2024 08:00:22 +0100 Subject: [PATCH 006/481] miri: disable test_downgrade_observe test on macOS --- std/src/sync/rwlock/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/std/src/sync/rwlock/tests.rs b/std/src/sync/rwlock/tests.rs index 29cad4400f189..48d442921f7fc 100644 --- a/std/src/sync/rwlock/tests.rs +++ b/std/src/sync/rwlock/tests.rs @@ -511,12 +511,15 @@ fn test_downgrade_basic() { } #[test] +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] fn test_downgrade_observe() { // Taken from the test `test_rwlock_downgrade` from: // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs const W: usize = 20; - const N: usize = 100; + const N: usize = if cfg!(miri) { 40 } else { 100 }; // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring // that the value they wrote has not changed after downgrading. From 063543fd114264174b2ec5b350b8677248f43e05 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 24 Nov 2024 00:30:16 +0000 Subject: [PATCH 007/481] Constify Drop and Destruct --- core/src/marker.rs | 1 + core/src/ops/drop.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index acbad07746bb9..1620b949590d0 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -957,6 +957,7 @@ marker_impls! { #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(not(bootstrap), const_trait)] pub trait Destruct {} /// A marker for tuple types. diff --git a/core/src/ops/drop.rs b/core/src/ops/drop.rs index a6f63ad68d695..f3314364e5428 100644 --- a/core/src/ops/drop.rs +++ b/core/src/ops/drop.rs @@ -203,7 +203,7 @@ /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME(const_trait_impl) #[const_trait] +#[cfg_attr(not(bootstrap), const_trait)] pub trait Drop { /// Executes the destructor for this type. /// From 4002ac0a3efe60f5b925c76e89a61457ff6b90ef Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 25 Nov 2024 13:41:30 +0100 Subject: [PATCH 008/481] std: expose `const_io_error!` as `const_error!` ACP: rust-lang/libs-team#205 Tracking issue: #133448 --- std/src/io/error.rs | 49 ++++++++++++++++++++++++++++----------------- std/src/io/mod.rs | 7 +++++-- std/src/lib.rs | 1 + 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/std/src/io/error.rs b/std/src/io/error.rs index 5d7adcace5247..d98ab35a8809e 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -151,27 +151,38 @@ pub type RawOsError = sys::RawOsError; // (For the sake of being explicit: the alignment requirement here only matters // if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't // matter at all) +#[doc(hidden)] +#[unstable(feature = "io_const_error_internals", issue = "none")] #[repr(align(4))] #[derive(Debug)] -pub(crate) struct SimpleMessage { - kind: ErrorKind, - message: &'static str, -} - -impl SimpleMessage { - pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self { - Self { kind, message } - } +pub struct SimpleMessage { + pub kind: ErrorKind, + pub message: &'static str, } -/// Creates and returns an `io::Error` for a given `ErrorKind` and constant -/// message. This doesn't allocate. -pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) { - $crate::io::error::Error::from_static_message({ - const MESSAGE_DATA: $crate::io::error::SimpleMessage = - $crate::io::error::SimpleMessage::new($kind, $message); - &MESSAGE_DATA - }) +/// Creates a new I/O error from a known kind of error and a string literal. +/// +/// Contrary to [`Error::new`], this macro does not allocate and can be used in +/// `const` contexts. +/// +/// # Example +/// ``` +/// #![feature(io_const_error)] +/// use std::io::{const_error, Error, ErrorKind}; +/// +/// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works"); +/// +/// fn not_here() -> Result<(), Error> { +/// Err(FAIL) +/// } +/// ``` +#[rustc_macro_transparency = "semitransparent"] +#[unstable(feature = "io_const_error", issue = "133448")] +#[allow_internal_unstable(hint_must_use, io_const_error_internals)] +pub macro const_error($kind:expr, $message:expr $(,)?) { + $crate::hint::must_use($crate::io::Error::from_static_message( + const { &$crate::io::SimpleMessage { kind: $kind, message: $message } }, + )) } // As with `SimpleMessage`: `#[repr(align(4))]` here is just because @@ -598,7 +609,9 @@ impl Error { /// This function should maybe change to `from_static_message(kind: ErrorKind)` in the future, when const generics allow that. #[inline] - pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error { + #[doc(hidden)] + #[unstable(feature = "io_const_error_internals", issue = "none")] + pub const fn from_static_message(msg: &'static SimpleMessage) -> Error { Self { repr: Repr::new_simple_message(msg) } } diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 21e7077495450..4ffb04630061f 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -301,12 +301,15 @@ mod tests; pub use core::io::{BorrowedBuf, BorrowedCursor}; use core::slice::memchr; -pub(crate) use error::const_io_error; - #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use self::buffered::WriterPanicked; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use self::error::RawOsError; +#[doc(hidden)] +#[unstable(feature = "io_const_error_internals", issue = "none")] +pub use self::error::SimpleMessage; +#[unstable(feature = "io_const_error", issue = "133448")] +pub use self::error::const_error; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; pub(crate) use self::stdio::attempt_print_to_stderr; diff --git a/std/src/lib.rs b/std/src/lib.rs index ee6fceb024fd7..f1eeac3354009 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -340,6 +340,7 @@ #![feature(fmt_internals)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] +#![feature(hint_must_use)] #![feature(ip)] #![feature(lazy_get)] #![feature(maybe_uninit_slice)] From 114bab9501b02ab52c17a7c0d137e7a566ad341c Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 25 Nov 2024 13:49:25 +0100 Subject: [PATCH 009/481] std: update internal uses of `io::const_error!` --- std/src/fs.rs | 2 +- std/src/io/buffered/bufreader/buffer.rs | 2 +- std/src/io/buffered/bufwriter.rs | 4 +- std/src/io/cursor.rs | 4 +- std/src/io/error.rs | 18 +++---- std/src/io/error/tests.rs | 10 ++-- std/src/io/tests.rs | 4 +- std/src/lib.rs | 1 + std/src/net/mod.rs | 2 +- std/src/net/udp.rs | 4 +- std/src/os/unix/net/addr.rs | 8 +-- std/src/os/wasi/fs.rs | 5 +- std/src/os/windows/io/socket.rs | 2 +- std/src/path.rs | 2 +- std/src/sys/pal/common/small_c_string.rs | 2 +- std/src/sys/pal/hermit/fs.rs | 16 +++--- std/src/sys/pal/hermit/mod.rs | 2 +- std/src/sys/pal/hermit/net.rs | 4 +- std/src/sys/pal/hermit/thread.rs | 2 +- std/src/sys/pal/sgx/mod.rs | 4 +- std/src/sys/pal/solid/fs.rs | 13 ++--- std/src/sys/pal/solid/net.rs | 2 +- std/src/sys/pal/solid/os.rs | 2 +- std/src/sys/pal/uefi/helpers.rs | 30 ++++++----- std/src/sys/pal/uefi/mod.rs | 2 +- std/src/sys/pal/uefi/os.rs | 12 ++--- std/src/sys/pal/uefi/process.rs | 8 +-- std/src/sys/pal/unix/fs.rs | 26 +++++----- std/src/sys/pal/unix/l4re.rs | 2 +- std/src/sys/pal/unix/net.rs | 4 +- std/src/sys/pal/unix/os.rs | 23 ++++----- .../sys/pal/unix/process/process_fuchsia.rs | 8 +-- std/src/sys/pal/unix/process/process_unix.rs | 10 ++-- .../sys/pal/unix/process/process_vxworks.rs | 2 +- std/src/sys/pal/unix/thread.rs | 4 +- std/src/sys/pal/unix/time.rs | 2 +- std/src/sys/pal/unsupported/os.rs | 4 +- std/src/sys/pal/wasi/fs.rs | 7 ++- std/src/sys/pal/wasip2/net.rs | 2 +- std/src/sys/pal/windows/args.rs | 4 +- std/src/sys/pal/windows/fs.rs | 20 +++----- std/src/sys/pal/windows/mod.rs | 2 +- std/src/sys/pal/windows/net.rs | 2 +- std/src/sys/pal/windows/process.rs | 13 +++-- std/src/sys/pal/windows/stdio.rs | 8 +-- std/src/sys/pal/xous/net/dns.rs | 5 +- std/src/sys/pal/xous/net/tcplistener.rs | 36 ++++++------- std/src/sys/pal/xous/net/tcpstream.rs | 46 ++++++++--------- std/src/sys/pal/xous/net/udp.rs | 50 ++++++++----------- std/src/sys/pal/zkvm/os.rs | 4 +- std/src/sys/path/windows.rs | 2 +- std/src/sys_common/fs.rs | 2 +- std/src/sys_common/net.rs | 4 +- 53 files changed, 213 insertions(+), 246 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index d846a4e5f0916..2d5d869630e0e 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -3020,7 +3020,7 @@ impl DirBuilder { match path.parent() { Some(p) => self.create_dir_all(p)?, None => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Uncategorized, "failed to create whole tree", )); diff --git a/std/src/io/buffered/bufreader/buffer.rs b/std/src/io/buffered/bufreader/buffer.rs index 52fe49985c65a..17721090db5de 100644 --- a/std/src/io/buffered/bufreader/buffer.rs +++ b/std/src/io/buffered/bufreader/buffer.rs @@ -41,7 +41,7 @@ impl Buffer { match Box::try_new_uninit_slice(capacity) { Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), Err(_) => { - Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) + Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) } } } diff --git a/std/src/io/buffered/bufwriter.rs b/std/src/io/buffered/bufwriter.rs index c41bae2aa4e81..574eb83dc5649 100644 --- a/std/src/io/buffered/bufwriter.rs +++ b/std/src/io/buffered/bufwriter.rs @@ -96,7 +96,7 @@ impl BufWriter { pub(crate) fn try_new_buffer() -> io::Result> { Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { - io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") + io::const_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") }) } @@ -238,7 +238,7 @@ impl BufWriter { match r { Ok(0) => { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::WriteZero, "failed to write the buffered data", )); diff --git a/std/src/io/cursor.rs b/std/src/io/cursor.rs index fbfdb4fa02323..b2ffeb0f95d0d 100644 --- a/std/src/io/cursor.rs +++ b/std/src/io/cursor.rs @@ -304,7 +304,7 @@ where self.pos = n; Ok(self.pos) } - None => Err(io::const_io_error!( + None => Err(io::const_error!( ErrorKind::InvalidInput, "invalid seek to a negative or overflowing position", )), @@ -446,7 +446,7 @@ fn reserve_and_pad( buf_len: usize, ) -> io::Result { let pos: usize = (*pos_mut).try_into().map_err(|_| { - io::const_io_error!( + io::const_error!( ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length", ) diff --git a/std/src/io/error.rs b/std/src/io/error.rs index d98ab35a8809e..03f38e220a581 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -76,31 +76,31 @@ impl fmt::Debug for Error { #[allow(dead_code)] impl Error { pub(crate) const INVALID_UTF8: Self = - const_io_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); + const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); pub(crate) const READ_EXACT_EOF: Self = - const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); + const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); - pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_io_error!( + pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!( ErrorKind::NotFound, "The number of hardware threads is not known for the target platform" ); pub(crate) const UNSUPPORTED_PLATFORM: Self = - const_io_error!(ErrorKind::Unsupported, "operation not supported on this platform"); + const_error!(ErrorKind::Unsupported, "operation not supported on this platform"); pub(crate) const WRITE_ALL_EOF: Self = - const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"); + const_error!(ErrorKind::WriteZero, "failed to write whole buffer"); pub(crate) const ZERO_TIMEOUT: Self = - const_io_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); + const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); } #[stable(feature = "rust1", since = "1.0.0")] impl From for Error { /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. fn from(_: alloc::ffi::NulError) -> Error { - const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") + const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") } } @@ -603,8 +603,8 @@ impl Error { /// /// This function does not allocate. /// - /// You should not use this directly, and instead use the `const_io_error!` - /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`. + /// You should not use this directly, and instead use the `const_error!` + /// macro: `io::const_error!(ErrorKind::Something, "some_message")`. /// /// This function should maybe change to `from_static_message(kind: ErrorKind)` in the future, when const generics allow that. diff --git a/std/src/io/error/tests.rs b/std/src/io/error/tests.rs index 00d04984a3854..edac6563478cd 100644 --- a/std/src/io/error/tests.rs +++ b/std/src/io/error/tests.rs @@ -1,4 +1,4 @@ -use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_io_error}; +use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error}; use crate::assert_matches::assert_matches; use crate::mem::size_of; use crate::sys::decode_error_kind; @@ -60,7 +60,7 @@ fn test_downcasting() { #[test] fn test_const() { - const E: Error = const_io_error!(ErrorKind::NotFound, "hello"); + const E: Error = const_error!(ErrorKind::NotFound, "hello"); assert_eq!(E.kind(), ErrorKind::NotFound); assert_eq!(E.to_string(), "hello"); @@ -110,13 +110,13 @@ fn test_simple_message_packing() { }}; } - let not_static = const_io_error!(Uncategorized, "not a constant!"); + let not_static = const_error!(Uncategorized, "not a constant!"); check_simple_msg!(not_static, Uncategorized, "not a constant!"); - const CONST: Error = const_io_error!(NotFound, "definitely a constant!"); + const CONST: Error = const_error!(NotFound, "definitely a constant!"); check_simple_msg!(CONST, NotFound, "definitely a constant!"); - static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!"); + static STATIC: Error = const_error!(BrokenPipe, "a constant, sort of!"); check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!"); } diff --git a/std/src/io/tests.rs b/std/src/io/tests.rs index 89e806c08911c..47cbb9614afdd 100644 --- a/std/src/io/tests.rs +++ b/std/src/io/tests.rs @@ -225,12 +225,12 @@ fn take_eof() { impl Read for R { fn read(&mut self, _: &mut [u8]) -> io::Result { - Err(io::const_io_error!(io::ErrorKind::Other, "")) + Err(io::const_error!(io::ErrorKind::Other, "")) } } impl BufRead for R { fn fill_buf(&mut self) -> io::Result<&[u8]> { - Err(io::const_io_error!(io::ErrorKind::Other, "")) + Err(io::const_error!(io::ErrorKind::Other, "")) } fn consume(&mut self, _amt: usize) {} } diff --git a/std/src/lib.rs b/std/src/lib.rs index f1eeac3354009..cf99a618e5520 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -411,6 +411,7 @@ // Only for const-ness: // tidy-alphabetical-start #![feature(const_collections_with_hasher)] +#![feature(io_const_error)] #![feature(thread_local_internals)] // tidy-alphabetical-end // diff --git a/std/src/net/mod.rs b/std/src/net/mod.rs index 3b19c743b1e24..ddd3b68dd2d63 100644 --- a/std/src/net/mod.rs +++ b/std/src/net/mod.rs @@ -84,6 +84,6 @@ where } } Err(last_err.unwrap_or_else(|| { - io::const_io_error!(ErrorKind::InvalidInput, "could not resolve to any addresses") + io::const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses") })) } diff --git a/std/src/net/udp.rs b/std/src/net/udp.rs index 6df47d7b0e0cd..674c5fb7d6ea3 100644 --- a/std/src/net/udp.rs +++ b/std/src/net/udp.rs @@ -203,9 +203,7 @@ impl UdpSocket { pub fn send_to(&self, buf: &[u8], addr: A) -> io::Result { match addr.to_socket_addrs()?.next() { Some(addr) => self.0.send_to(buf, &addr), - None => { - Err(io::const_io_error!(ErrorKind::InvalidInput, "no addresses to send data to")) - } + None => Err(io::const_error!(ErrorKind::InvalidInput, "no addresses to send data to")), } } diff --git a/std/src/os/unix/net/addr.rs b/std/src/os/unix/net/addr.rs index 253e1503cf7af..56789f235fdab 100644 --- a/std/src/os/unix/net/addr.rs +++ b/std/src/os/unix/net/addr.rs @@ -30,14 +30,14 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s let bytes = path.as_os_str().as_bytes(); if bytes.contains(&0) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "paths must not contain interior null bytes", )); } if bytes.len() >= addr.sun_path.len() { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "path must be shorter than SUN_LEN", )); @@ -119,7 +119,7 @@ impl SocketAddr { // linux returns zero bytes of address len = SUN_PATH_OFFSET as libc::socklen_t; // i.e., zero-length address } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "file descriptor did not correspond to a Unix socket", )); @@ -273,7 +273,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { addr.sun_family = libc::AF_UNIX as libc::sa_family_t; if name.len() + 1 > addr.sun_path.len() { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "abstract socket name must be shorter than SUN_LEN", )); diff --git a/std/src/os/wasi/fs.rs b/std/src/os/wasi/fs.rs index 9ec3e387e2ba9..42aada131dadc 100644 --- a/std/src/os/wasi/fs.rs +++ b/std/src/os/wasi/fs.rs @@ -261,7 +261,7 @@ impl FileExt for fs::File { a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED, a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE, _ => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "invalid parameter 'advice'", )); @@ -560,6 +560,5 @@ pub fn symlink_path, U: AsRef>(old_path: P, new_path: U) -> } fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str() - .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) + f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) } diff --git a/std/src/os/windows/io/socket.rs b/std/src/os/windows/io/socket.rs index 1fcfb6e73ad03..272641ea6c7a8 100644 --- a/std/src/os/windows/io/socket.rs +++ b/std/src/os/windows/io/socket.rs @@ -101,7 +101,7 @@ impl OwnedSocket { #[cfg(target_vendor = "uwp")] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP")) + Err(io::const_error!(io::ErrorKind::Unsupported, "Unavailable on UWP")) } } diff --git a/std/src/path.rs b/std/src/path.rs index 7ffb11b6aedbd..33a3e4332f377 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -3581,7 +3581,7 @@ impl Error for StripPrefixError { pub fn absolute>(path: P) -> io::Result { let path = path.as_ref(); if path.as_os_str().is_empty() { - Err(io::const_io_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",)) + Err(io::const_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",)) } else { sys::path::absolute(path) } diff --git a/std/src/sys/pal/common/small_c_string.rs b/std/src/sys/pal/common/small_c_string.rs index 3c96714b5c58c..f54505a856e05 100644 --- a/std/src/sys/pal/common/small_c_string.rs +++ b/std/src/sys/pal/common/small_c_string.rs @@ -11,7 +11,7 @@ const MAX_STACK_ALLOCATION: usize = 384; const MAX_STACK_ALLOCATION: usize = 32; const NUL_ERR: io::Error = - io::const_io_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte"); + io::const_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte"); #[inline] pub fn run_path_with_cstr(path: &Path, f: &dyn Fn(&CStr) -> io::Result) -> io::Result { diff --git a/std/src/sys/pal/hermit/fs.rs b/std/src/sys/pal/hermit/fs.rs index 17d15ed2e5045..11862a076082d 100644 --- a/std/src/sys/pal/hermit/fs.rs +++ b/std/src/sys/pal/hermit/fs.rs @@ -294,7 +294,7 @@ impl OpenOptions { (false, _, true) => Ok(O_WRONLY | O_APPEND), (true, _, true) => Ok(O_RDWR | O_APPEND), (false, false, false) => { - Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid access mode")) + Err(io::const_error!(ErrorKind::InvalidInput, "invalid access mode")) } } } @@ -304,18 +304,16 @@ impl OpenOptions { (true, false) => {} (false, false) => { if self.truncate || self.create || self.create_new { - return Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid creation mode", - )); + return Err( + io::const_error!(ErrorKind::InvalidInput, "invalid creation mode",), + ); } } (_, true) => { if self.truncate && !self.create_new { - return Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid creation mode", - )); + return Err( + io::const_error!(ErrorKind::InvalidInput, "invalid creation mode",), + ); } } } diff --git a/std/src/sys/pal/hermit/mod.rs b/std/src/sys/pal/hermit/mod.rs index b62afb40a615f..f03fca603441d 100644 --- a/std/src/sys/pal/hermit/mod.rs +++ b/std/src/sys/pal/hermit/mod.rs @@ -42,7 +42,7 @@ pub fn unsupported() -> crate::io::Result { } pub fn unsupported_err() -> crate::io::Error { - crate::io::const_io_error!( + crate::io::const_error!( crate::io::ErrorKind::Unsupported, "operation not supported on HermitCore yet", ) diff --git a/std/src/sys/pal/hermit/net.rs b/std/src/sys/pal/hermit/net.rs index d9baa091a2321..4e12374203e38 100644 --- a/std/src/sys/pal/hermit/net.rs +++ b/std/src/sys/pal/hermit/net.rs @@ -87,7 +87,7 @@ impl Socket { loop { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); } let timeout = timeout - elapsed; @@ -114,7 +114,7 @@ impl Socket { // for POLLHUP rather than read readiness if pollfd.revents & netc::POLLHUP != 0 { let e = self.take_error()?.unwrap_or_else(|| { - io::const_io_error!( + io::const_error!( io::ErrorKind::Uncategorized, "no error set after POLLHUP", ) diff --git a/std/src/sys/pal/hermit/thread.rs b/std/src/sys/pal/hermit/thread.rs index 41f2c3e212355..2a0b8dcb4ed60 100644 --- a/std/src/sys/pal/hermit/thread.rs +++ b/std/src/sys/pal/hermit/thread.rs @@ -41,7 +41,7 @@ impl Thread { unsafe { drop(Box::from_raw(p)); } - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Unable to create thread!")) + Err(io::const_error!(io::ErrorKind::Uncategorized, "Unable to create thread!")) } else { Ok(Thread { tid: tid }) }; diff --git a/std/src/sys/pal/sgx/mod.rs b/std/src/sys/pal/sgx/mod.rs index 586ccd18c2f57..ce8a2fed4bc6b 100644 --- a/std/src/sys/pal/sgx/mod.rs +++ b/std/src/sys/pal/sgx/mod.rs @@ -48,7 +48,7 @@ pub fn unsupported() -> crate::io::Result { } pub fn unsupported_err() -> crate::io::Error { - crate::io::const_io_error!(ErrorKind::Unsupported, "operation not supported on SGX yet") + crate::io::const_error!(ErrorKind::Unsupported, "operation not supported on SGX yet") } /// This function is used to implement various functions that doesn't exist, @@ -59,7 +59,7 @@ pub fn unsupported_err() -> crate::io::Error { pub fn sgx_ineffective(v: T) -> crate::io::Result { static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false); if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) { - Err(crate::io::const_io_error!( + Err(crate::io::const_error!( ErrorKind::Uncategorized, "operation can't be trusted to have any effect on SGX", )) diff --git a/std/src/sys/pal/solid/fs.rs b/std/src/sys/pal/solid/fs.rs index 776a96ff3b7ba..04dd10ad806d3 100644 --- a/std/src/sys/pal/solid/fs.rs +++ b/std/src/sys/pal/solid/fs.rs @@ -303,7 +303,7 @@ fn cstr(path: &Path) -> io::Result { if !path.starts_with(br"\") { // Relative paths aren't supported - return Err(crate::io::const_io_error!( + return Err(crate::io::const_error!( crate::io::ErrorKind::Unsupported, "relative path is not supported on this platform", )); @@ -314,10 +314,7 @@ fn cstr(path: &Path) -> io::Result { let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat(); CString::from_vec_with_nul(wrapped_path).map_err(|_| { - crate::io::const_io_error!( - io::ErrorKind::InvalidInput, - "path provided contains a nul byte", - ) + crate::io::const_error!(io::ErrorKind::InvalidInput, "path provided contains a nul byte",) }) } @@ -512,7 +509,7 @@ impl fmt::Debug for File { pub fn unlink(p: &Path) -> io::Result<()> { if stat(p)?.file_type().is_dir() { - Err(io::const_io_error!(io::ErrorKind::IsADirectory, "is a directory")) + Err(io::const_error!(io::ErrorKind::IsADirectory, "is a directory")) } else { error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) .map_err(|e| e.as_io_error())?; @@ -542,7 +539,7 @@ pub fn rmdir(p: &Path) -> io::Result<()> { .map_err(|e| e.as_io_error())?; Ok(()) } else { - Err(io::const_io_error!(io::ErrorKind::NotADirectory, "not a directory")) + Err(io::const_error!(io::ErrorKind::NotADirectory, "not a directory")) } } @@ -570,7 +567,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { pub fn readlink(p: &Path) -> io::Result { // This target doesn't support symlinks stat(p)?; - Err(io::const_io_error!(io::ErrorKind::InvalidInput, "not a symbolic link")) + Err(io::const_error!(io::ErrorKind::InvalidInput, "not a symbolic link")) } pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { diff --git a/std/src/sys/pal/solid/net.rs b/std/src/sys/pal/solid/net.rs index c0818ecd856d2..5f6436807e27e 100644 --- a/std/src/sys/pal/solid/net.rs +++ b/std/src/sys/pal/solid/net.rs @@ -175,7 +175,7 @@ impl Socket { }; match n { - 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")), + 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), _ => { let can_write = writefds.num_fds != 0; if !can_write { diff --git a/std/src/sys/pal/solid/os.rs b/std/src/sys/pal/solid/os.rs index d8afcb91f67f2..57c28aed3b293 100644 --- a/std/src/sys/pal/solid/os.rs +++ b/std/src/sys/pal/solid/os.rs @@ -204,7 +204,7 @@ pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { /// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this /// function just returns a generic error. fn cvt_env(t: c_int) -> io::Result { - if t == -1 { Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } + if t == -1 { Err(io::const_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } } pub fn temp_dir() -> PathBuf { diff --git a/std/src/sys/pal/uefi/helpers.rs b/std/src/sys/pal/uefi/helpers.rs index abc8e69a285f3..47d9add72b5f0 100644 --- a/std/src/sys/pal/uefi/helpers.rs +++ b/std/src/sys/pal/uefi/helpers.rs @@ -13,7 +13,7 @@ use r_efi::efi::{self, Guid}; use r_efi::protocols::{device_path, device_path_to_text, shell}; use crate::ffi::{OsStr, OsString}; -use crate::io::{self, const_io_error}; +use crate::io::{self, const_error}; use crate::mem::{MaybeUninit, size_of}; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; @@ -30,7 +30,7 @@ type BootUninstallMultipleProtocolInterfaces = unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status; const BOOT_SERVICES_UNAVAILABLE: io::Error = - const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available"); + const_error!(io::ErrorKind::Other, "Boot Services are no longer available"); /// Locates Handles with a particular Protocol GUID. /// @@ -114,7 +114,7 @@ pub(crate) fn open_protocol( Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { NonNull::new(unsafe { protocol.assume_init() }) - .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol")) + .ok_or(const_error!(io::ErrorKind::Other, "null protocol")) } } @@ -134,7 +134,7 @@ pub(crate) fn create_event( if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { - NonNull::new(event).ok_or(const_io_error!(io::ErrorKind::Other, "null protocol")) + NonNull::new(event).ok_or(const_error!(io::ErrorKind::Other, "null protocol")) } } @@ -155,10 +155,8 @@ pub(crate) unsafe fn close_event(evt: NonNull) -> io::Result /// /// Note: Some protocols need to be manually freed. It is the caller's responsibility to do so. pub(crate) fn image_handle_protocol(protocol_guid: Guid) -> io::Result> { - let system_handle = uefi::env::try_image_handle().ok_or(io::const_io_error!( - io::ErrorKind::NotFound, - "Protocol not found in Image handle" - ))?; + let system_handle = uefi::env::try_image_handle() + .ok_or(io::const_error!(io::ErrorKind::NotFound, "Protocol not found in Image handle"))?; open_protocol(system_handle, protocol_guid) } @@ -178,7 +176,7 @@ pub(crate) fn device_path_to_text(path: NonNull) -> io::R }; let path = os_string_from_raw(path_ptr) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; if let Some(boot_services) = crate::os::uefi::env::boot_services() { let boot_services: NonNull = boot_services.cast(); @@ -213,7 +211,7 @@ pub(crate) fn device_path_to_text(path: NonNull) -> io::R } } - Err(io::const_io_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) + Err(io::const_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) } /// Gets RuntimeServices. @@ -234,7 +232,7 @@ impl DevicePath { ) -> io::Result { let path_vec = p.encode_wide().chain(Some(0)).collect::>(); if path_vec[..path_vec.len() - 1].contains(&0) { - return Err(const_io_error!( + return Err(const_error!( io::ErrorKind::InvalidInput, "strings passed to UEFI cannot contain NULs", )); @@ -243,9 +241,9 @@ impl DevicePath { let path = unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) }; - NonNull::new(path).map(DevicePath).ok_or_else(|| { - const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path") - }) + NonNull::new(path) + .map(DevicePath) + .ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")) } static LAST_VALID_HANDLE: AtomicPtr = @@ -271,7 +269,7 @@ impl DevicePath { } } - io::Result::Err(const_io_error!( + io::Result::Err(const_error!( io::ErrorKind::NotFound, "DevicePathFromText Protocol not found" )) @@ -326,7 +324,7 @@ impl OwnedProtocol { }; let handle = NonNull::new(handle) - .ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?; + .ok_or(io::const_error!(io::ErrorKind::Uncategorized, "found null handle"))?; Ok(Self { guid, handle, protocol }) } diff --git a/std/src/sys/pal/uefi/mod.rs b/std/src/sys/pal/uefi/mod.rs index c0ab52f650aa5..f29c91f3bfe68 100644 --- a/std/src/sys/pal/uefi/mod.rs +++ b/std/src/sys/pal/uefi/mod.rs @@ -95,7 +95,7 @@ pub const fn unsupported() -> std_io::Result { #[inline] pub const fn unsupported_err() -> std_io::Error { - std_io::const_io_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI",) + std_io::const_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI",) } pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind { diff --git a/std/src/sys/pal/uefi/os.rs b/std/src/sys/pal/uefi/os.rs index 27395f7c3c0b3..6d23c72ef2209 100644 --- a/std/src/sys/pal/uefi/os.rs +++ b/std/src/sys/pal/uefi/os.rs @@ -131,7 +131,7 @@ pub fn getcwd() -> io::Result { let path_ptr = unsafe { ((*shell.as_ptr()).get_cur_dir)(crate::ptr::null_mut()) }; helpers::os_string_from_raw(path_ptr) .map(PathBuf::from) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path")) + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path")) } None => { let mut t = current_exe()?; @@ -147,7 +147,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { let shell = helpers::open_shell().ok_or(unsupported_err())?; let mut p = helpers::os_string_to_raw(p.as_os_str()) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; let r = unsafe { ((*shell.as_ptr()).set_cur_dir)(crate::ptr::null_mut(), p.as_mut_ptr()) }; if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } @@ -290,15 +290,15 @@ mod uefi_env { pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; let mut val_ptr = helpers::os_string_to_raw(val) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } } pub(crate) fn unset(key: &OsStr) -> io::Result<()> { let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } } @@ -328,7 +328,7 @@ mod uefi_env { }); // SAFETY: val.add(start) is always NULL terminated let val = unsafe { get_raw(shell, val.add(start)) } - .ok_or(io::const_io_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; vars.push((key, val)); start = i + 1; diff --git a/std/src/sys/pal/uefi/process.rs b/std/src/sys/pal/uefi/process.rs index 1b83f4b0aee88..95707ebb7f023 100644 --- a/std/src/sys/pal/uefi/process.rs +++ b/std/src/sys/pal/uefi/process.rs @@ -307,7 +307,7 @@ mod uefi_command_internal { use super::super::helpers; use crate::ffi::{OsStr, OsString}; - use crate::io::{self, const_io_error}; + use crate::io::{self, const_error}; use crate::mem::MaybeUninit; use crate::os::uefi::env::{boot_services, image_handle, system_table}; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; @@ -328,7 +328,7 @@ mod uefi_command_internal { pub fn load_image(p: &OsStr) -> io::Result { let path = helpers::DevicePath::from_text(p)?; let boot_services: NonNull = boot_services() - .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? + .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); let mut child_handle: MaybeUninit = MaybeUninit::uninit(); let image_handle = image_handle(); @@ -369,7 +369,7 @@ mod uefi_command_internal { } let boot_services: NonNull = boot_services() - .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? + .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); let mut exit_data_size: usize = 0; let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit(); @@ -583,7 +583,7 @@ mod uefi_command_internal { OsString::from_wide(&self._buffer) .into_string() .map(Into::into) - .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) + .map_err(|_| const_error!(io::ErrorKind::Other, "utf8 conversion failed")) } extern "efiapi" fn reset( diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 96f99efb21e84..37029bcd36e30 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -559,7 +559,7 @@ impl FileAttr { return if (ext.stx_mask & libc::STATX_BTIME) != 0 { SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64) } else { - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Unsupported, "creation time is not available for the filesystem", )) @@ -567,7 +567,7 @@ impl FileAttr { } } - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Unsupported, "creation time is not available on this platform \ currently", @@ -1272,7 +1272,7 @@ impl File { target_vendor = "apple", )))] pub fn lock(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "lock() not supported")) } #[cfg(any( @@ -1293,7 +1293,7 @@ impl File { target_vendor = "apple", )))] pub fn lock_shared(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "lock_shared() not supported")) } #[cfg(any( @@ -1320,7 +1320,7 @@ impl File { target_vendor = "apple", )))] pub fn try_lock(&self) -> io::Result { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) } #[cfg(any( @@ -1347,7 +1347,7 @@ impl File { target_vendor = "apple", )))] pub fn try_lock_shared(&self) -> io::Result { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) } #[cfg(any( @@ -1368,7 +1368,7 @@ impl File { target_vendor = "apple", )))] pub fn unlock(&self) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "unlock() not supported")) + Err(io::const_error!(io::ErrorKind::Unsupported, "unlock() not supported")) } pub fn truncate(&self, size: u64) -> io::Result<()> { @@ -1459,11 +1459,11 @@ impl File { )))] let to_timespec = |time: Option| match time { Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts), - Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!( + Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_error!( io::ErrorKind::InvalidInput, "timestamp is too large to set as a file time" )), - Some(_) => Err(io::const_io_error!( + Some(_) => Err(io::const_error!( io::ErrorKind::InvalidInput, "timestamp is too small to set as a file time" )), @@ -1476,7 +1476,7 @@ impl File { // the same as for Redox. // `futimens` and `UTIME_OMIT` are a work in progress for vxworks. let _ = times; - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Unsupported, "setting file times not supported", )) @@ -1515,7 +1515,7 @@ impl File { weak!(fn futimens(c_int, *const libc::timespec) -> c_int); match futimens.get() { Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), - None => return Err(io::const_io_error!( + None => return Err(io::const_error!( io::ErrorKind::Unsupported, "setting file times requires Android API level >= 19", )), @@ -2090,7 +2090,7 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { #[cfg(target_os = "vxworks")] pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { let (_, _, _) = (path, uid, gid); - Err(io::const_io_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) + Err(io::const_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) } #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] @@ -2101,7 +2101,7 @@ pub fn chroot(dir: &Path) -> io::Result<()> { #[cfg(target_os = "vxworks")] pub fn chroot(dir: &Path) -> io::Result<()> { let _ = dir; - Err(io::const_io_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) + Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) } pub use remove_dir_impl::remove_dir_all; diff --git a/std/src/sys/pal/unix/l4re.rs b/std/src/sys/pal/unix/l4re.rs index 52d39dcfb16fb..37dd370c5146c 100644 --- a/std/src/sys/pal/unix/l4re.rs +++ b/std/src/sys/pal/unix/l4re.rs @@ -1,6 +1,6 @@ macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, "No networking available on L4Re.", )); diff --git a/std/src/sys/pal/unix/net.rs b/std/src/sys/pal/unix/net.rs index 6a67bb0a101e9..d140607869c14 100644 --- a/std/src/sys/pal/unix/net.rs +++ b/std/src/sys/pal/unix/net.rs @@ -190,7 +190,7 @@ impl Socket { loop { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); } let timeout = timeout - elapsed; @@ -225,7 +225,7 @@ impl Socket { // for POLLHUP or POLLERR rather than read readiness if pollfd.revents & (libc::POLLHUP | libc::POLLERR) != 0 { let e = self.take_error()?.unwrap_or_else(|| { - io::const_io_error!( + io::const_error!( io::ErrorKind::Uncategorized, "no error set after POLLHUP", ) diff --git a/std/src/sys/pal/unix/os.rs b/std/src/sys/pal/unix/os.rs index f207131ddf332..789a40c13e61b 100644 --- a/std/src/sys/pal/unix/os.rs +++ b/std/src/sys/pal/unix/os.rs @@ -258,7 +258,7 @@ pub fn current_exe() -> io::Result { use crate::env; use crate::io::ErrorKind; - let exe_path = env::args().next().ok_or(io::const_io_error!( + let exe_path = env::args().next().ok_or(io::const_error!( ErrorKind::NotFound, "an executable path was not found because no arguments were provided through argv" ))?; @@ -284,7 +284,7 @@ pub fn current_exe() -> io::Result { } } } - Err(io::const_io_error!(ErrorKind::NotFound, "an executable path was not found")) + Err(io::const_error!(ErrorKind::NotFound, "an executable path was not found")) } #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] @@ -340,7 +340,7 @@ pub fn current_exe() -> io::Result { 0, ))?; if path_len <= 1 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Uncategorized, "KERN_PROC_PATHNAME sysctl returned zero-length string", )); @@ -363,7 +363,7 @@ pub fn current_exe() -> io::Result { if curproc_exe.is_file() { return crate::fs::read_link(curproc_exe); } - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::Uncategorized, "/proc/curproc/exe doesn't point to regular file.", )) @@ -382,10 +382,9 @@ pub fn current_exe() -> io::Result { cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?; argv.set_len(argv_len as usize); if argv[0].is_null() { - return Err(io::const_io_error!( - io::ErrorKind::Uncategorized, - "no current exe available", - )); + return Err( + io::const_error!(io::ErrorKind::Uncategorized, "no current exe available",), + ); } let argv0 = CStr::from_ptr(argv[0]).to_bytes(); if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') { @@ -405,7 +404,7 @@ pub fn current_exe() -> io::Result { ))] pub fn current_exe() -> io::Result { match crate::fs::read_link("/proc/self/exe") { - Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!( + Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_error!( io::ErrorKind::Uncategorized, "no /proc/self/exe available. Is /proc mounted?", )), @@ -476,7 +475,7 @@ pub fn current_exe() -> io::Result { ); if result != libc::B_OK { use crate::io::ErrorKind; - Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path")) + Err(io::const_error!(ErrorKind::Uncategorized, "Error getting executable path")) } else { // find_path adds the null terminator. let name = CStr::from_ptr(name.as_ptr()).to_bytes(); @@ -493,7 +492,7 @@ pub fn current_exe() -> io::Result { #[cfg(target_os = "l4re")] pub fn current_exe() -> io::Result { use crate::io::ErrorKind; - Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!")) + Err(io::const_error!(ErrorKind::Unsupported, "Not yet implemented!")) } #[cfg(target_os = "vxworks")] @@ -523,7 +522,7 @@ pub fn current_exe() -> io::Result { use crate::env; use crate::io::ErrorKind; - let exe_path = env::args().next().ok_or(io::const_io_error!( + let exe_path = env::args().next().ok_or(io::const_error!( ErrorKind::Uncategorized, "an executable path was not found because no arguments were provided through argv" ))?; diff --git a/std/src/sys/pal/unix/process/process_fuchsia.rs b/std/src/sys/pal/unix/process/process_fuchsia.rs index 8f7d786e32fcd..b7a35718757ae 100644 --- a/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -18,7 +18,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "nul byte found in provided data", )); @@ -38,7 +38,7 @@ impl Command { pub fn exec(&mut self, default: Stdio) -> io::Error { if self.saw_nul() { - return io::const_io_error!( + return io::const_error!( io::ErrorKind::InvalidInput, "nul byte found in provided data", ); @@ -185,7 +185,7 @@ impl Process { ))?; } if actual != 1 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Failed to get exit status of process", )); @@ -222,7 +222,7 @@ impl Process { ))?; } if actual != 1 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Failed to get exit status of process", )); diff --git a/std/src/sys/pal/unix/process/process_unix.rs b/std/src/sys/pal/unix/process/process_unix.rs index 8faf1fda5464d..ec4965c1d7196 100644 --- a/std/src/sys/pal/unix/process/process_unix.rs +++ b/std/src/sys/pal/unix/process/process_unix.rs @@ -61,7 +61,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::InvalidInput, "nul byte found in provided data", )); @@ -175,7 +175,7 @@ impl Command { // allowed to exist in dead code), but it sounds bad, so we go out of our // way to avoid that all-together. #[cfg(any(target_os = "tvos", target_os = "watchos"))] - const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!( + const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_error!( ErrorKind::Unsupported, "`fork`+`exec`-based process spawning is not supported on this target", ); @@ -218,7 +218,7 @@ impl Command { } else if delay < MAX_FORKSPAWN_SLEEP { thread::sleep(delay); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::WouldBlock, "forking returned EBADF too often", )); @@ -235,7 +235,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data",); + return io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data",); } match self.setup_io(default, true) { @@ -561,7 +561,7 @@ impl Command { } else if delay < MAX_FORKSPAWN_SLEEP { thread::sleep(delay); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::WouldBlock, "posix_spawnp returned EBADF too often", )); diff --git a/std/src/sys/pal/unix/process/process_vxworks.rs b/std/src/sys/pal/unix/process/process_vxworks.rs index 38daf6af91808..e2c1b6a032624 100644 --- a/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/std/src/sys/pal/unix/process/process_vxworks.rs @@ -22,7 +22,7 @@ impl Command { let envp = self.capture_env(); if self.saw_nul() { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::InvalidInput, "nul byte found in provided data", )); diff --git a/std/src/sys/pal/unix/thread.rs b/std/src/sys/pal/unix/thread.rs index 040246618360f..131a6e81b1e92 100644 --- a/std/src/sys/pal/unix/thread.rs +++ b/std/src/sys/pal/unix/thread.rs @@ -469,7 +469,7 @@ pub fn available_parallelism() -> io::Result> { unsafe { use libc::_syspage_ptr; if _syspage_ptr.is_null() { - Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available")) + Err(io::const_error!(io::ErrorKind::NotFound, "No syspage available")) } else { let cpus = (*_syspage_ptr).num_cpu; NonZero::new(cpus as usize) @@ -509,7 +509,7 @@ pub fn available_parallelism() -> io::Result> { } } else { // FIXME: implement on Redox, l4re - Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) } } } diff --git a/std/src/sys/pal/unix/time.rs b/std/src/sys/pal/unix/time.rs index 535fe6b27d91e..343864d0b3fd2 100644 --- a/std/src/sys/pal/unix/time.rs +++ b/std/src/sys/pal/unix/time.rs @@ -96,7 +96,7 @@ impl Timespec { if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 { Ok(unsafe { Self::new_unchecked(tv_sec, tv_nsec) }) } else { - Err(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid timestamp")) + Err(io::const_error!(io::ErrorKind::InvalidData, "Invalid timestamp")) } } diff --git a/std/src/sys/pal/unsupported/os.rs b/std/src/sys/pal/unsupported/os.rs index 481fd62c04fe8..48de4312885fe 100644 --- a/std/src/sys/pal/unsupported/os.rs +++ b/std/src/sys/pal/unsupported/os.rs @@ -96,11 +96,11 @@ pub fn getenv(_: &OsStr) -> Option { } pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) } pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) } pub fn temp_dir() -> PathBuf { diff --git a/std/src/sys/pal/wasi/fs.rs b/std/src/sys/pal/wasi/fs.rs index 3296c762cca2b..0667eb9010100 100644 --- a/std/src/sys/pal/wasi/fs.rs +++ b/std/src/sys/pal/wasi/fs.rs @@ -496,7 +496,7 @@ impl File { pub fn set_times(&self, times: FileTimes) -> io::Result<()> { let to_timestamp = |time: Option| match time { Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts), - Some(_) => Err(io::const_io_error!( + Some(_) => Err(io::const_error!( io::ErrorKind::InvalidInput, "timestamp is too large to set as a file time" )), @@ -764,8 +764,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { } pub fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str() - .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) + f.to_str().ok_or_else(|| io::const_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) } pub fn copy(from: &Path, to: &Path) -> io::Result { @@ -811,7 +810,7 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { for entry in ReadDir::new(fd, dummy_root) { let entry = entry?; let path = crate::str::from_utf8(&entry.name).map_err(|_| { - io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") + io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") })?; let result: io::Result<()> = try { diff --git a/std/src/sys/pal/wasip2/net.rs b/std/src/sys/pal/wasip2/net.rs index 06e623df8438e..f009a51821f35 100644 --- a/std/src/sys/pal/wasip2/net.rs +++ b/std/src/sys/pal/wasip2/net.rs @@ -117,7 +117,7 @@ impl Socket { loop { let elapsed = start.elapsed(); if elapsed >= timeout { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")); } let timeout = timeout - elapsed; diff --git a/std/src/sys/pal/windows/args.rs b/std/src/sys/pal/windows/args.rs index e9fc19bcb99c1..3447a0157e4c5 100644 --- a/std/src/sys/pal/windows/args.rs +++ b/std/src/sys/pal/windows/args.rs @@ -327,7 +327,7 @@ pub(crate) fn make_bat_command_line( force_quotes: bool, ) -> io::Result> { const INVALID_ARGUMENT_ERROR: io::Error = - io::const_io_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); + io::const_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); // Set the start of the command line to `cmd.exe /c "` // It is necessary to surround the command in an extra pair of quotes, // hence the trailing quote here. It will be closed after all arguments @@ -340,7 +340,7 @@ pub(crate) fn make_bat_command_line( // Windows file names cannot contain a `"` character or end with `\\`. // If the script name does then return an error. if script.contains(&(b'"' as u16)) || script.last() == Some(&(b'\\' as u16)) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "Windows file names may not contain `\"` or end with `\\`" )); diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 07e4f93a37956..5bdd5f81b9c3d 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -677,7 +677,7 @@ impl File { ) } _ => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Uncategorized, "Unsupported reparse point type", )); @@ -718,7 +718,7 @@ impl File { || times.modified.map_or(false, is_zero) || times.created.map_or(false, is_zero) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0", )); @@ -728,7 +728,7 @@ impl File { || times.modified.map_or(false, is_max) || times.created.map_or(false, is_max) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0xFFFF_FFFF_FFFF_FFFF", )); @@ -1305,10 +1305,9 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { #[cfg(target_vendor = "uwp")] pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { - return Err(io::const_io_error!( - io::ErrorKind::Unsupported, - "hard link are not supported on UWP", - )); + return Err( + io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP",), + ); } pub fn stat(path: &Path) -> io::Result { @@ -1495,7 +1494,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { let bytes = unsafe { OsStr::from_encoded_bytes_unchecked(&abs_path[2..]) }; r"\??\UNC\".encode_utf16().chain(bytes.encode_wide()).collect() } else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, "path is not valid")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "path is not valid")); } }; // Defined inline so we don't have to mess about with variable length buffer. @@ -1512,10 +1511,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } let data_len = 12 + (abs_path.len() * 2); if data_len > u16::MAX as usize { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "`original` path is too long" - )); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long")); } let data_len = data_len as u16; let mut header = MountPointBuffer { diff --git a/std/src/sys/pal/windows/mod.rs b/std/src/sys/pal/windows/mod.rs index aca69490d7a1a..d66ff15e10bf6 100644 --- a/std/src/sys/pal/windows/mod.rs +++ b/std/src/sys/pal/windows/mod.rs @@ -183,7 +183,7 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { maybe_result.extend(s.encode_wide()); if unrolled_find_u16s(0, &maybe_result).is_some() { - return Err(crate::io::const_io_error!( + return Err(crate::io::const_error!( ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", )); diff --git a/std/src/sys/pal/windows/net.rs b/std/src/sys/pal/windows/net.rs index fd62d1f407c27..a92853c642c06 100644 --- a/std/src/sys/pal/windows/net.rs +++ b/std/src/sys/pal/windows/net.rs @@ -267,7 +267,7 @@ impl Socket { }; match count { - 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")), + 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), _ => { if writefds.fd_count != 1 { if let Some(e) = self.take_error()? { diff --git a/std/src/sys/pal/windows/process.rs b/std/src/sys/pal/windows/process.rs index 17bb03fe7af04..da0daacd1dde3 100644 --- a/std/src/sys/pal/windows/process.rs +++ b/std/src/sys/pal/windows/process.rs @@ -144,7 +144,7 @@ impl AsRef for EnvKey { pub(crate) fn ensure_no_nuls>(str: T) -> io::Result { if str.as_ref().encode_wide().any(|b| b == 0) { - Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) + Err(io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) } else { Ok(str) } @@ -439,10 +439,9 @@ fn resolve_exe<'a>( ) -> io::Result> { // Early return if there is no filename. if exe_path.is_empty() || path::has_trailing_slash(exe_path) { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - "program path has no file name", - )); + return Err( + io::const_error!(io::ErrorKind::InvalidInput, "program path has no file name",), + ); } // Test if the file name has the `exe` extension. // This does a case-insensitive `ends_with`. @@ -492,7 +491,7 @@ fn resolve_exe<'a>( } } // If we get here then the executable cannot be found. - Err(io::const_io_error!(io::ErrorKind::NotFound, "program not found")) + Err(io::const_error!(io::ErrorKind::NotFound, "program not found")) } // Calls `f` for every path that should be used to find an executable. @@ -921,7 +920,7 @@ fn make_proc_thread_attribute_list( // a null pointer to retrieve the required size. let mut required_size = 0; let Ok(attribute_count) = attributes.len().try_into() else { - return Err(io::const_io_error!( + return Err(io::const_error!( ErrorKind::InvalidInput, "maximum number of ProcThreadAttributes exceeded", )); diff --git a/std/src/sys/pal/windows/stdio.rs b/std/src/sys/pal/windows/stdio.rs index 575f2250eb91c..642c8bc4df7d1 100644 --- a/std/src/sys/pal/windows/stdio.rs +++ b/std/src/sys/pal/windows/stdio.rs @@ -107,7 +107,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i if data[0] >> 6 != 0b10 { // not a continuation byte - reject incomplete_utf8.len = 0; - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); @@ -129,7 +129,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i return Ok(1); } Err(_) => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); @@ -153,7 +153,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i incomplete_utf8.len = 1; return Ok(1); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); @@ -392,7 +392,7 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { }; if result == 0 { // We can't really do any better than forget all data and return an error. - Err(io::const_io_error!( + Err(io::const_error!( io::ErrorKind::InvalidData, "Windows stdin in console mode does not support non-UTF-16 input; \ encountered unpaired surrogate", diff --git a/std/src/sys/pal/xous/net/dns.rs b/std/src/sys/pal/xous/net/dns.rs index 1a2b56b4da5d3..ff6e49ed2d430 100644 --- a/std/src/sys/pal/xous/net/dns.rs +++ b/std/src/sys/pal/xous/net/dns.rs @@ -107,7 +107,7 @@ impl TryFrom<&str> for LookupHost { ($e:expr, $msg:expr) => { match $e { Some(r) => r, - None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)), + None => return Err(io::const_error!(io::ErrorKind::InvalidInput, &$msg)), } }; } @@ -123,7 +123,6 @@ impl TryFrom<(&str, u16)> for LookupHost { type Error = io::Error; fn try_from(v: (&str, u16)) -> io::Result { - lookup(v.0, v.1) - .map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure")) + lookup(v.0, v.1).map_err(|_e| io::const_error!(io::ErrorKind::InvalidInput, &"DNS failure")) } } diff --git a/std/src/sys/pal/xous/net/tcplistener.rs b/std/src/sys/pal/xous/net/tcplistener.rs index ddfb289162b69..640a02a64f525 100644 --- a/std/src/sys/pal/xous/net/tcplistener.rs +++ b/std/src/sys/pal/xous/net/tcplistener.rs @@ -9,7 +9,7 @@ use crate::{fmt, io}; macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, &"This function is not yet implemented", )); @@ -71,7 +71,7 @@ impl TcpListener { 0, 4096, ) else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Invalid response")); }; // The first four bytes should be zero upon success, and will be nonzero @@ -80,16 +80,13 @@ impl TcpListener { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_io_error!( - io::ErrorKind::AddrNotAvailable, - &"Invalid address" - )); + return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, &"Invalid address")); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Other, &"Unable to connect or internal error" )); @@ -130,16 +127,15 @@ impl TcpListener { if receive_request.raw[0] != 0 { // error case if receive_request.raw[1] == NetError::TimedOut as u8 { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"accept timed out",)); + return Err(io::const_error!(io::ErrorKind::TimedOut, &"accept timed out",)); } else if receive_request.raw[1] == NetError::WouldBlock as u8 { - return Err(io::const_io_error!( - io::ErrorKind::WouldBlock, - &"accept would block", - )); + return Err( + io::const_error!(io::ErrorKind::WouldBlock, &"accept would block",), + ); } else if receive_request.raw[1] == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); } } else { // accept successful @@ -163,7 +159,7 @@ impl TcpListener { port, ) } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); }; // replenish the listener @@ -175,7 +171,7 @@ impl TcpListener { Ok((TcpStream::from_listener(stream_fd, self.local.port(), port, addr), addr)) } } else { - Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unable to accept")) + Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unable to accept")) } } @@ -192,7 +188,7 @@ impl TcpListener { services::net_server(), services::NetBlockingScalar::StdSetTtlTcp(self.fd.load(Ordering::Relaxed), ttl).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -201,7 +197,7 @@ impl TcpListener { services::net_server(), services::NetBlockingScalar::StdGetTtlTcp(self.fd.load(Ordering::Relaxed)).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/std/src/sys/pal/xous/net/tcpstream.rs b/std/src/sys/pal/xous/net/tcpstream.rs index 03442cf2fcdfd..572dd6b3b6398 100644 --- a/std/src/sys/pal/xous/net/tcpstream.rs +++ b/std/src/sys/pal/xous/net/tcpstream.rs @@ -10,7 +10,7 @@ use crate::time::Duration; macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, &"This function is not yet implemented", )); @@ -96,7 +96,7 @@ impl TcpStream { 0, 4096, ) else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Invalid response")); }; // The first four bytes should be zero upon success, and will be nonzero @@ -106,14 +106,11 @@ impl TcpStream { // errcode is a u8 but stuck in a u16 where the upper byte is invalid. Mask & decode accordingly. let errcode = response[0]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use",)); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, &"Socket in use",)); } else if errcode == NetError::Unaddressable as u8 { - return Err(io::const_io_error!( - io::ErrorKind::AddrNotAvailable, - &"Invalid address", - )); + return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, &"Invalid address",)); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Unable to connect or internal error", )); @@ -199,7 +196,7 @@ impl TcpStream { self.read_timeout.load(Ordering::Relaxed) as usize, data_to_read, ) else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Library failure: wrong message type or messaging error" )); @@ -215,14 +212,14 @@ impl TcpStream { if result[0] != 0 { if result[1] == 8 { // timed out - return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"Timeout",)); + return Err(io::const_error!(io::ErrorKind::TimedOut, &"Timeout",)); } if result[1] == 9 { // would block - return Err(io::const_io_error!(io::ErrorKind::WouldBlock, &"Would block",)); + return Err(io::const_error!(io::ErrorKind::WouldBlock, &"Would block",)); } } - Err(io::const_io_error!(io::ErrorKind::Other, &"recv_slice failure")) + Err(io::const_error!(io::ErrorKind::Other, &"recv_slice failure")) } } @@ -261,23 +258,20 @@ impl TcpStream { self.write_timeout.load(Ordering::Relaxed) as usize, buf_len, ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")))?; + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Internal error")))?; if send_request.raw[0] != 0 { if send_request.raw[4] == 8 { // timed out - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::BrokenPipe, &"Timeout or connection closed", )); } else if send_request.raw[4] == 9 { // would block - return Err(io::const_io_error!(io::ErrorKind::WouldBlock, &"Would block",)); + return Err(io::const_error!(io::ErrorKind::WouldBlock, &"Would block",)); } else { - return Err(io::const_io_error!( - io::ErrorKind::InvalidInput, - &"Error when sending", - )); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Error when sending",)); } } Ok(u32::from_le_bytes([ @@ -310,7 +304,7 @@ impl TcpStream { 0, 0, ) else { - return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, &"Internal error")); }; let mut i = get_addr.raw.iter(); match *i.next().unwrap() { @@ -330,7 +324,7 @@ impl TcpStream { } Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0))) } - _ => Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Internal error")), + _ => Err(io::const_error!(io::ErrorKind::InvalidInput, &"Internal error")), } } @@ -339,7 +333,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdTcpStreamShutdown(self.fd, how).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -361,7 +355,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdSetNodelay(self.fd, enabled).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -370,7 +364,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdGetNodelay(self.fd).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] != 0)?) } @@ -382,7 +376,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdSetTtlTcp(self.fd, ttl).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -391,7 +385,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdGetTtlTcp(self.fd).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/std/src/sys/pal/xous/net/udp.rs b/std/src/sys/pal/xous/net/udp.rs index de5133280ba9d..1b7ecac6d3a7e 100644 --- a/std/src/sys/pal/xous/net/udp.rs +++ b/std/src/sys/pal/xous/net/udp.rs @@ -11,7 +11,7 @@ use crate::{fmt, io}; macro_rules! unimpl { () => { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Unsupported, &"This function is not yet implemented", )); @@ -72,16 +72,16 @@ impl UdpSocket { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, &"Socket in use")); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Port can't be 0 or invalid address" )); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Other, &"Unable to connect or internal error" )); @@ -98,13 +98,13 @@ impl UdpSocket { nonblocking: Cell::new(false), }); } - Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Invalid response")) + Err(io::const_error!(io::ErrorKind::InvalidInput, &"Invalid response")) } pub fn peer_addr(&self) -> io::Result { match self.remote.get() { Some(dest) => Ok(dest), - None => Err(io::const_io_error!(io::ErrorKind::NotConnected, &"No peer specified")), + None => Err(io::const_error!(io::ErrorKind::NotConnected, &"No peer specified")), } } @@ -141,16 +141,13 @@ impl UdpSocket { if receive_request.raw[0] != 0 { // error case if receive_request.raw[1] == NetError::TimedOut as u8 { - return Err(io::const_io_error!(io::ErrorKind::TimedOut, &"recv timed out",)); + return Err(io::const_error!(io::ErrorKind::TimedOut, &"recv timed out",)); } else if receive_request.raw[1] == NetError::WouldBlock as u8 { - return Err(io::const_io_error!( - io::ErrorKind::WouldBlock, - &"recv would block", - )); + return Err(io::const_error!(io::ErrorKind::WouldBlock, &"recv would block",)); } else if receive_request.raw[1] == NetError::LibraryError as u8 { - return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); } } else { let rr = &receive_request.raw; @@ -173,7 +170,7 @@ impl UdpSocket { port, ) } else { - return Err(io::const_io_error!(io::ErrorKind::Other, &"library error",)); + return Err(io::const_error!(io::ErrorKind::Other, &"library error",)); }; for (&s, d) in rr[22..22 + rxlen as usize].iter().zip(buf.iter_mut()) { *d = s; @@ -181,7 +178,7 @@ impl UdpSocket { Ok((rxlen as usize, addr)) } } else { - Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unable to recv")) + Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unable to recv")) } } @@ -211,7 +208,7 @@ impl UdpSocket { if let Some(addr) = self.remote.get() { self.send_to(buf, &addr) } else { - Err(io::const_io_error!(io::ErrorKind::NotConnected, &"No remote specified")) + Err(io::const_error!(io::ErrorKind::NotConnected, &"No remote specified")) } } @@ -282,22 +279,19 @@ impl UdpSocket { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::ResourceBusy, &"Socket in use" )); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, &"Socket not valid" )); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_io_error!( - io::ErrorKind::Other, - &"Library error" - )); + return Err(io::const_error!(io::ErrorKind::Other, &"Library error")); } else { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::Other, &"Unable to connect" )); @@ -309,7 +303,7 @@ impl UdpSocket { } Err(crate::os::xous::ffi::Error::ServerQueueFull) => { if now.elapsed() >= write_timeout { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::WouldBlock, &"Write timed out" )); @@ -318,7 +312,7 @@ impl UdpSocket { crate::thread::yield_now(); } } - _ => return Err(io::const_io_error!(io::ErrorKind::Other, &"Library error")), + _ => return Err(io::const_error!(io::ErrorKind::Other, &"Library error")), } } } @@ -372,7 +366,7 @@ impl UdpSocket { services::net_server(), services::NetBlockingScalar::StdSetTtlUdp(self.fd, ttl).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|_| ()) } @@ -381,7 +375,7 @@ impl UdpSocket { services::net_server(), services::NetBlockingScalar::StdGetTtlUdp(self.fd).into(), ) - .or(Err(io::const_io_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, &"Unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/std/src/sys/pal/zkvm/os.rs b/std/src/sys/pal/zkvm/os.rs index 5d224ffd1ba5a..868b19e33b672 100644 --- a/std/src/sys/pal/zkvm/os.rs +++ b/std/src/sys/pal/zkvm/os.rs @@ -115,11 +115,11 @@ pub fn getenv(varname: &OsStr) -> Option { } pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) } pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) } pub fn temp_dir() -> PathBuf { diff --git a/std/src/sys/path/windows.rs b/std/src/sys/path/windows.rs index 9267602cb9715..de042fa3f82ab 100644 --- a/std/src/sys/path/windows.rs +++ b/std/src/sys/path/windows.rs @@ -328,7 +328,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { if prefix.map(|x| x.is_verbatim()).unwrap_or(false) { // NULs in verbatim paths are rejected for consistency. if path.as_encoded_bytes().contains(&0) { - return Err(io::const_io_error!( + return Err(io::const_error!( io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", )); diff --git a/std/src/sys_common/fs.rs b/std/src/sys_common/fs.rs index a25a7244660bb..bfd684d295b89 100644 --- a/std/src/sys_common/fs.rs +++ b/std/src/sys_common/fs.rs @@ -5,7 +5,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::path::Path; use crate::sys_common::ignore_notfound; -pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!( +pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( ErrorKind::InvalidInput, "the source path is neither a regular file nor a symlink to a regular file", ); diff --git a/std/src/sys_common/net.rs b/std/src/sys_common/net.rs index 5a0ad90758101..74306978d2284 100644 --- a/std/src/sys_common/net.rs +++ b/std/src/sys_common/net.rs @@ -122,7 +122,7 @@ pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result *(storage as *const _ as *const c::sockaddr_in6) }))) } - _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument")), + _ => Err(io::const_error!(ErrorKind::InvalidInput, "invalid argument")), } } @@ -185,7 +185,7 @@ impl TryFrom<&str> for LookupHost { ($e:expr, $msg:expr) => { match $e { Some(r) => r, - None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)), + None => return Err(io::const_error!(io::ErrorKind::InvalidInput, $msg)), } }; } From dc61e4137ee6f949219e0fc409e7a605e221b772 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 23 Nov 2024 16:11:02 +1100 Subject: [PATCH 010/481] Sort and separate lint/feature attributes in `profiler_builtins` --- profiler_builtins/src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/profiler_builtins/src/lib.rs b/profiler_builtins/src/lib.rs index ac685b18c2911..b868cdde405a9 100644 --- a/profiler_builtins/src/lib.rs +++ b/profiler_builtins/src/lib.rs @@ -1,11 +1,15 @@ -#![no_std] +// tidy-alphabetical-start +#![allow(internal_features)] +#![allow(unused_features)] #![feature(profiler_runtime)] +#![feature(staged_api)] +// tidy-alphabetical-end + +// Other attributes: +#![no_std] #![profiler_runtime] #![unstable( feature = "profiler_runtime_lib", reason = "internal implementation detail of rustc right now", issue = "none" )] -#![allow(unused_features)] -#![allow(internal_features)] -#![feature(staged_api)] From bf43487dcdf5fd50a0cdefbfdb4f05389c0f9904 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 23 Nov 2024 16:13:53 +1100 Subject: [PATCH 011/481] Remove unnecessary `#![allow(unused_features)]` --- profiler_builtins/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/profiler_builtins/src/lib.rs b/profiler_builtins/src/lib.rs index b868cdde405a9..68b6058db978c 100644 --- a/profiler_builtins/src/lib.rs +++ b/profiler_builtins/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![allow(unused_features)] #![feature(profiler_runtime)] #![feature(staged_api)] // tidy-alphabetical-end From 36569a27b28b64f4e3f4fdfcf7902646dcd5f698 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 23 Nov 2024 16:14:40 +1100 Subject: [PATCH 012/481] Make profiler_builtins `#![no_core]` instead of just `#![no_std]` This crate doesn't contain any actual Rust code; it's just C/C++ code built and packaged in a Rust-friendly way. --- Cargo.lock | 2 -- profiler_builtins/Cargo.toml | 2 -- profiler_builtins/src/lib.rs | 3 ++- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55851daaf2a80..197e0a8fedb8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,8 +235,6 @@ name = "profiler_builtins" version = "0.0.0" dependencies = [ "cc", - "compiler_builtins", - "core", ] [[package]] diff --git a/profiler_builtins/Cargo.toml b/profiler_builtins/Cargo.toml index 9aadefce3b39e..c601a41b433c7 100644 --- a/profiler_builtins/Cargo.toml +++ b/profiler_builtins/Cargo.toml @@ -9,8 +9,6 @@ bench = false doc = false [dependencies] -core = { path = "../core" } -compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] cc = "1.2" diff --git a/profiler_builtins/src/lib.rs b/profiler_builtins/src/lib.rs index 68b6058db978c..a258f7d31a191 100644 --- a/profiler_builtins/src/lib.rs +++ b/profiler_builtins/src/lib.rs @@ -1,11 +1,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![feature(no_core)] #![feature(profiler_runtime)] #![feature(staged_api)] // tidy-alphabetical-end // Other attributes: -#![no_std] +#![no_core] #![profiler_runtime] #![unstable( feature = "profiler_runtime_lib", From 15cdb2afe07d4162f91fa99350b5e551b113955a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 Nov 2024 15:19:19 +0100 Subject: [PATCH 013/481] Add missing code examples on `LocalKey` --- std/src/thread/local.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/std/src/thread/local.rs b/std/src/thread/local.rs index 9edb3fa41933d..bc5f701e3464a 100644 --- a/std/src/thread/local.rs +++ b/std/src/thread/local.rs @@ -252,6 +252,19 @@ impl LocalKey { /// This function will `panic!()` if the key currently has its /// destructor running, and it **may** panic if the destructor has /// previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// thread_local! { + /// pub static STATIC: String = String::from("I am"); + /// } + /// + /// assert_eq!( + /// STATIC.with(|original_value| format!("{original_value} initialized")), + /// "I am initialized", + /// ); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with(&'static self, f: F) -> R where @@ -273,6 +286,19 @@ impl LocalKey { /// /// This function will still `panic!()` if the key is uninitialized and the /// key's initializer panics. + /// + /// # Examples + /// + /// ``` + /// thread_local! { + /// pub static STATIC: String = String::from("I am"); + /// } + /// + /// assert_eq!( + /// STATIC.try_with(|original_value| format!("{original_value} initialized")), + /// Ok(String::from("I am initialized")), + /// ); + /// ``` #[stable(feature = "thread_local_try_with", since = "1.26.0")] #[inline] pub fn try_with(&'static self, f: F) -> Result @@ -452,7 +478,7 @@ impl LocalKey> { /// Panics if the key currently has its destructor running, /// and it **may** panic if the destructor has previously been run for this thread. /// - /// # Example + /// # Examples /// /// ``` /// use std::cell::RefCell; @@ -483,7 +509,7 @@ impl LocalKey> { /// Panics if the key currently has its destructor running, /// and it **may** panic if the destructor has previously been run for this thread. /// - /// # Example + /// # Examples /// /// ``` /// use std::cell::RefCell; From bd7f5d83c05126dd0d25209692f2edf7dad1608c Mon Sep 17 00:00:00 2001 From: Peter Gervai Date: Thu, 22 Aug 2024 14:29:57 +0200 Subject: [PATCH 014/481] Expand std::os::unix::fs::chown() doc with a warning Include warning about losing setuid/gid when chowning, per POSIX. --- std/src/os/unix/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/std/src/os/unix/fs.rs b/std/src/os/unix/fs.rs index ba6481f052cdf..fd542cd8c0672 100644 --- a/std/src/os/unix/fs.rs +++ b/std/src/os/unix/fs.rs @@ -986,6 +986,10 @@ impl DirBuilderExt for fs::DirBuilder { /// Changing the owner typically requires privileges, such as root or a specific capability. /// Changing the group typically requires either being the owner and a member of the group, or /// having privileges. +/// +/// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases +/// according to POSIX, usually even if the user is root. The sgid is not cleared when +/// the file is non-group-executable. /// /// If called on a symbolic link, this will change the owner and group of the link target. To /// change the owner and group of the link itself, see [`lchown`]. From c2c0a75f9233e84b1b3055d2a67722c439e50d6c Mon Sep 17 00:00:00 2001 From: Peter Gervai Date: Thu, 22 Aug 2024 18:38:27 +0200 Subject: [PATCH 015/481] Update chown help with a link and adding cap warning Linked to chown(2) manpage on the web which expands on chown call behaviour. --- std/src/os/unix/fs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/std/src/os/unix/fs.rs b/std/src/os/unix/fs.rs index fd542cd8c0672..4fc94c1a1b19d 100644 --- a/std/src/os/unix/fs.rs +++ b/std/src/os/unix/fs.rs @@ -989,7 +989,8 @@ impl DirBuilderExt for fs::DirBuilder { /// /// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases /// according to POSIX, usually even if the user is root. The sgid is not cleared when -/// the file is non-group-executable. +/// the file is non-group-executable. See: +/// This call may also clear file capabilities, if there was any. /// /// If called on a symbolic link, this will change the owner and group of the link target. To /// change the owner and group of the link itself, see [`lchown`]. From 4729e105a9e4cd308963266ee99dfd7d9b33a160 Mon Sep 17 00:00:00 2001 From: Peter Gervai Date: Thu, 14 Nov 2024 22:01:13 +0100 Subject: [PATCH 016/481] Remove one stray space. --- std/src/os/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/os/unix/fs.rs b/std/src/os/unix/fs.rs index 4fc94c1a1b19d..04a45fd035a55 100644 --- a/std/src/os/unix/fs.rs +++ b/std/src/os/unix/fs.rs @@ -986,7 +986,7 @@ impl DirBuilderExt for fs::DirBuilder { /// Changing the owner typically requires privileges, such as root or a specific capability. /// Changing the group typically requires either being the owner and a member of the group, or /// having privileges. -/// +/// /// Be aware that changing owner clears the `suid` and `sgid` permission bits in most cases /// according to POSIX, usually even if the user is root. The sgid is not cleared when /// the file is non-group-executable. See: From bafdacdaa20a973d4167cd6880040913340909c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Tue, 26 Nov 2024 21:49:28 +0100 Subject: [PATCH 017/481] Add '<[T]>::as_array', '<[T]>::as_mut_array', '<*const [T]>::as_array', and '<*mut [T]>::as_mut_array' conversion methods; --- core/src/array/mod.rs | 20 ++++---------------- core/src/lib.rs | 1 + core/src/ptr/const_ptr.rs | 16 ++++++++++++++++ core/src/ptr/mut_ptr.rs | 16 ++++++++++++++++ core/src/slice/mod.rs | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index 67fbda34bb935..95c1eb460cd94 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -214,8 +214,8 @@ impl BorrowMut<[T]> for [T; N] { } } -/// Tries to create an array `[T; N]` by copying from a slice `&[T]`. Succeeds if -/// `slice.len() == N`. +/// Tries to create an array `[T; N]` by copying from a slice `&[T]`. +/// Succeeds if `slice.len() == N`. /// /// ``` /// let bytes: [u8; 3] = [1, 0, 2]; @@ -282,13 +282,7 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { #[inline] fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> { - if slice.len() == N { - let ptr = slice.as_ptr() as *const [T; N]; - // SAFETY: ok because we just checked that the length fits - unsafe { Ok(&*ptr) } - } else { - Err(TryFromSliceError(())) - } + slice.as_array().ok_or(TryFromSliceError(())) } } @@ -310,13 +304,7 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { #[inline] fn try_from(slice: &'a mut [T]) -> Result<&'a mut [T; N], TryFromSliceError> { - if slice.len() == N { - let ptr = slice.as_mut_ptr() as *mut [T; N]; - // SAFETY: ok because we just checked that the length fits - unsafe { Ok(&mut *ptr) } - } else { - Err(TryFromSliceError(())) - } + slice.as_mut_array().ok_or(TryFromSliceError(())) } } diff --git a/core/src/lib.rs b/core/src/lib.rs index a178d10125477..1089d415eca94 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -144,6 +144,7 @@ #![feature(ptr_alignment_type)] #![feature(ptr_metadata)] #![feature(set_ptr_value)] +#![feature(slice_as_array)] #![feature(slice_as_chunks)] #![feature(slice_ptr_get)] #![feature(str_internals)] diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 0dbe819acb1b9..27516789f867c 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -1526,6 +1526,22 @@ impl *const [T] { self as *const T } + /// Gets a raw pointer to the underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub const fn as_array(self) -> Option<*const [T; N]> { + if self.len() == N { + let me = self.as_ptr() as *const [T; N]; + Some(me) + } else { + None + } + } + /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index f0204bd0f773d..e637edd745918 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -1760,6 +1760,22 @@ impl *mut [T] { self.len() == 0 } + /// Gets a raw, mutable pointer to the underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub const fn as_mut_array(self) -> Option<*mut [T; N]> { + if self.len() == N { + let me = self.as_mut_ptr() as *mut [T; N]; + Some(me) + } else { + None + } + } + /// Divides one mutable raw slice into two at an index. /// /// The first will contain all indices from `[0, mid)` (excluding diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index b3defba5a9823..ee91479bb1a9d 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -855,6 +855,44 @@ impl [T] { start..end } + /// Gets a reference to the underlying array. + /// + /// If `N` is not exactly equal to slice's the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub const fn as_array(&self) -> Option<&[T; N]> { + if self.len() == N { + let ptr = self.as_ptr() as *const [T; N]; + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &*ptr }; + Some(me) + } else { + None + } + } + + /// Gets a mutable reference to the slice's underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { + if self.len() == N { + let ptr = self.as_mut_ptr() as *mut [T; N]; + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &mut *ptr }; + Some(me) + } else { + None + } + } + /// Swaps two elements in the slice. /// /// If `a` equals to `b`, it's guaranteed that elements won't change value. From 528ac03a3b1d71f4efe31ad9971d84207edbd15a Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Fri, 22 Nov 2024 17:47:15 -0500 Subject: [PATCH 018/481] aix: create shim for lgammaf_r --- std/src/sys/cmath.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/std/src/sys/cmath.rs b/std/src/sys/cmath.rs index 2997e908fa1b2..829042381a24c 100644 --- a/std/src/sys/cmath.rs +++ b/std/src/sys/cmath.rs @@ -26,6 +26,7 @@ extern "C" { pub fn tgamma(n: f64) -> f64; pub fn tgammaf(n: f32) -> f32; pub fn lgamma_r(n: f64, s: &mut i32) -> f64; + #[cfg(not(target_os = "aix"))] pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; pub fn acosf128(n: f128) -> f128; @@ -56,13 +57,20 @@ extern "C" { }} } +// On AIX, we don't have lgammaf_r only the f64 version, so we can +// use the f64 version lgamma_r +#[cfg(target_os = "aix")] +pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { + lgamma_r(n.into(), s) as f32 +} + // On 32-bit x86 MSVC these functions aren't defined, so we just define shims // which promote everything to f64, perform the calculation, and then demote // back to f32. While not precisely correct should be "correct enough" for now. cfg_if::cfg_if! { if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] { #[inline] - pub unsafe fn acosf(n: f32) -> f32 { + pub unsafe fn acosf(n: f32) -> f32 { f64::acos(n as f64) as f32 } From 8f15140568856e930876137e077a4635df4e6771 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Wed, 27 Nov 2024 12:02:02 -0500 Subject: [PATCH 019/481] fmt --- std/src/sys/cmath.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sys/cmath.rs b/std/src/sys/cmath.rs index 829042381a24c..ee36127cfdf1e 100644 --- a/std/src/sys/cmath.rs +++ b/std/src/sys/cmath.rs @@ -70,7 +70,7 @@ pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { cfg_if::cfg_if! { if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] { #[inline] - pub unsafe fn acosf(n: f32) -> f32 { + pub unsafe fn acosf(n: f32) -> f32 { f64::acos(n as f64) as f32 } From 5a25d49993e0160aaadb963b59ecb353cf1c9aba Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 23 Nov 2024 13:19:17 -0500 Subject: [PATCH 020/481] Share inline(never) generics across crates This reduces code sizes and better respects programmer intent when marking inline(never). Previously such a marking was essentially ignored for generic functions, as we'd still inline them in remote crates. --- alloc/src/raw_vec.rs | 4 +++- std/src/lib.rs | 1 + std/src/panicking.rs | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/alloc/src/raw_vec.rs b/alloc/src/raw_vec.rs index 85a9120c7e255..51b2a0570d909 100644 --- a/alloc/src/raw_vec.rs +++ b/alloc/src/raw_vec.rs @@ -757,7 +757,9 @@ impl RawVecInner { } } -#[inline(never)] +// not marked inline(never) since we want optimizers to be able to observe the specifics of this +// function, see tests/codegen/vec-reserve-extend.rs. +#[cold] fn finish_grow( new_layout: Layout, current_memory: Option<(NonNull, Layout)>, diff --git a/std/src/lib.rs b/std/src/lib.rs index cf99a618e5520..314d9203ca10f 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -362,6 +362,7 @@ #![feature(strict_provenance_atomic_ptr)] #![feature(sync_unsafe_cell)] #![feature(ub_checks)] +#![feature(used_with_arg)] // tidy-alphabetical-end // // Library features (alloc): diff --git a/std/src/panicking.rs b/std/src/panicking.rs index ac1f547c9143f..97f800dddaa43 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -27,6 +27,22 @@ use crate::sys::backtrace; use crate::sys::stdio::panic_output; use crate::{fmt, intrinsics, process, thread}; +// This forces codegen of the function called by panic!() inside the std crate, rather than in +// downstream crates. Primarily this is useful for rustc's codegen tests, which rely on noticing +// complete removal of panic from generated IR. Since begin_panic is inline(never), it's only +// codegen'd once per crate-graph so this pushes that to std rather than our codegen test crates. +// +// (See https://github.com/rust-lang/rust/pull/123244 for more info on why). +// +// If this is causing problems we can also modify those codegen tests to use a crate type like +// cdylib which doesn't export "Rust" symbols to downstream linkage units. +#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] +#[doc(hidden)] +#[allow(dead_code)] +#[used(compiler)] +pub static EMPTY_PANIC: fn(&'static str) -> ! = + begin_panic::<&'static str> as fn(&'static str) -> !; + // Binary interface to the panic runtime that the standard library depends on. // // The standard library is tagged with `#![needs_panic_runtime]` (introduced in From 50245a5c0be912a18c9d61355bdd4be04c18abe5 Mon Sep 17 00:00:00 2001 From: Aakarshit Uppal <26065812+aksh1618@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:37:30 +0000 Subject: [PATCH 021/481] Fix typos in pin.rs --- core/src/pin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/pin.rs b/core/src/pin.rs index c14c49a0d92f9..43cebf4881eb5 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -373,9 +373,9 @@ //! exactly what we did with our `AddrTracker` example above. Without doing this, you *must not* //! rely on pinning-related guarantees to apply to your type! //! -//! If need to truly pin a value of a foreign or built-in type that implements [`Unpin`], you'll -//! need to create your own wrapper type around the [`Unpin`] type you want to pin and then -//! opts-out of [`Unpin`] using [`PhantomPinned`]. +//! If you really need to pin a value of a foreign or built-in type that implements [`Unpin`], +//! you'll need to create your own wrapper type around the [`Unpin`] type you want to pin and then +//! opt-out of [`Unpin`] using [`PhantomPinned`]. //! //! Exposing access to the inner field which you want to remain pinned must then be carefully //! considered as well! Remember, exposing a method that gives access to a From 12e62c1c05eba50ecfaaade59ebf10e59df92a36 Mon Sep 17 00:00:00 2001 From: timvisee Date: Thu, 28 Nov 2024 09:39:33 +0100 Subject: [PATCH 022/481] Use consistent wording in docs, use zero instead of 0 --- core/src/num/int_macros.rs | 26 +++++++++++++------------- core/src/num/uint_macros.rs | 22 +++++++++++----------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 64dcb4c91e628..6c50f21a773bc 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -1828,7 +1828,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -1986,7 +1986,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2014,7 +2014,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2042,7 +2042,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2069,7 +2069,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2526,7 +2526,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2557,7 +2557,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2588,7 +2588,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2619,7 +2619,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2887,7 +2887,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or if `self` is `Self::MIN` + /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` /// and `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -2926,7 +2926,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or if `self` is `Self::MIN` and + /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` and /// `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -2975,7 +2975,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or if `self` is `Self::MIN` + /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` /// and `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -3019,7 +3019,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or if `self` is `Self::MIN` + /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` /// and `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 0383c13fa082d..23aace0cd6667 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -1877,7 +1877,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2034,7 +2034,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2063,7 +2063,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2091,7 +2091,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2121,7 +2121,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2545,7 +2545,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2576,7 +2576,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2604,7 +2604,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2635,7 +2635,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2872,7 +2872,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2900,7 +2900,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// From 5517aca3390c76db8764e62fced550b62211882d Mon Sep 17 00:00:00 2001 From: timvisee Date: Thu, 28 Nov 2024 09:46:26 +0100 Subject: [PATCH 023/481] Also use zero when referencing to capacity or length --- alloc/src/collections/binary_heap/mod.rs | 4 +-- alloc/src/vec/mod.rs | 8 +++--- core/src/iter/traits/iterator.rs | 4 +-- core/src/slice/mod.rs | 32 ++++++++++++------------ std/src/collections/hash/map.rs | 4 +-- std/src/collections/hash/set.rs | 4 +-- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 59f10b09c73fd..0bc65cdbc55a3 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -452,7 +452,7 @@ impl BinaryHeap { /// /// The binary heap will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the binary heap will not allocate. + /// `capacity`. If `capacity` is zero, the binary heap will not allocate. /// /// # Examples /// @@ -496,7 +496,7 @@ impl BinaryHeap { /// /// The binary heap will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the binary heap will not allocate. + /// `capacity`. If `capacity` is zero, the binary heap will not allocate. /// /// # Examples /// diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 990b7e8f76127..87e730b13f8b9 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -427,7 +427,7 @@ impl Vec { /// /// The vector will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// `capacity`. If `capacity` is zero, the vector will not allocate. /// /// It is important to note that although the returned vector has the /// minimum *capacity* specified, the vector will have a zero *length*. For @@ -487,7 +487,7 @@ impl Vec { /// /// The vector will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// `capacity`. If `capacity` is zero, the vector will not allocate. /// /// # Errors /// @@ -745,7 +745,7 @@ impl Vec { /// /// The vector will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// `capacity`. If `capacity` is zero, the vector will not allocate. /// /// It is important to note that although the returned vector has the /// minimum *capacity* specified, the vector will have a zero *length*. For @@ -808,7 +808,7 @@ impl Vec { /// /// The vector will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// `capacity`. If `capacity` is zero, the vector will not allocate. /// /// # Errors /// diff --git a/core/src/iter/traits/iterator.rs b/core/src/iter/traits/iterator.rs index ffaf1bc56e942..38dfbbef39323 100644 --- a/core/src/iter/traits/iterator.rs +++ b/core/src/iter/traits/iterator.rs @@ -1553,7 +1553,7 @@ pub trait Iterator { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a + /// Panics if `N` is zero. This check will most probably get changed to a /// compile time error before this method gets stabilized. /// /// ```should_panic @@ -3454,7 +3454,7 @@ pub trait Iterator { /// /// # Panics /// - /// Panics if `N` is 0. + /// Panics if `N` is zero. /// /// # Examples /// diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index ee91479bb1a9d..7afdb680df65b 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -1077,7 +1077,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `size` is 0. + /// Panics if `size` is zero. /// /// # Examples /// @@ -1133,7 +1133,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1168,7 +1168,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1210,7 +1210,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1249,7 +1249,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1326,7 +1326,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1372,7 +1372,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1410,7 +1410,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1486,7 +1486,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1527,7 +1527,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1571,7 +1571,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1606,7 +1606,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// Panics if `N` is zero. This check will most probably get changed to a compile time /// error before this method gets stabilized. /// /// # Examples @@ -1642,7 +1642,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1677,7 +1677,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1720,7 +1720,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// @@ -1760,7 +1760,7 @@ impl [T] { /// /// # Panics /// - /// Panics if `chunk_size` is 0. + /// Panics if `chunk_size` is zero. /// /// # Examples /// diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 24bbc2f32cf6d..09c0b61fb2b89 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -235,7 +235,7 @@ impl HashMap { /// /// The hash map will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the hash map will not allocate. + /// `capacity`. If `capacity` is zero, the hash map will not allocate. /// /// # Examples /// @@ -287,7 +287,7 @@ impl HashMap { /// /// The hash map will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the hash map will not allocate. + /// `capacity`. If `capacity` is zero, the hash map will not allocate. /// /// Warning: `hasher` is normally randomly generated, and /// is designed to allow HashMaps to be resistant to attacks that diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index f86bcdb4796ec..21a73259f6179 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -130,7 +130,7 @@ impl HashSet { /// /// The hash set will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the hash set will not allocate. + /// `capacity`. If `capacity` is zero, the hash set will not allocate. /// /// # Examples /// @@ -379,7 +379,7 @@ impl HashSet { /// /// The hash set will be able to hold at least `capacity` elements without /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is 0, the hash set will not allocate. + /// `capacity`. If `capacity` is zero, the hash set will not allocate. /// /// Warning: `hasher` is normally randomly generated, and /// is designed to allow `HashSet`s to be resistant to attacks that From f5d6e66daf98fb88a8b06500131256b3adfffc79 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 25 Nov 2024 11:46:46 +0000 Subject: [PATCH 024/481] replace placeholder version --- alloc/src/boxed/convert.rs | 4 ++-- alloc/src/ffi/c_str.rs | 6 +++--- alloc/src/rc.rs | 4 ++-- alloc/src/sync.rs | 4 ++-- core/src/cell.rs | 4 ++-- core/src/char/methods.rs | 8 ++++---- core/src/fmt/mod.rs | 2 +- core/src/intrinsics/mod.rs | 6 +++--- core/src/mem/maybe_uninit.rs | 2 +- core/src/net/ip_addr.rs | 8 ++++---- core/src/num/int_macros.rs | 8 ++++---- core/src/num/mod.rs | 4 ++-- core/src/num/nonzero.rs | 8 ++++---- core/src/num/uint_macros.rs | 4 ++-- core/src/option.rs | 8 ++++---- core/src/panic.rs | 2 +- core/src/panic/panic_info.rs | 2 +- core/src/pin.rs | 22 +++++++++++----------- core/src/ptr/const_ptr.rs | 12 ++++++------ core/src/ptr/mod.rs | 20 ++++++++++---------- core/src/ptr/mut_ptr.rs | 14 +++++++------- core/src/ptr/non_null.rs | 6 +++--- core/src/slice/ascii.rs | 4 ++-- core/src/str/mod.rs | 4 ++-- core/src/sync/atomic.rs | 6 +++--- std/src/ffi/os_str.rs | 6 +++--- std/src/os/darwin/mod.rs | 2 +- std/src/path.rs | 6 +++--- 28 files changed, 93 insertions(+), 93 deletions(-) diff --git a/alloc/src/boxed/convert.rs b/alloc/src/boxed/convert.rs index 4430fff66775c..255cefb1e78fb 100644 --- a/alloc/src/boxed/convert.rs +++ b/alloc/src/boxed/convert.rs @@ -110,7 +110,7 @@ impl From<&[T]> for Box<[T]> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut [T]> for Box<[T]> { /// Converts a `&mut [T]` into a `Box<[T]>` /// @@ -171,7 +171,7 @@ impl From<&str> for Box { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut str> for Box { /// Converts a `&mut str` into a `Box` /// diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index d91682b796e4f..c739832bc7843 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -773,7 +773,7 @@ impl From<&CStr> for Box { } #[cfg(not(test))] -#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Box { /// Converts a `&mut CStr` into a `Box`, /// by copying the contents into a newly allocated [`Box`]. @@ -921,7 +921,7 @@ impl From<&CStr> for Arc { } #[cfg(target_has_atomic = "ptr")] -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Arc { /// Converts a `&mut CStr` into a `Arc`, /// by copying the contents into a newly allocated [`Arc`]. @@ -953,7 +953,7 @@ impl From<&CStr> for Rc { } } -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Rc { /// Converts a `&mut CStr` into a `Rc`, /// by copying the contents into a newly allocated [`Rc`]. diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 3a9bd1b5bf119..48ffdcb77d319 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -2659,7 +2659,7 @@ impl From<&[T]> for Rc<[T]> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut [T]> for Rc<[T]> { /// Allocates a reference-counted slice and fills it by cloning `v`'s items. /// @@ -2698,7 +2698,7 @@ impl From<&str> for Rc { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut str> for Rc { /// Allocates a reference-counted string slice and copies `v` into it. /// diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index da2d6bb3bce24..f7d1c9e4efb4d 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -3618,7 +3618,7 @@ impl From<&[T]> for Arc<[T]> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut [T]> for Arc<[T]> { /// Allocates a reference-counted slice and fills it by cloning `v`'s items. /// @@ -3657,7 +3657,7 @@ impl From<&str> for Arc { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut str> for Arc { /// Allocates a reference-counted `str` and copies `v` into it. /// diff --git a/core/src/cell.rs b/core/src/cell.rs index bfd2a71f97b2c..d62cb28fc5729 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -2133,8 +2133,8 @@ impl UnsafeCell { /// assert_eq!(*uc.get_mut(), 41); /// ``` #[inline(always)] - #[stable(feature = "unsafe_cell_from_mut", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unsafe_cell_from_mut", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsafe_cell_from_mut", since = "1.84.0")] + #[rustc_const_stable(feature = "unsafe_cell_from_mut", since = "1.84.0")] #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn from_mut(value: &mut T) -> &mut UnsafeCell { // SAFETY: `UnsafeCell` has the same memory layout as `T` due to #[repr(transparent)]. diff --git a/core/src/char/methods.rs b/core/src/char/methods.rs index 974e7baccf7bc..86822af31ca26 100644 --- a/core/src/char/methods.rs +++ b/core/src/char/methods.rs @@ -729,7 +729,7 @@ impl char { /// '𝕊'.encode_utf16(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[rustc_const_stable(feature = "const_char_encode_utf16", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_char_encode_utf16", since = "1.84.0")] #[inline] pub const fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { encode_utf16_raw(self as u32, dst) @@ -1299,7 +1299,7 @@ impl char { /// /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); @@ -1325,7 +1325,7 @@ impl char { /// /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); @@ -1838,7 +1838,7 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] #[cfg_attr( bootstrap, - rustc_const_stable(feature = "const_char_encode_utf16", since = "CURRENT_RUSTC_VERSION") + rustc_const_stable(feature = "const_char_encode_utf16", since = "1.84.0") )] #[doc(hidden)] #[inline] diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 2b1692a195e50..9db6d27967ff7 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -438,7 +438,7 @@ impl<'a> Arguments<'a> { /// assert_eq!(format_args!("{:?}", std::env::current_dir()).as_str(), None); /// ``` #[stable(feature = "fmt_as_str", since = "1.52.0")] - #[rustc_const_stable(feature = "const_arguments_as_str", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_arguments_as_str", since = "1.84.0")] #[must_use] #[inline] pub const fn as_str(&self) -> Option<&'static str> { diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 2f75bfae988f2..8741e1b080754 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1494,7 +1494,7 @@ pub const fn cold_path() {} /// This intrinsic does not have a stable counterpart. #[cfg_attr( bootstrap, - rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") + rustc_const_stable(feature = "const_likely", since = "1.84.0") )] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_nounwind] @@ -1526,7 +1526,7 @@ pub const fn likely(b: bool) -> bool { /// This intrinsic does not have a stable counterpart. #[cfg_attr( bootstrap, - rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") + rustc_const_stable(feature = "const_likely", since = "1.84.0") )] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_nounwind] @@ -3629,7 +3629,7 @@ pub(crate) macro const_eval_select { /// ``` #[cfg_attr( bootstrap, - rustc_const_stable(feature = "const_is_val_statically_known", since = "CURRENT_RUSTC_VERSION") + rustc_const_stable(feature = "const_is_val_statically_known", since = "1.84.0") )] #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 27273e4eedf3a..476a8f823cb6f 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -913,7 +913,7 @@ impl MaybeUninit { #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] #[rustc_const_stable( feature = "const_maybe_uninit_assume_init", - since = "CURRENT_RUSTC_VERSION" + since = "1.84.0" )] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut T { diff --git a/core/src/net/ip_addr.rs b/core/src/net/ip_addr.rs index 6746f0b2b316b..82f11f0eaac3c 100644 --- a/core/src/net/ip_addr.rs +++ b/core/src/net/ip_addr.rs @@ -1601,8 +1601,8 @@ impl Ipv6Addr { /// ``` #[must_use] #[inline] - #[stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ipv6_is_unique_local", since = "1.84.0")] + #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "1.84.0")] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1679,8 +1679,8 @@ impl Ipv6Addr { /// ``` #[must_use] #[inline] - #[stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ipv6_is_unique_local", since = "1.84.0")] + #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "1.84.0")] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 6c50f21a773bc..3d55313b56c86 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -1613,8 +1613,8 @@ macro_rules! int_impl { /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")] /// ``` - #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "isqrt", since = "1.84.0")] + #[rustc_const_stable(feature = "isqrt", since = "1.84.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2860,8 +2860,8 @@ macro_rules! int_impl { /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` - #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "isqrt", since = "1.84.0")] + #[rustc_const_stable(feature = "isqrt", since = "1.84.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 9d9897b9cf05e..4278fec9f58c2 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -677,7 +677,7 @@ impl u8 { /// /// [`to_ascii_uppercase`]: Self::to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); @@ -703,7 +703,7 @@ impl u8 { /// /// [`to_ascii_lowercase`]: Self::to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index b883a0c2ec7f9..dba64d5dc8e34 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -139,9 +139,9 @@ impl_nonzero_fmt! { LowerHex #[stable(feature = "nonzero", since = "1.28.0")] UpperHex - #[stable(feature = "nonzero_fmt_exp", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_fmt_exp", since = "1.84.0")] LowerExp - #[stable(feature = "nonzero_fmt_exp", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_fmt_exp", since = "1.84.0")] UpperExp } @@ -1587,8 +1587,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "isqrt", since = "1.84.0")] + #[rustc_const_stable(feature = "isqrt", since = "1.84.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 23aace0cd6667..ed3f02788e622 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -2838,8 +2838,8 @@ macro_rules! uint_impl { /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` - #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "isqrt", since = "1.84.0")] + #[rustc_const_stable(feature = "isqrt", since = "1.84.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/option.rs b/core/src/option.rs index 29d1956af9559..a12fb6a827e73 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -738,7 +738,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "pin", since = "1.33.0")] - #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_option_ext", since = "1.84.0")] pub const fn as_pin_ref(self: Pin<&Self>) -> Option> { // FIXME(const-hack): use `map` once that is possible match Pin::get_ref(self).as_ref() { @@ -755,7 +755,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "pin", since = "1.33.0")] - #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_option_ext", since = "1.84.0")] pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option> { // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`. // `x` is guaranteed to be pinned because it comes from `self` which is pinned. @@ -802,7 +802,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "option_as_slice", since = "1.75.0")] - #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_option_ext", since = "1.84.0")] pub const fn as_slice(&self) -> &[T] { // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to @@ -857,7 +857,7 @@ impl Option { #[inline] #[must_use] #[stable(feature = "option_as_slice", since = "1.75.0")] - #[rustc_const_stable(feature = "const_option_ext", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_option_ext", since = "1.84.0")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to diff --git a/core/src/panic.rs b/core/src/panic.rs index 179aadf0c286c..1e61cfd804c26 100644 --- a/core/src/panic.rs +++ b/core/src/panic.rs @@ -208,7 +208,7 @@ pub macro const_panic { #[rustc_allow_const_fn_unstable(const_eval_select)] #[inline(always)] // inline the wrapper #[track_caller] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_panic", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_panic", since = "1.84.0"))] const fn do_panic($($arg: $ty),*) -> ! { $crate::intrinsics::const_eval_select!( @capture { $($arg: $ty = $arg),* } -> !: diff --git a/core/src/panic/panic_info.rs b/core/src/panic/panic_info.rs index 230a9918dbf3e..9d53567a26fd9 100644 --- a/core/src/panic/panic_info.rs +++ b/core/src/panic/panic_info.rs @@ -165,7 +165,7 @@ impl<'a> PanicMessage<'a> { /// /// See [`fmt::Arguments::as_str`] for details. #[stable(feature = "panic_info_message", since = "1.81.0")] - #[rustc_const_stable(feature = "const_arguments_as_str", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_arguments_as_str", since = "1.84.0")] #[must_use] #[inline] pub const fn as_str(&self) -> Option<&'static str> { diff --git a/core/src/pin.rs b/core/src/pin.rs index 43cebf4881eb5..f18a45083ff7e 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -1186,7 +1186,7 @@ impl> Pin { /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val); /// ``` #[inline(always)] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const fn new(pointer: Ptr) -> Pin { // SAFETY: the value pointed to is `Unpin`, and so has no requirements @@ -1215,7 +1215,7 @@ impl> Pin { /// ``` #[inline(always)] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin) -> Ptr { pin.__pointer @@ -1352,7 +1352,7 @@ impl Pin { /// [`pin` module docs]: self #[lang = "new_unchecked"] #[inline(always)] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin { Pin { __pointer: pointer } @@ -1423,7 +1423,7 @@ impl Pin { /// move in the future, and this method does not enable the pointee to move. "Malicious" /// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of /// `Pin::new_unchecked`. - #[stable(feature = "pin_deref_mut", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "pin_deref_mut", since = "1.84.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline(always)] pub fn as_deref_mut(self: Pin<&mut Pin>) -> Pin<&mut Ptr::Target> { @@ -1505,7 +1505,7 @@ impl Pin { /// instead. #[inline(always)] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { pin.__pointer @@ -1561,7 +1561,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// ["pinning projections"]: self#projections-and-structural-pinning #[inline(always)] #[must_use] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const fn get_ref(self) -> &'a T { self.__pointer @@ -1572,7 +1572,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[inline(always)] #[must_use = "`self` will be dropped if the result is not used"] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] #[stable(feature = "pin", since = "1.33.0")] pub const fn into_ref(self) -> Pin<&'a T> { Pin { __pointer: self.__pointer } @@ -1590,7 +1590,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[inline(always)] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "pin", since = "1.33.0")] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] pub const fn get_mut(self) -> &'a mut T where T: Unpin, @@ -1611,7 +1611,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[inline(always)] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "pin", since = "1.33.0")] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { self.__pointer } @@ -1654,7 +1654,7 @@ impl Pin<&'static T> { /// This is safe because `T` is borrowed immutably for the `'static` lifetime, which /// never ends. #[stable(feature = "pin_static_ref", since = "1.61.0")] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] pub const fn static_ref(r: &'static T) -> Pin<&'static T> { // SAFETY: The 'static borrow guarantees the data will not be // moved/invalidated until it gets dropped (which is never). @@ -1668,7 +1668,7 @@ impl Pin<&'static mut T> { /// This is safe because `T` is borrowed for the `'static` lifetime, which /// never ends. #[stable(feature = "pin_static_ref", since = "1.61.0")] - #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pin", since = "1.84.0")] pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T> { // SAFETY: The 'static borrow guarantees the data will not be // moved/invalidated until it gets dropped (which is never). diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 27516789f867c..acb2f0d6d76d4 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -29,7 +29,7 @@ impl *const T { /// assert!(!ptr.is_null()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[rustc_diagnostic_item = "ptr_const_is_null"] #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] @@ -159,7 +159,7 @@ impl *const T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline(always)] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> usize { // A pointer-to-integer transmute currently has exactly the right semantics: it returns the // address without exposing the provenance. Note that this is *not* a stable guarantee about @@ -193,7 +193,7 @@ impl *const T { /// [`with_exposed_provenance`]: with_exposed_provenance #[must_use] #[inline(always)] - #[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "exposed_provenance", since = "1.84.0")] pub fn expose_provenance(self) -> usize { self.cast::<()>() as usize } @@ -211,7 +211,7 @@ impl *const T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn with_addr(self, addr: usize) -> Self { // This should probably be an intrinsic to avoid doing any sort of arithmetic, but // meanwhile, we can implement it with `wrapping_offset`, which preserves the pointer's @@ -230,7 +230,7 @@ impl *const T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self { self.with_addr(f(self.addr())) } @@ -282,7 +282,7 @@ impl *const T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 805edddfe6312..6147e9f5e6190 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -591,8 +591,8 @@ pub const fn null_mut() -> *mut T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] -#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] -#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "strict_provenance", since = "1.84.0")] +#[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn without_provenance(addr: usize) -> *const T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute @@ -613,8 +613,8 @@ pub const fn without_provenance(addr: usize) -> *const T { /// some other means. #[inline(always)] #[must_use] -#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] -#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "strict_provenance", since = "1.84.0")] +#[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn dangling() -> *const T { without_provenance(mem::align_of::()) } @@ -634,8 +634,8 @@ pub const fn dangling() -> *const T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] -#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] -#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "strict_provenance", since = "1.84.0")] +#[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn without_provenance_mut(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute @@ -656,8 +656,8 @@ pub const fn without_provenance_mut(addr: usize) -> *mut T { /// some other means. #[inline(always)] #[must_use] -#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] -#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "strict_provenance", since = "1.84.0")] +#[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn dangling_mut() -> *mut T { without_provenance_mut(mem::align_of::()) } @@ -695,7 +695,7 @@ pub const fn dangling_mut() -> *mut T { /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[must_use] #[inline(always)] -#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "exposed_provenance", since = "1.84.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead pub fn with_exposed_provenance(addr: usize) -> *const T { @@ -735,7 +735,7 @@ pub fn with_exposed_provenance(addr: usize) -> *const T { /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[must_use] #[inline(always)] -#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "exposed_provenance", since = "1.84.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead pub fn with_exposed_provenance_mut(addr: usize) -> *mut T { diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index e637edd745918..115aa9d8be7e4 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -29,7 +29,7 @@ impl *mut T { /// assert!(!ptr.is_null()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[rustc_diagnostic_item = "ptr_is_null"] #[inline] pub const fn is_null(self) -> bool { @@ -146,7 +146,7 @@ impl *mut T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline(always)] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> usize { // A pointer-to-integer transmute currently has exactly the right semantics: it returns the // address without exposing the provenance. Note that this is *not* a stable guarantee about @@ -179,7 +179,7 @@ impl *mut T { /// /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut #[inline(always)] - #[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "exposed_provenance", since = "1.84.0")] pub fn expose_provenance(self) -> usize { self.cast::<()>() as usize } @@ -197,7 +197,7 @@ impl *mut T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn with_addr(self, addr: usize) -> Self { // This should probably be an intrinsic to avoid doing any sort of arithmetic, but // meanwhile, we can implement it with `wrapping_offset`, which preserves the pointer's @@ -216,7 +216,7 @@ impl *mut T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self { self.with_addr(f(self.addr())) } @@ -271,7 +271,7 @@ impl *mut T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid for a @@ -619,7 +619,7 @@ impl *mut T { /// println!("{s:?}"); // It'll print: "[4, 2, 3]". /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[inline] pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { // SAFETY: the caller must guarantee that `self` is be valid for diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index b69f8a4b9d3ea..0fb5880fd1a0e 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -278,7 +278,7 @@ impl NonNull { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> NonZero { // SAFETY: The pointer is guaranteed by the type to be non-null, // meaning that the address will be non-zero. @@ -293,7 +293,7 @@ impl NonNull { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn with_addr(self, addr: NonZero) -> Self { // SAFETY: The result of `ptr::from::with_addr` is non-null because `addr` is guaranteed to be non-zero. unsafe { NonNull::new_unchecked(self.pointer.with_addr(addr.get()) as *mut _) } @@ -307,7 +307,7 @@ impl NonNull { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn map_addr(self, f: impl FnOnce(NonZero) -> NonZero) -> Self { self.with_addr(f(self.addr())) } diff --git a/core/src/slice/ascii.rs b/core/src/slice/ascii.rs index 17ad4fd8f677f..7cdb896586f13 100644 --- a/core/src/slice/ascii.rs +++ b/core/src/slice/ascii.rs @@ -88,7 +88,7 @@ impl [u8] { /// /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_uppercase(&mut self) { // FIXME(const-hack): We would like to simply iterate using `for` loops but this isn't currently allowed in constant expressions. @@ -110,7 +110,7 @@ impl [u8] { /// /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_lowercase(&mut self) { // FIXME(const-hack): We would like to simply iterate using `for` loops but this isn't currently allowed in constant expressions. diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 4629b770cb46d..189ab39e976f5 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -2503,7 +2503,7 @@ impl str { /// assert_eq!("GRüßE, JüRGEN ❤", s); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_uppercase(&mut self) { // SAFETY: changing ASCII letters only does not invalidate UTF-8. @@ -2531,7 +2531,7 @@ impl str { /// assert_eq!("grÜße, jÜrgen ❤", s); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_make_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_make_ascii", since = "1.84.0")] #[inline] pub const fn make_ascii_lowercase(&mut self) { // SAFETY: changing ASCII letters only does not invalidate UTF-8. diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 7f2a5424787f7..487fffba881b3 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -469,7 +469,7 @@ impl AtomicBool { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -1264,7 +1264,7 @@ impl AtomicPtr { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -2263,7 +2263,7 @@ macro_rules! atomic_int { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 328185d1f2b0c..fff140f1564fa 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -1229,7 +1229,7 @@ impl From<&OsStr> for Box { } } -#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut OsStr> for Box { /// Copies the string into a newly allocated [Box]<[OsStr]>. #[inline] @@ -1309,7 +1309,7 @@ impl From<&OsStr> for Arc { } } -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut OsStr> for Arc { /// Copies the string into a newly allocated [Arc]<[OsStr]>. #[inline] @@ -1339,7 +1339,7 @@ impl From<&OsStr> for Rc { } } -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut OsStr> for Rc { /// Copies the string into a newly allocated [Rc]<[OsStr]>. #[inline] diff --git a/std/src/os/darwin/mod.rs b/std/src/os/darwin/mod.rs index 7a057ddb861b7..3b1bd974fa313 100644 --- a/std/src/os/darwin/mod.rs +++ b/std/src/os/darwin/mod.rs @@ -13,7 +13,7 @@ //! `aarch64-apple-darwin` target names, which are mostly named that way for //! legacy reasons. -#![stable(feature = "os_darwin", since = "CURRENT_RUSTC_VERSION")] +#![stable(feature = "os_darwin", since = "1.84.0")] #![doc(cfg(target_vendor = "apple"))] pub mod fs; diff --git a/std/src/path.rs b/std/src/path.rs index 33a3e4332f377..635c7bca0e010 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -1762,7 +1762,7 @@ impl From<&Path> for Box { } } -#[stable(feature = "box_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut Path> for Box { /// Creates a boxed [`Path`] from a reference. /// @@ -2000,7 +2000,7 @@ impl From<&Path> for Arc { } } -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut Path> for Arc { /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer. #[inline] @@ -2030,7 +2030,7 @@ impl From<&Path> for Rc { } } -#[stable(feature = "shared_from_mut_slice", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] impl From<&mut Path> for Rc { /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer. #[inline] From b8f491d1fc98e90b3dc71d99e02ec4354dc47714 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 27 Nov 2024 15:14:47 +0000 Subject: [PATCH 025/481] update cfgs --- alloc/benches/lib.rs | 3 +- alloc/src/boxed.rs | 11 +- alloc/src/lib.rs | 3 +- alloc/src/raw_vec.rs | 3 - alloc/src/rc.rs | 2 +- alloc/src/sync.rs | 2 +- alloc/src/vec/mod.rs | 4 +- alloc/tests/boxed.rs | 2 +- alloc/tests/lib.rs | 3 +- core/Cargo.toml | 2 - core/src/alloc/layout.rs | 9 +- core/src/cell.rs | 9 +- core/src/char/methods.rs | 5 - core/src/ffi/c_str.rs | 8 +- core/src/fmt/mod.rs | 4 - core/src/future/future.rs | 2 +- core/src/hint.rs | 1 - core/src/intrinsics/mod.rs | 246 ++++++------------------- core/src/lib.rs | 7 +- core/src/macros/mod.rs | 1 - core/src/mem/maybe_uninit.rs | 9 +- core/src/num/int_macros.rs | 7 - core/src/num/mod.rs | 1 - core/src/num/uint_macros.rs | 7 - core/src/ops/deref.rs | 6 +- core/src/ops/mod.rs | 1 - core/src/option.rs | 2 +- core/src/panic.rs | 3 +- core/src/panicking.rs | 27 +-- core/src/ptr/alignment.rs | 7 - core/src/ptr/const_ptr.rs | 2 - core/src/ptr/metadata.rs | 3 - core/src/ptr/mut_ptr.rs | 2 - core/src/ptr/non_null.rs | 1 - core/src/result.rs | 2 +- core/src/slice/memchr.rs | 4 - core/src/slice/mod.rs | 4 +- core/src/str/mod.rs | 4 +- core/src/task/wake.rs | 2 - core/src/ub_checks.rs | 2 - core/src/unicode/unicode_data.rs | 3 - core/tests/lib.rs | 4 +- panic_unwind/Cargo.toml | 5 +- std/Cargo.toml | 2 - std/src/lib.rs | 6 +- std/src/sys/sync/condvar/no_threads.rs | 1 - std/src/sys/sync/mutex/no_threads.rs | 1 - std/src/sys/sync/once/no_threads.rs | 1 - std/src/sys/sync/once/queue.rs | 1 - std/src/sys/sync/rwlock/no_threads.rs | 1 - std/src/sys/thread_local/key/racy.rs | 1 - std/src/sys/thread_local/os.rs | 1 - std/src/thread/local.rs | 1 - unwind/Cargo.toml | 5 +- 54 files changed, 106 insertions(+), 350 deletions(-) diff --git a/alloc/benches/lib.rs b/alloc/benches/lib.rs index c1907361f93e1..2633154318c13 100644 --- a/alloc/benches/lib.rs +++ b/alloc/benches/lib.rs @@ -4,8 +4,7 @@ #![feature(iter_next_chunk)] #![feature(repr_simd)] #![feature(slice_partition_dedup)] -#![cfg_attr(bootstrap, feature(strict_provenance))] -#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] +#![feature(strict_provenance_lints)] #![feature(test)] #![deny(fuzzy_provenance_casts)] diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index ee60ec0fbacbe..e0f94428cfa65 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -191,9 +191,7 @@ use core::error::{self, Error}; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; -#[cfg(not(bootstrap))] -use core::marker::PointerLike; -use core::marker::{Tuple, Unsize}; +use core::marker::{PointerLike, Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, @@ -227,7 +225,7 @@ pub use thin::ThinBox; #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] // The declaration of the `Box` struct must be kept in sync with the // compiler or ICEs will happen. pub struct Box< @@ -1502,7 +1500,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1551,7 +1549,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline] pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -2134,6 +2132,5 @@ impl Error for Box { } } -#[cfg(not(bootstrap))] #[unstable(feature = "pointer_like_trait", issue = "none")] impl PointerLike for Box {} diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 041ff37897f05..108224b27fa80 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -163,8 +163,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(strict_provenance))] -#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![cfg_attr(not(test), feature(coroutine_trait))] #![cfg_attr(test, feature(panic_update_hook))] #![cfg_attr(test, feature(test))] @@ -188,6 +186,7 @@ #![feature(slice_internals)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] #![feature(with_negative_coherence)] diff --git a/alloc/src/raw_vec.rs b/alloc/src/raw_vec.rs index 51b2a0570d909..2c7cdcf0cfb4e 100644 --- a/alloc/src/raw_vec.rs +++ b/alloc/src/raw_vec.rs @@ -103,7 +103,6 @@ impl RawVec { /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. #[must_use] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] pub const fn new() -> Self { Self::new_in(Global) } @@ -179,7 +178,6 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] pub const fn new_in(alloc: A) -> Self { Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } } @@ -409,7 +407,6 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { impl RawVecInner { #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] const fn new_in(alloc: A, align: usize) -> Self { let ptr = unsafe { core::mem::transmute(align) }; // `cap: 0` means "unallocated". zero-sized types are ignored. diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 48ffdcb77d319..7aa1457b1df54 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -307,7 +307,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { /// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. /// /// [get_mut]: Rc::get_mut -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index f7d1c9e4efb4d..b8bdd298c27ab 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -235,7 +235,7 @@ macro_rules! acquire { /// counting in general. /// /// [rc_examples]: crate::rc#examples -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 87e730b13f8b9..4b706086e0770 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -1662,7 +1662,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline] pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1725,7 +1725,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/alloc/tests/boxed.rs b/alloc/tests/boxed.rs index 6a8ba5c92fb30..94389cf2de933 100644 --- a/alloc/tests/boxed.rs +++ b/alloc/tests/boxed.rs @@ -4,7 +4,7 @@ use core::mem::MaybeUninit; use core::ptr::NonNull; #[test] -#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))] +#[expect(dangling_pointers_from_temporaries)] fn uninitialized_zero_size_box() { assert_eq!( &*Box::<()>::new_uninit() as *const _, diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs index 699a8e6776e6d..02bbb40ef81d2 100644 --- a/alloc/tests/lib.rs +++ b/alloc/tests/lib.rs @@ -32,10 +32,9 @@ #![feature(panic_update_hook)] #![feature(pointer_is_aligned_to)] #![feature(thin_box)] -#![cfg_attr(bootstrap, feature(strict_provenance))] -#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![feature(drain_keep_rest)] #![feature(local_waker)] +#![feature(strict_provenance_lints)] #![feature(vec_pop_if)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] diff --git a/core/Cargo.toml b/core/Cargo.toml index 94f343d06705e..cace4582b489a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -43,8 +43,6 @@ check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', 'cfg(stdarch_intel_sde)', - # #[cfg(bootstrap)] rtems - 'cfg(target_os, values("rtems"))', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index f412ca1716338..60936da2e0b0d 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -157,7 +157,6 @@ impl Layout { #[must_use = "this returns the minimum alignment, \ without modifying the layout"] #[inline] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(ptr_alignment_type))] pub const fn align(&self) -> usize { self.align.as_usize() } @@ -255,7 +254,7 @@ impl Layout { /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_const_stable_indirect] #[inline] pub const fn align_to(&self, align: usize) -> Result { if let Some(align) = Alignment::new(align) { @@ -331,7 +330,7 @@ impl Layout { /// to the layout's current size. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_const_stable_indirect] #[must_use = "this returns a new `Layout`, \ without modifying the original"] #[inline] @@ -431,7 +430,7 @@ impl Layout { /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_const_stable_indirect] #[inline] pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = Alignment::max(self.align, next.align); @@ -495,7 +494,7 @@ impl Layout { /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_const_stable_indirect] #[inline] pub const fn array(n: usize) -> Result { // Reduce the amount of code we need to monomorphize per `T`. diff --git a/core/src/cell.rs b/core/src/cell.rs index d62cb28fc5729..c553979032777 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -587,7 +587,7 @@ impl Cell { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() @@ -1150,7 +1150,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[rustc_never_returns_null_ptr] pub fn as_ptr(&self) -> *mut T { self.value.get() @@ -2135,7 +2135,6 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "unsafe_cell_from_mut", since = "1.84.0")] #[rustc_const_stable(feature = "unsafe_cell_from_mut", since = "1.84.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn from_mut(value: &mut T) -> &mut UnsafeCell { // SAFETY: `UnsafeCell` has the same memory layout as `T` due to #[repr(transparent)]. unsafe { &mut *(value as *mut T as *mut UnsafeCell) } @@ -2160,7 +2159,7 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of @@ -2308,7 +2307,7 @@ impl SyncUnsafeCell { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { self.value.get() diff --git a/core/src/char/methods.rs b/core/src/char/methods.rs index 86822af31ca26..7d33765879f2f 100644 --- a/core/src/char/methods.rs +++ b/core/src/char/methods.rs @@ -1787,7 +1787,6 @@ const fn len_utf16(code: u32) -> usize { /// Panics if the buffer is not large enough. /// A buffer of length four is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))] #[doc(hidden)] #[inline] pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { @@ -1836,10 +1835,6 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { /// Panics if the buffer is not large enough. /// A buffer of length 2 is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_char_encode_utf16", since = "1.84.0") -)] #[doc(hidden)] #[inline] pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 9e32f74227cf9..8831443a10f17 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -138,11 +138,9 @@ enum FromBytesWithNulErrorKind { // FIXME: const stability attributes should not be required here, I think impl FromBytesWithNulError { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))] const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))] const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -464,8 +462,7 @@ impl CStr { /// /// ```no_run /// # #![allow(unused_must_use)] - /// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))] - /// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))] + /// # #![expect(dangling_pointers_from_temporaries)] /// use std::ffi::CString; /// /// // Do not do this: @@ -500,7 +497,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() @@ -732,7 +729,6 @@ impl AsRef for CStr { /// located within `isize::MAX` from `ptr`. #[inline] #[unstable(feature = "cstr_internals", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))] #[rustc_allow_const_fn_unstable(const_eval_select)] const unsafe fn strlen(ptr: *const c_char) -> usize { const_eval_select!( diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 9db6d27967ff7..7fc9dd21fdd81 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -333,10 +333,6 @@ pub struct Arguments<'a> { #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { #[inline] - #[cfg_attr( - bootstrap, - rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none") - )] pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { const { assert!(N <= 1) }; Arguments { pieces, fmt: None, args: &[] } diff --git a/core/src/future/future.rs b/core/src/future/future.rs index 234914c20fc31..cfbd88bbe7998 100644 --- a/core/src/future/future.rs +++ b/core/src/future/future.rs @@ -25,7 +25,7 @@ use crate::task::{Context, Poll}; /// [`async`]: ../../std/keyword.async.html /// [`Waker`]: crate::task::Waker #[doc(notable_trait)] -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] diff --git a/core/src/hint.rs b/core/src/hint.rs index 78df51f2bc47d..c59e4414d3726 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -506,7 +506,6 @@ pub const fn black_box(dummy: T) -> T { /// # } /// ``` #[unstable(feature = "hint_must_use", issue = "94745")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "hint_must_use", issue = "94745"))] #[must_use] // <-- :) #[inline(always)] pub const fn must_use(value: T) -> T { diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 8741e1b080754..6b9011adf3d3d 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1431,11 +1431,7 @@ pub fn abort() -> ! { /// reach code marked with this function. /// /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1453,8 +1449,7 @@ pub const unsafe fn unreachable() -> ! { /// own, or if it does not enable any significant optimizations. /// /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -1474,8 +1469,7 @@ pub const unsafe fn assume(b: bool) { /// /// This intrinsic does not have a stable counterpart. #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] -#[cfg(not(bootstrap))] +#[rustc_intrinsic] #[rustc_nounwind] #[miri::intrinsic_fallback_is_spec] #[cold] @@ -1492,19 +1486,10 @@ pub const fn cold_path() {} /// any safety invariants. /// /// This intrinsic does not have a stable counterpart. -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_likely", since = "1.84.0") -)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_nounwind] #[inline(always)] pub const fn likely(b: bool) -> bool { - #[cfg(bootstrap)] - { - b - } - #[cfg(not(bootstrap))] if b { true } else { @@ -1524,19 +1509,10 @@ pub const fn likely(b: bool) -> bool { /// any safety invariants. /// /// This intrinsic does not have a stable counterpart. -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_likely", since = "1.84.0") -)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_nounwind] #[inline(always)] pub const fn unlikely(b: bool) -> bool { - #[cfg(bootstrap)] - { - b - } - #[cfg(not(bootstrap))] if b { cold_path(); true @@ -1570,8 +1546,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1583,8 +1558,7 @@ pub const fn assert_inhabited() { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1595,8 +1569,7 @@ pub const fn assert_zero_valid() { /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1612,8 +1585,7 @@ pub const fn assert_mem_uninitialized_valid() { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1630,8 +1602,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> { /// it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold /// any safety invariants. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1944,8 +1915,7 @@ pub const unsafe fn transmute(_src: Src) -> Dst { /// /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1966,8 +1936,7 @@ pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { /// any safety invariants. /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1992,8 +1961,7 @@ pub const fn needs_drop() -> bool { /// /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2015,8 +1983,7 @@ pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { /// /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2723,8 +2690,7 @@ pub fn frem_algebraic(_a: T, _b: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2768,8 +2734,7 @@ pub const fn ctpop(_x: T) -> u32 { /// let num_leading = ctlz(x); /// assert_eq!(num_leading, 16); /// ``` -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2794,8 +2759,7 @@ pub const fn ctlz(_x: T) -> u32 { /// let num_leading = unsafe { ctlz_nonzero(x) }; /// assert_eq!(num_leading, 3); /// ``` -#[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2839,8 +2803,7 @@ pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { /// let num_trailing = cttz(x); /// assert_eq!(num_trailing, 16); /// ``` -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2865,8 +2828,7 @@ pub const fn cttz(_x: T) -> u32 { /// let num_trailing = unsafe { cttz_nonzero(x) }; /// assert_eq!(num_trailing, 3); /// ``` -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2884,8 +2846,7 @@ pub const unsafe fn cttz_nonzero(_x: T) -> u32 { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2903,8 +2864,7 @@ pub const fn bswap(_x: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2919,7 +2879,6 @@ pub const fn bitreverse(_x: T) -> T { /// large and difficult to optimize. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_three_way_compare", issue = "none"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { @@ -2936,8 +2895,7 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2955,8 +2913,7 @@ pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2974,8 +2931,7 @@ pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2987,7 +2943,6 @@ pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// /// This intrinsic does not have a stable counterpart. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_exact_div", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3001,8 +2956,7 @@ pub const unsafe fn exact_div(_x: T, _y: T) -> T { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3015,8 +2969,7 @@ pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3030,8 +2983,7 @@ pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3044,8 +2996,7 @@ pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3058,8 +3009,7 @@ pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { /// /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3072,8 +3022,7 @@ pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { /// /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3086,8 +3035,7 @@ pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { /// /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3105,8 +3053,7 @@ pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3124,8 +3071,7 @@ pub const fn rotate_left(_x: T, _shift: u32) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3143,8 +3089,7 @@ pub const fn rotate_right(_x: T, _shift: u32) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3161,8 +3106,7 @@ pub const fn wrapping_add(_a: T, _b: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3179,8 +3123,7 @@ pub const fn wrapping_sub(_a: T, _b: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3198,8 +3141,7 @@ pub const fn wrapping_mul(_a: T, _b: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3216,8 +3158,7 @@ pub const fn saturating_add(_a: T, _b: T) -> T { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3231,8 +3172,7 @@ pub const fn saturating_sub(_a: T, _b: T) -> T { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it /// trivially obeys runtime-MIR rules about derefs in operands. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3246,8 +3186,7 @@ pub const unsafe fn read_via_copy(_ptr: *const T) -> T { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3264,8 +3203,7 @@ pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { /// any safety invariants. /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3304,8 +3242,7 @@ extern "rust-intrinsic" { } /// See documentation of `<*const T>::offset_from` for details. -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3314,7 +3251,6 @@ pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize } /// See documentation of `<*const T>::sub_ptr` for details. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3326,7 +3262,6 @@ pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) /// Returns `2` if the result is unknown. /// Returns `1` if the pointers are guaranteed equal. /// Returns `0` if the pointers are guaranteed inequal. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))] #[rustc_intrinsic] #[rustc_nounwind] #[rustc_do_not_const_check] @@ -3359,7 +3294,6 @@ pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { /// /// (The implementation is allowed to branch on the results of comparisons, /// which is UB if any of their inputs are `undef`.) -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3381,10 +3315,6 @@ pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { /// that differs. That allows optimizations that can read in large chunks. /// /// [valid]: crate::ptr#safety -#[cfg_attr( - bootstrap, - rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none") -)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3395,7 +3325,6 @@ pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: u /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_black_box", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3627,11 +3556,7 @@ pub(crate) macro const_eval_select { /// # _ = foo(&5_i32); /// # _ = bar(&5_i32); /// ``` -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_is_val_statically_known", since = "1.84.0") -)] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_const_stable_indirect] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -3673,8 +3598,7 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] // just for UB checks +#[rustc_intrinsic_const_stable_indirect] // just for UB checks #[inline(always)] #[rustc_intrinsic] pub const fn ub_checks() -> bool { @@ -3757,8 +3681,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { /// The stabilized version of this intrinsic is [`core::mem::size_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn size_of() -> usize { @@ -3775,8 +3698,7 @@ pub const fn size_of() -> usize { /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn min_align_of() -> usize { @@ -3789,7 +3711,6 @@ pub const fn min_align_of() -> usize { /// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_pref_align_of", issue = "91971"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn pref_align_of() -> usize { @@ -3807,7 +3728,6 @@ pub const unsafe fn pref_align_of() -> usize { /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "variant_count", issue = "73662"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn variant_count() -> usize { @@ -3823,7 +3743,6 @@ pub const fn variant_count() -> usize { /// See [`crate::mem::size_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_size_of_val", issue = "46571"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn size_of_val(_ptr: *const T) -> usize { @@ -3839,7 +3758,6 @@ pub const unsafe fn size_of_val(_ptr: *const T) -> usize { /// See [`crate::mem::align_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_align_of_val", issue = "46571"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { @@ -3856,7 +3774,6 @@ pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_name", issue = "63084"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn type_name() -> &'static str { @@ -3875,7 +3792,6 @@ pub const fn type_name() -> &'static str { /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_id", issue = "77125"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn type_id() -> u128 { @@ -3889,8 +3805,7 @@ pub const fn type_id() -> u128 { /// change the possible layouts of pointers. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { @@ -3915,11 +3830,7 @@ impl AggregateRawPtr<*mut T> for *mut P { /// This is used to implement functions like `ptr::metadata`. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[cfg_attr( - bootstrap, - cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { @@ -4025,8 +3936,7 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] + #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -4132,8 +4042,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] + #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -4216,8 +4125,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] + #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -4250,7 +4158,6 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { /// The stabilized version of this intrinsic is /// [`f16::min`] #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf16(_x: f16, _y: f16) -> f16 { @@ -4267,11 +4174,7 @@ pub const fn minnumf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::min`] #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf32(_x: f32, _y: f32) -> f32 { @@ -4288,11 +4191,7 @@ pub const fn minnumf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::min`] #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf64(_x: f64, _y: f64) -> f64 { @@ -4309,7 +4208,6 @@ pub const fn minnumf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::min`] #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf128(_x: f128, _y: f128) -> f128 { @@ -4326,7 +4224,6 @@ pub const fn minnumf128(_x: f128, _y: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::max`] #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { @@ -4343,11 +4240,7 @@ pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::max`] #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { @@ -4364,11 +4257,7 @@ pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::max`] #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { @@ -4385,7 +4274,6 @@ pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::max`] #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { @@ -4397,7 +4285,6 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::abs`](../../std/primitive.f16.html#method.abs) #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf16(_x: f16) -> f16 { @@ -4409,11 +4296,7 @@ pub const unsafe fn fabsf16(_x: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::abs`](../../std/primitive.f32.html#method.abs) #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf32(_x: f32) -> f32 { @@ -4425,11 +4308,7 @@ pub const unsafe fn fabsf32(_x: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::abs`](../../std/primitive.f64.html#method.abs) #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf64(_x: f64) -> f64 { @@ -4441,7 +4320,6 @@ pub const unsafe fn fabsf64(_x: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::abs`](../../std/primitive.f128.html#method.abs) #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf128(_x: f128) -> f128 { @@ -4453,7 +4331,6 @@ pub const unsafe fn fabsf128(_x: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { @@ -4465,11 +4342,7 @@ pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { @@ -4480,11 +4353,7 @@ pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) #[rustc_nounwind] -#[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION") -)] -#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { @@ -4496,7 +4365,6 @@ pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { diff --git a/core/src/lib.rs b/core/src/lib.rs index 1089d415eca94..1b9a9ea3ecffc 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -107,9 +107,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(const_exact_div))] -#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] -#![cfg_attr(bootstrap, feature(const_ub_checks))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] @@ -159,8 +156,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(strict_provenance))] -#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -210,6 +205,7 @@ #![feature(simd_ffi)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] #![feature(target_feature_11)] #![feature(trait_alias)] #![feature(transparent_unions)] @@ -259,7 +255,6 @@ pub mod assert_matches { } // We don't export this through #[macro_export] for now, to avoid breakage. -#[cfg(not(bootstrap))] #[unstable(feature = "autodiff", issue = "124509")] /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 771c2d31b60e0..ab674b58902b5 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1554,7 +1554,6 @@ pub(crate) mod builtin { #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] - #[cfg(not(bootstrap))] pub macro autodiff($item:item) { /* compiler built-in */ } diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 476a8f823cb6f..3c1a098374ef9 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -529,7 +529,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline(always)] pub const fn as_ptr(&self) -> *const T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -571,7 +571,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -911,10 +911,7 @@ impl MaybeUninit { /// }; /// ``` #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] - #[rustc_const_stable( - feature = "const_maybe_uninit_assume_init", - since = "1.84.0" - )] + #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.84.0")] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 3d55313b56c86..9a202600988c4 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -1152,7 +1152,6 @@ macro_rules! int_impl { )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "unchecked_neg", issue = "85122"))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_neg(self) -> Self { @@ -1217,7 +1216,6 @@ macro_rules! int_impl { /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1282,7 +1280,6 @@ macro_rules! int_impl { )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "unchecked_shifts", issue = "85122"))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { @@ -1340,7 +1337,6 @@ macro_rules! int_impl { /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1405,7 +1401,6 @@ macro_rules! int_impl { )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "unchecked_shifts", issue = "85122"))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { @@ -2134,7 +2129,6 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] pub const fn wrapping_shl(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -2164,7 +2158,6 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] pub const fn wrapping_shr(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 4278fec9f58c2..995ed6eac3015 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -1449,7 +1449,6 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_from_str", since = "1.82.0"))] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index ed3f02788e622..90b986f4998db 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -1434,7 +1434,6 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1499,7 +1498,6 @@ macro_rules! uint_impl { )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "unchecked_shifts", issue = "85122"))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { @@ -1557,7 +1555,6 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1622,7 +1619,6 @@ macro_rules! uint_impl { )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "unchecked_shifts", issue = "85122"))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { @@ -2193,7 +2189,6 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] pub const fn wrapping_shl(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -2226,7 +2221,6 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_shifts))] pub const fn wrapping_shr(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -3091,7 +3085,6 @@ macro_rules! uint_impl { // overflow cases it instead ends up returning the maximum value // of the type, and can return 0 for 0. #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_pow", since = "1.50.0"))] const fn one_less_than_next_power_of_two(self) -> Self { if self <= 1 { return 0; } diff --git a/core/src/ops/deref.rs b/core/src/ops/deref.rs index e9bb40d0fdd17..c36d55fe2a8c1 100644 --- a/core/src/ops/deref.rs +++ b/core/src/ops/deref.rs @@ -405,18 +405,15 @@ unsafe impl DerefPure for &mut T {} /// } /// ``` #[lang = "receiver"] -#[cfg(not(bootstrap))] #[unstable(feature = "arbitrary_self_types", issue = "44874")] pub trait Receiver { /// The target type on which the method may be called. - #[cfg(not(bootstrap))] #[rustc_diagnostic_item = "receiver_target"] #[lang = "receiver_target"] #[unstable(feature = "arbitrary_self_types", issue = "44874")] type Target: ?Sized; } -#[cfg(not(bootstrap))] #[unstable(feature = "arbitrary_self_types", issue = "44874")] impl Receiver for P where @@ -433,8 +430,7 @@ where /// facility based around the current "arbitrary self types" unstable feature. /// That new facility will use the replacement trait above called `Receiver` /// which is why this is now named `LegacyReceiver`. -#[cfg_attr(bootstrap, lang = "receiver")] -#[cfg_attr(not(bootstrap), lang = "legacy_receiver")] +#[lang = "legacy_receiver"] #[unstable(feature = "legacy_receiver_trait", issue = "none")] #[doc(hidden)] pub trait LegacyReceiver { diff --git a/core/src/ops/mod.rs b/core/src/ops/mod.rs index cea1f84f3fd60..40526f9583e64 100644 --- a/core/src/ops/mod.rs +++ b/core/src/ops/mod.rs @@ -171,7 +171,6 @@ pub use self::deref::DerefPure; #[unstable(feature = "legacy_receiver_trait", issue = "none")] pub use self::deref::LegacyReceiver; #[unstable(feature = "arbitrary_self_types", issue = "44874")] -#[cfg(not(bootstrap))] pub use self::deref::Receiver; #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; diff --git a/core/src/option.rs b/core/src/option.rs index a12fb6a827e73..f4ac7af63961b 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -563,7 +563,7 @@ use crate::pin::Pin; use crate::{cmp, convert, hint, mem, slice}; /// The `Option` type. See [the module level documentation](self) for more. -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] #[derive(Copy, Eq, Debug, Hash)] #[rustc_diagnostic_item = "Option"] #[lang = "Option"] diff --git a/core/src/panic.rs b/core/src/panic.rs index 1e61cfd804c26..5fa340a6147f6 100644 --- a/core/src/panic.rs +++ b/core/src/panic.rs @@ -208,14 +208,13 @@ pub macro const_panic { #[rustc_allow_const_fn_unstable(const_eval_select)] #[inline(always)] // inline the wrapper #[track_caller] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_panic", since = "1.84.0"))] const fn do_panic($($arg: $ty),*) -> ! { $crate::intrinsics::const_eval_select!( @capture { $($arg: $ty = $arg),* } -> !: #[noinline] if const #[track_caller] #[inline] { // Inline this, to prevent codegen $crate::panic!($const_msg) - } else #[track_caller] #[cfg_attr(bootstrap, inline)] { // Do not inline this, it makes perf worse + } else #[track_caller] { // Do not inline this, it makes perf worse $crate::panic!($runtime_msg) } ) diff --git a/core/src/panicking.rs b/core/src/panicking.rs index f603eb2971f6d..53e2b238bae69 100644 --- a/core/src/panicking.rs +++ b/core/src/panicking.rs @@ -51,8 +51,7 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -86,8 +85,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // which causes a "panic in a function that cannot unwind". #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { const_eval_select!( @@ -130,8 +128,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = "panic"] // used by lints and miri for panics pub const fn panic(expr: &'static str) -> ! { // Use Arguments::new_const instead of format_args!("{expr}") to potentially @@ -169,8 +166,7 @@ macro_rules! panic_const { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable + #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] pub const fn $lang() -> ! { // Use Arguments::new_const instead of format_args!("{expr}") to potentially @@ -217,8 +213,7 @@ panic_const! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_nounwind(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); } @@ -234,8 +229,7 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { #[track_caller] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_explicit() -> ! { panic_display(&"explicit panic"); } @@ -252,8 +246,7 @@ pub fn unreachable_display(x: &T) -> ! { #[inline] #[track_caller] #[rustc_diagnostic_item = "panic_str_2015"] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_str_2015(expr: &str) -> ! { panic_display(&expr); } @@ -263,8 +256,7 @@ pub const fn panic_str_2015(expr: &str) -> ! { #[rustc_do_not_const_check] // hooked by const-eval // enforce a &&str argument in const-check and hook this by const-eval #[rustc_const_panic_str] -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } @@ -333,8 +325,7 @@ fn panic_in_cleanup() -> ! { /// This function is used instead of panic_fmt in const eval. #[lang = "const_panic_fmt"] // needed by const-eval machine to replace calls to `panic_fmt` lang item -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { // The panic_display function is hooked by const eval. diff --git a/core/src/ptr/alignment.rs b/core/src/ptr/alignment.rs index 2538d60a8eee9..74a1d40f4e734 100644 --- a/core/src/ptr/alignment.rs +++ b/core/src/ptr/alignment.rs @@ -41,7 +41,6 @@ impl Alignment { /// This provides the same numerical value as [`mem::align_of`], /// but in an `Alignment` instead of a `usize`. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn of() -> Self { // SAFETY: rustc ensures that type alignment is always a power of two. @@ -53,7 +52,6 @@ impl Alignment { /// /// Note that `0` is not a power of two, nor a valid alignment. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn new(align: usize) -> Option { if align.is_power_of_two() { @@ -73,7 +71,6 @@ impl Alignment { /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. /// It must *not* be zero. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const unsafe fn new_unchecked(align: usize) -> Self { assert_unsafe_precondition!( @@ -89,7 +86,6 @@ impl Alignment { /// Returns the alignment as a [`usize`]. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn as_usize(self) -> usize { self.0 as usize @@ -97,7 +93,6 @@ impl Alignment { /// Returns the alignment as a [NonZero]<[usize]>. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn as_nonzero(self) -> NonZero { // SAFETY: All the discriminants are non-zero. @@ -118,7 +113,6 @@ impl Alignment { /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10); /// ``` #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() @@ -148,7 +142,6 @@ impl Alignment { /// assert_ne!(one.mask(Alignment::of::().mask()), one); /// ``` #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn mask(self) -> usize { // SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow. diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index acb2f0d6d76d4..6f6815f49cd29 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -113,7 +113,6 @@ impl *const T { /// println!("{:?}", unsafe { &*bad }); /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *const U @@ -1018,7 +1017,6 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_neg))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub(self, count: usize) -> Self diff --git a/core/src/ptr/metadata.rs b/core/src/ptr/metadata.rs index 5f20cb2ee7206..ae9810e558aa1 100644 --- a/core/src/ptr/metadata.rs +++ b/core/src/ptr/metadata.rs @@ -92,7 +92,6 @@ pub trait Thin = Pointee; /// /// assert_eq!(std::ptr::metadata("foo"), 3_usize); /// ``` -#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { ptr_metadata(ptr) @@ -106,7 +105,6 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { /// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn from_raw_parts( data_pointer: *const impl Thin, @@ -120,7 +118,6 @@ pub const fn from_raw_parts( /// /// See the documentation of [`from_raw_parts`] for more details. #[unstable(feature = "ptr_metadata", issue = "81513")] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn from_raw_parts_mut( data_pointer: *mut impl Thin, diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 115aa9d8be7e4..678c6029158b5 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -94,7 +94,6 @@ impl *mut T { /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`. /// println!("{:?}", unsafe { &*bad }); #[unstable(feature = "set_ptr_value", issue = "75091")] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *mut U @@ -1097,7 +1096,6 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_neg))] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn sub(self, count: usize) -> Self diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 0fb5880fd1a0e..d37b7eedfcbdb 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -629,7 +629,6 @@ impl NonNull { #[must_use = "returns a new pointer rather than modifying its argument"] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] - #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_neg))] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, diff --git a/core/src/result.rs b/core/src/result.rs index b450123c5aa90..9c7be618bc773 100644 --- a/core/src/result.rs +++ b/core/src/result.rs @@ -520,7 +520,7 @@ use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// /// See the [module documentation](self) for details. -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "Result"] diff --git a/core/src/slice/memchr.rs b/core/src/slice/memchr.rs index 339adad1b17bf..98db7aaf53321 100644 --- a/core/src/slice/memchr.rs +++ b/core/src/slice/memchr.rs @@ -16,7 +16,6 @@ const USIZE_BYTES: usize = mem::size_of::(); /// bytes where the borrow propagated all the way to the most significant /// bit." #[inline] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn contains_zero_byte(x: usize) -> bool { x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 } @@ -24,7 +23,6 @@ const fn contains_zero_byte(x: usize) -> bool { /// Returns the first index matching the byte `x` in `text`. #[inline] #[must_use] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] pub const fn memchr(x: u8, text: &[u8]) -> Option { // Fast path for small slices. if text.len() < 2 * USIZE_BYTES { @@ -35,7 +33,6 @@ pub const fn memchr(x: u8, text: &[u8]) -> Option { } #[inline] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_naive(x: u8, text: &[u8]) -> Option { let mut i = 0; @@ -52,7 +49,6 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option { } #[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_aligned(x: u8, text: &[u8]) -> Option { // The runtime version behaves the same as the compiletime version, it's // just more optimized. diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 7afdb680df65b..a24417dba8cc2 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -735,7 +735,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -766,7 +766,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 189ab39e976f5..8a473b398bb5f 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -373,7 +373,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -391,7 +391,7 @@ impl str { #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] #[rustc_never_returns_null_ptr] - #[cfg_attr(not(bootstrap), rustc_as_ptr)] + #[rustc_as_ptr] #[must_use] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut u8 { diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index 34673707f010a..41e9c593ebdb3 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -319,7 +319,6 @@ impl<'a> ContextBuilder<'a> { /// Creates a ContextBuilder from a Waker. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))] pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; @@ -373,7 +372,6 @@ impl<'a> ContextBuilder<'a> { /// Builds the `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))] pub const fn build(self) -> Context<'a> { let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self; Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 } diff --git a/core/src/ub_checks.rs b/core/src/ub_checks.rs index 3e6110c9c88a7..b289f6026ffcb 100644 --- a/core/src/ub_checks.rs +++ b/core/src/ub_checks.rs @@ -47,7 +47,6 @@ use crate::intrinsics::{self, const_eval_select}; /// order to call it. Since the precompiled standard library is built with full debuginfo and these /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough /// debuginfo to have a measurable compile-time impact on debug builds. -#[cfg_attr(bootstrap, allow_internal_unstable(const_ub_checks))] // permit this to be called in stably-const fn #[macro_export] #[unstable(feature = "ub_checks", issue = "none")] macro_rules! assert_unsafe_precondition { @@ -89,7 +88,6 @@ pub use intrinsics::ub_checks as check_library_ub; /// /// The intention is to not do that when running in the interpreter, as that one has its own /// language UB checks which generally produce better errors. -#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn check_language_ub() -> bool { diff --git a/core/src/unicode/unicode_data.rs b/core/src/unicode/unicode_data.rs index 7f4826402eb53..4655d35e9c437 100644 --- a/core/src/unicode/unicode_data.rs +++ b/core/src/unicode/unicode_data.rs @@ -1,7 +1,6 @@ ///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually! #[inline(always)] -#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, @@ -424,7 +423,6 @@ pub mod lowercase { (5, 187), (6, 78), (7, 132), ]; - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, @@ -549,7 +547,6 @@ pub mod uppercase { (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), ]; - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, diff --git a/core/tests/lib.rs b/core/tests/lib.rs index f7825571cd7a8..40129619ce50e 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -1,7 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(const_three_way_compare))] -#![cfg_attr(bootstrap, feature(strict_provenance))] -#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] @@ -83,6 +80,7 @@ #![feature(step_trait)] #![feature(str_internals)] #![feature(strict_provenance_atomic_ptr)] +#![feature(strict_provenance_lints)] #![feature(test)] #![feature(trait_upcasting)] #![feature(trusted_len)] diff --git a/panic_unwind/Cargo.toml b/panic_unwind/Cargo.toml index 6d1f9764efbfd..252f118fecfbb 100644 --- a/panic_unwind/Cargo.toml +++ b/panic_unwind/Cargo.toml @@ -23,7 +23,4 @@ libc = { version = "0.2", default-features = false } [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [ - # #[cfg(bootstrap)] rtems - 'cfg(target_os, values("rtems"))', -] +check-cfg = [] diff --git a/std/Cargo.toml b/std/Cargo.toml index c1ab70b714a4c..260732dee188e 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -144,6 +144,4 @@ check-cfg = [ # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg 'cfg(feature, values(any()))', - # #[cfg(bootstrap)] rtems - 'cfg(target_os, values("rtems"))', ] diff --git a/std/src/lib.rs b/std/src/lib.rs index 314d9203ca10f..42f99c3b97118 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -262,7 +262,6 @@ #![allow(unused_features)] // // Features: -#![cfg_attr(not(bootstrap), feature(autodiff))] #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), @@ -274,13 +273,12 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(strict_provenance))] -#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] +#![feature(autodiff)] #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] @@ -314,6 +312,7 @@ #![feature(rustdoc_internals)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] #![feature(thread_local)] #![feature(try_blocks)] #![feature(type_alias_impl_trait)] @@ -623,7 +622,6 @@ pub mod simd { #[doc(inline)] pub use crate::std_float::StdFloat; } -#[cfg(not(bootstrap))] #[unstable(feature = "autodiff", issue = "124509")] /// This module provides support for automatic differentiation. pub mod autodiff { diff --git a/std/src/sys/sync/condvar/no_threads.rs b/std/src/sys/sync/condvar/no_threads.rs index 2a67ed766aa0c..88ce39305e1ae 100644 --- a/std/src/sys/sync/condvar/no_threads.rs +++ b/std/src/sys/sync/condvar/no_threads.rs @@ -5,7 +5,6 @@ pub struct Condvar {} impl Condvar { #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> Condvar { Condvar {} } diff --git a/std/src/sys/sync/mutex/no_threads.rs b/std/src/sys/sync/mutex/no_threads.rs index 7b243575e018e..57c78f454c57c 100644 --- a/std/src/sys/sync/mutex/no_threads.rs +++ b/std/src/sys/sync/mutex/no_threads.rs @@ -10,7 +10,6 @@ unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> Mutex { Mutex { locked: Cell::new(false) } } diff --git a/std/src/sys/sync/once/no_threads.rs b/std/src/sys/sync/once/no_threads.rs index fb1b496510aba..88a1d50361ee4 100644 --- a/std/src/sys/sync/once/no_threads.rs +++ b/std/src/sys/sync/once/no_threads.rs @@ -35,7 +35,6 @@ unsafe impl Sync for Once {} impl Once { #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))] pub const fn new() -> Once { Once { state: Cell::new(State::Incomplete) } } diff --git a/std/src/sys/sync/once/queue.rs b/std/src/sys/sync/once/queue.rs index 87837915b396e..5beff4ce6836c 100644 --- a/std/src/sys/sync/once/queue.rs +++ b/std/src/sys/sync/once/queue.rs @@ -116,7 +116,6 @@ fn to_state(current: StateAndQueue) -> usize { impl Once { #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))] pub const fn new() -> Once { Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) } } diff --git a/std/src/sys/sync/rwlock/no_threads.rs b/std/src/sys/sync/rwlock/no_threads.rs index c11e59f719e93..573d0d602dbd6 100644 --- a/std/src/sys/sync/rwlock/no_threads.rs +++ b/std/src/sys/sync/rwlock/no_threads.rs @@ -10,7 +10,6 @@ unsafe impl Sync for RwLock {} // no threads on this platform impl RwLock { #[inline] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> RwLock { RwLock { mode: Cell::new(0) } } diff --git a/std/src/sys/thread_local/key/racy.rs b/std/src/sys/thread_local/key/racy.rs index 97df8997b80de..e1bc08eabb358 100644 --- a/std/src/sys/thread_local/key/racy.rs +++ b/std/src/sys/thread_local/key/racy.rs @@ -30,7 +30,6 @@ const KEY_SENTVAL: usize = 0; const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; impl LazyKey { - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const fn new(dtor: Option) -> LazyKey { LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor } } diff --git a/std/src/sys/thread_local/os.rs b/std/src/sys/thread_local/os.rs index 58f291ffdb985..00d2e30bd6036 100644 --- a/std/src/sys/thread_local/os.rs +++ b/std/src/sys/thread_local/os.rs @@ -60,7 +60,6 @@ struct Value { } impl Storage { - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const fn new() -> Storage { Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } } diff --git a/std/src/thread/local.rs b/std/src/thread/local.rs index bc5f701e3464a..56cf438bd9bbe 100644 --- a/std/src/thread/local.rs +++ b/std/src/thread/local.rs @@ -237,7 +237,6 @@ impl LocalKey { reason = "recently added to create a key", issue = "none" )] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const unsafe fn new(inner: fn(Option<&mut Option>) -> *const T) -> LocalKey { LocalKey { inner } } diff --git a/unwind/Cargo.toml b/unwind/Cargo.toml index 569a1b3299e5f..96ddae16f0ab3 100644 --- a/unwind/Cargo.toml +++ b/unwind/Cargo.toml @@ -37,7 +37,4 @@ system-llvm-libunwind = [] [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [ - # #[cfg(bootstrap)] rtems - 'cfg(target_os, values("rtems"))', -] +check-cfg = [] From e823042da65eb9ee9542bc47b5fcab9ffbe238fd Mon Sep 17 00:00:00 2001 From: Soveu Date: Tue, 23 Apr 2024 22:14:41 +0200 Subject: [PATCH 026/481] Stabilize `extended_varargs_abi_support` --- std/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/std/src/lib.rs b/std/src/lib.rs index 42f99c3b97118..059c8d8309c83 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -290,7 +290,6 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(extended_varargs_abi_support)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] From e8fba7fcc187b3916f27d72dd500079169ceb360 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Oct 2023 08:33:37 +0000 Subject: [PATCH 027/481] Doc comment custom MIR debuginfo. and add a test for the constant case --- core/src/intrinsics/mir.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/core/src/intrinsics/mir.rs b/core/src/intrinsics/mir.rs index 6539964bc0956..d9701225cceb8 100644 --- a/core/src/intrinsics/mir.rs +++ b/core/src/intrinsics/mir.rs @@ -249,6 +249,30 @@ //! `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`. //! - [`TailCall`] does not have a return destination or next block, so its syntax is just //! `TailCall(function(arg1, arg2, ...))`. +//! +//! #### Debuginfo +//! +//! - A debuginfo name can be given to a local using `debug my_name => contents;`. +//! For `contents`, we use the same syntax as operands, to support both places and constants. +//! +//! ```rust +//! #![allow(internal_features)] +//! #![feature(core_intrinsics, custom_mir)] +//! +//! use core::intrinsics::mir::*; +//! +//! #[custom_mir(dialect = "built")] +//! fn debuginfo(option: Option<&i32>) { +//! mir!( +//! debug option => option; +//! debug projection => *Field::<&i32>(Variant(option, 1), 0); +//! debug constant => 5_usize; +//! { +//! Return() +//! } +//! ) +//! } +//! ``` #![unstable( feature = "custom_mir", From cd9ce4a18cc63eeee00499dff8bf477f45734e56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2024 12:41:51 +0100 Subject: [PATCH 028/481] refine mir debuginfo docs --- core/src/intrinsics/mir.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/core/src/intrinsics/mir.rs b/core/src/intrinsics/mir.rs index d9701225cceb8..55dcf7cd47e97 100644 --- a/core/src/intrinsics/mir.rs +++ b/core/src/intrinsics/mir.rs @@ -252,8 +252,13 @@ //! //! #### Debuginfo //! -//! - A debuginfo name can be given to a local using `debug my_name => contents;`. -//! For `contents`, we use the same syntax as operands, to support both places and constants. +//! Debuginfo associates source code variable names (of variables that may not exist any more) with +//! MIR expressions that indicate where the value of that variable is stored. The syntax to do so +//! is: +//! ```text +//! debug source_var_name => expression; +//! ``` +//! Both places and constants are supported in the `expression`. //! //! ```rust //! #![allow(internal_features)] @@ -262,10 +267,14 @@ //! use core::intrinsics::mir::*; //! //! #[custom_mir(dialect = "built")] -//! fn debuginfo(option: Option<&i32>) { +//! fn debuginfo(arg: Option<&i32>) { //! mir!( -//! debug option => option; -//! debug projection => *Field::<&i32>(Variant(option, 1), 0); +//! // Debuginfo for a source variable `plain_local` that just duplicates `arg`. +//! debug plain_local => arg; +//! // Debuginfo for a source variable `projection` that can be computed by dereferencing +//! // a field of `arg`. +//! debug projection => *Field::<&i32>(Variant(arg, 1), 0); +//! // Debuginfo for a source variable `constant` that always holds the value `5`. //! debug constant => 5_usize; //! { //! Return() From c57bde10150ed0bcb6c48cbbd7ef46cd0d49841e Mon Sep 17 00:00:00 2001 From: Kornel Date: Sat, 2 Nov 2024 11:05:01 +0000 Subject: [PATCH 029/481] Fix and undeprecate home_dir() --- std/src/env.rs | 16 ++++++---------- std/src/sys/pal/windows/os.rs | 4 ++-- std/tests/env.rs | 12 ++++++------ 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/std/src/env.rs b/std/src/env.rs index 27f4daba44bf6..043747d0bc5e3 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -608,20 +608,16 @@ impl Error for JoinPathsError { /// /// # Windows /// -/// - Returns the value of the 'HOME' environment variable if it is set -/// (including to an empty string). -/// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set -/// (including to an empty string). -/// - If both do not exist, [`GetUserProfileDirectory`][msdn] is used to return the path. +/// - Returns the value of the 'USERPROFILE' environment variable if it is set, and is not an empty string. +/// - Otherwise, [`GetUserProfileDirectory`][msdn] is used to return the path. This may change in the future. /// /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectorya /// -/// # Deprecation +/// In UWP (Universal Windows Platform) targets this function is unimplemented and always returns `None`. /// -/// This function is deprecated because the behavior on Windows is not correct. -/// The 'HOME' environment variable is not standard on Windows, and may not produce -/// desired results; for instance, under Cygwin or Mingw it will return `/home/you` -/// when it should return `C:\Users\you`. +/// Before Rust CURRENT_RUSTC_VERSION, this function used to return the value of the 'HOME' environment variable +/// on Windows, which in Cygwin or Mingw environments could return non-standard paths like `/home/you` +/// instead of `C:\Users\you`. /// /// # Examples /// diff --git a/std/src/sys/pal/windows/os.rs b/std/src/sys/pal/windows/os.rs index 5242bc9da31fe..5231a34469abf 100644 --- a/std/src/sys/pal/windows/os.rs +++ b/std/src/sys/pal/windows/os.rs @@ -377,8 +377,8 @@ fn home_dir_crt() -> Option { } pub fn home_dir() -> Option { - crate::env::var_os("HOME") - .or_else(|| crate::env::var_os("USERPROFILE")) + crate::env::var_os("USERPROFILE") + .filter(|s| !s.is_empty()) .map(PathBuf::from) .or_else(home_dir_crt) } diff --git a/std/tests/env.rs b/std/tests/env.rs index 4e472b4ce9953..44fe84c989fb7 100644 --- a/std/tests/env.rs +++ b/std/tests/env.rs @@ -122,19 +122,19 @@ fn env_home_dir() { assert!(home_dir().is_some()); - set_var("HOME", "/home/MountainView"); + set_var("HOME", "/home/PaloAlto"); + assert_ne!(home_dir(), Some(PathBuf::from("/home/PaloAlto")), "HOME must not be used"); + + set_var("USERPROFILE", "/home/MountainView"); assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); remove_var("HOME"); - set_var("USERPROFILE", "/home/MountainView"); assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - set_var("HOME", "/home/MountainView"); - set_var("USERPROFILE", "/home/PaloAlto"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + set_var("USERPROFILE", ""); + assert_ne!(home_dir(), Some(PathBuf::from("")), "Empty USERPROFILE must be ignored"); - remove_var("HOME"); remove_var("USERPROFILE"); if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } From 7d39a490cb5284edfd1742135f0cbe9989c26385 Mon Sep 17 00:00:00 2001 From: "aaishwarymishra@gmail.com" Date: Sat, 16 Nov 2024 19:40:39 +0530 Subject: [PATCH 030/481] changes old intrinsic declaration to new declaration blesses tests/ui/intrinsics blesses tests/ui/intrinsics --- core/src/intrinsics/mod.rs | 1544 ++++++++++++++++++++++-------------- 1 file changed, 949 insertions(+), 595 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 6b9011adf3d3d..46873fdc0479f 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -2006,628 +2006,982 @@ pub fn ptr_mask(_ptr: *const T, _mask: usize) -> *const T { unreachable!() } -extern "rust-intrinsic" { - /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with - /// a size of `count` * `size_of::()` and an alignment of - /// `min_align_of::()` - /// - /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); - /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with - /// a size of `count * size_of::()` and an alignment of - /// `min_align_of::()` - /// - /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); - /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a - /// size of `count * size_of::()` and an alignment of - /// `min_align_of::()`. - /// - /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); +/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with +/// a size of `count` * `size_of::()` and an alignment of +/// `min_align_of::()` +/// +/// The volatile parameter is set to `true`, so it will not be optimized out +/// unless size is equal to zero. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn volatile_copy_nonoverlapping_memory(_dst: *mut T, _src: *const T, _count: usize) { + unreachable!() +} +/// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with +/// a size of `count * size_of::()` and an alignment of +/// `min_align_of::()` +/// +/// The volatile parameter is set to `true`, so it will not be optimized out +/// unless size is equal to zero. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn volatile_copy_memory(_dst: *mut T, _src: *const T, _count: usize) { + unreachable!() +} +/// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a +/// size of `count * size_of::()` and an alignment of +/// `min_align_of::()`. +/// +/// The volatile parameter is set to `true`, so it will not be optimized out +/// unless size is equal to zero. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn volatile_set_memory(_dst: *mut T, _val: u8, _count: usize) { + unreachable!() +} - /// Performs a volatile load from the `src` pointer. - /// - /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. - #[rustc_nounwind] - pub fn volatile_load(src: *const T) -> T; - /// Performs a volatile store to the `dst` pointer. - /// - /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. - #[rustc_nounwind] - pub fn volatile_store(dst: *mut T, val: T); +/// Performs a volatile load from the `src` pointer. +/// +/// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn volatile_load(_src: *const T) -> T { + unreachable!() +} +/// Performs a volatile store to the `dst` pointer. +/// +/// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn volatile_store(_dst: *mut T, _val: T) { + unreachable!() +} - /// Performs a volatile load from the `src` pointer - /// The pointer is not required to be aligned. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_load"] - pub fn unaligned_volatile_load(src: *const T) -> T; - /// Performs a volatile store to the `dst` pointer. - /// The pointer is not required to be aligned. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] - pub fn unaligned_volatile_store(dst: *mut T, val: T); +/// Performs a volatile load from the `src` pointer +/// The pointer is not required to be aligned. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +#[rustc_diagnostic_item = "intrinsics_unaligned_volatile_load"] +pub unsafe fn unaligned_volatile_load(_src: *const T) -> T { + unreachable!() +} +/// Performs a volatile store to the `dst` pointer. +/// The pointer is not required to be aligned. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +#[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] +pub unsafe fn unaligned_volatile_store(_dst: *mut T, _val: T) { + unreachable!() +} - /// Returns the square root of an `f16` - /// - /// The stabilized version of this intrinsic is - /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf16(x: f16) -> f16; - /// Returns the square root of an `f32` - /// - /// The stabilized version of this intrinsic is - /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf32(x: f32) -> f32; - /// Returns the square root of an `f64` - /// - /// The stabilized version of this intrinsic is - /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf64(x: f64) -> f64; - /// Returns the square root of an `f128` - /// - /// The stabilized version of this intrinsic is - /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) - #[rustc_nounwind] - pub fn sqrtf128(x: f128) -> f128; +/// Returns the square root of an `f16` +/// +/// The stabilized version of this intrinsic is +/// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sqrtf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the square root of an `f32` +/// +/// The stabilized version of this intrinsic is +/// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sqrtf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the square root of an `f64` +/// +/// The stabilized version of this intrinsic is +/// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sqrtf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the square root of an `f128` +/// +/// The stabilized version of this intrinsic is +/// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sqrtf128(_x: f128) -> f128 { + unreachable!() +} - /// Raises an `f16` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f16::powi`](../../std/primitive.f16.html#method.powi) - #[rustc_nounwind] - pub fn powif16(a: f16, x: i32) -> f16; - /// Raises an `f32` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f32::powi`](../../std/primitive.f32.html#method.powi) - #[rustc_nounwind] - pub fn powif32(a: f32, x: i32) -> f32; - /// Raises an `f64` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f64::powi`](../../std/primitive.f64.html#method.powi) - #[rustc_nounwind] - pub fn powif64(a: f64, x: i32) -> f64; - /// Raises an `f128` to an integer power. - /// - /// The stabilized version of this intrinsic is - /// [`f128::powi`](../../std/primitive.f128.html#method.powi) - #[rustc_nounwind] - pub fn powif128(a: f128, x: i32) -> f128; +/// Raises an `f16` to an integer power. +/// +/// The stabilized version of this intrinsic is +/// [`f16::powi`](../../std/primitive.f16.html#method.powi) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powif16(_a: f16, _x: i32) -> f16 { + unreachable!() +} +/// Raises an `f32` to an integer power. +/// +/// The stabilized version of this intrinsic is +/// [`f32::powi`](../../std/primitive.f32.html#method.powi) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powif32(_a: f32, _x: i32) -> f32 { + unreachable!() +} +/// Raises an `f64` to an integer power. +/// +/// The stabilized version of this intrinsic is +/// [`f64::powi`](../../std/primitive.f64.html#method.powi) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powif64(_a: f64, _x: i32) -> f64 { + unreachable!() +} +/// Raises an `f128` to an integer power. +/// +/// The stabilized version of this intrinsic is +/// [`f128::powi`](../../std/primitive.f128.html#method.powi) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powif128(_a: f128, _x: i32) -> f128 { + unreachable!() +} - /// Returns the sine of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::sin`](../../std/primitive.f16.html#method.sin) - #[rustc_nounwind] - pub fn sinf16(x: f16) -> f16; - /// Returns the sine of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::sin`](../../std/primitive.f32.html#method.sin) - #[rustc_nounwind] - pub fn sinf32(x: f32) -> f32; - /// Returns the sine of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::sin`](../../std/primitive.f64.html#method.sin) - #[rustc_nounwind] - pub fn sinf64(x: f64) -> f64; - /// Returns the sine of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::sin`](../../std/primitive.f128.html#method.sin) - #[rustc_nounwind] - pub fn sinf128(x: f128) -> f128; +/// Returns the sine of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::sin`](../../std/primitive.f16.html#method.sin) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sinf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the sine of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::sin`](../../std/primitive.f32.html#method.sin) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sinf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the sine of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::sin`](../../std/primitive.f64.html#method.sin) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sinf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the sine of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::sin`](../../std/primitive.f128.html#method.sin) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn sinf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the cosine of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::cos`](../../std/primitive.f16.html#method.cos) - #[rustc_nounwind] - pub fn cosf16(x: f16) -> f16; - /// Returns the cosine of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::cos`](../../std/primitive.f32.html#method.cos) - #[rustc_nounwind] - pub fn cosf32(x: f32) -> f32; - /// Returns the cosine of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::cos`](../../std/primitive.f64.html#method.cos) - #[rustc_nounwind] - pub fn cosf64(x: f64) -> f64; - /// Returns the cosine of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::cos`](../../std/primitive.f128.html#method.cos) - #[rustc_nounwind] - pub fn cosf128(x: f128) -> f128; +/// Returns the cosine of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::cos`](../../std/primitive.f16.html#method.cos) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn cosf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the cosine of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::cos`](../../std/primitive.f32.html#method.cos) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn cosf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the cosine of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::cos`](../../std/primitive.f64.html#method.cos) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn cosf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the cosine of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::cos`](../../std/primitive.f128.html#method.cos) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn cosf128(_x: f128) -> f128 { + unreachable!() +} - /// Raises an `f16` to an `f16` power. - /// - /// The stabilized version of this intrinsic is - /// [`f16::powf`](../../std/primitive.f16.html#method.powf) - #[rustc_nounwind] - pub fn powf16(a: f16, x: f16) -> f16; - /// Raises an `f32` to an `f32` power. - /// - /// The stabilized version of this intrinsic is - /// [`f32::powf`](../../std/primitive.f32.html#method.powf) - #[rustc_nounwind] - pub fn powf32(a: f32, x: f32) -> f32; - /// Raises an `f64` to an `f64` power. - /// - /// The stabilized version of this intrinsic is - /// [`f64::powf`](../../std/primitive.f64.html#method.powf) - #[rustc_nounwind] - pub fn powf64(a: f64, x: f64) -> f64; - /// Raises an `f128` to an `f128` power. - /// - /// The stabilized version of this intrinsic is - /// [`f128::powf`](../../std/primitive.f128.html#method.powf) - #[rustc_nounwind] - pub fn powf128(a: f128, x: f128) -> f128; +/// Raises an `f16` to an `f16` power. +/// +/// The stabilized version of this intrinsic is +/// [`f16::powf`](../../std/primitive.f16.html#method.powf) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powf16(_a: f16, _x: f16) -> f16 { + unreachable!() +} +/// Raises an `f32` to an `f32` power. +/// +/// The stabilized version of this intrinsic is +/// [`f32::powf`](../../std/primitive.f32.html#method.powf) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powf32(_a: f32, _x: f32) -> f32 { + unreachable!() +} +/// Raises an `f64` to an `f64` power. +/// +/// The stabilized version of this intrinsic is +/// [`f64::powf`](../../std/primitive.f64.html#method.powf) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powf64(_a: f64, _x: f64) -> f64 { + unreachable!() +} +/// Raises an `f128` to an `f128` power. +/// +/// The stabilized version of this intrinsic is +/// [`f128::powf`](../../std/primitive.f128.html#method.powf) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn powf128(_a: f128, _x: f128) -> f128 { + unreachable!() +} - /// Returns the exponential of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::exp`](../../std/primitive.f16.html#method.exp) - #[rustc_nounwind] - pub fn expf16(x: f16) -> f16; - /// Returns the exponential of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::exp`](../../std/primitive.f32.html#method.exp) - #[rustc_nounwind] - pub fn expf32(x: f32) -> f32; - /// Returns the exponential of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::exp`](../../std/primitive.f64.html#method.exp) - #[rustc_nounwind] - pub fn expf64(x: f64) -> f64; - /// Returns the exponential of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::exp`](../../std/primitive.f128.html#method.exp) - #[rustc_nounwind] - pub fn expf128(x: f128) -> f128; +/// Returns the exponential of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::exp`](../../std/primitive.f16.html#method.exp) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn expf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the exponential of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::exp`](../../std/primitive.f32.html#method.exp) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn expf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the exponential of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::exp`](../../std/primitive.f64.html#method.exp) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn expf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the exponential of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::exp`](../../std/primitive.f128.html#method.exp) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn expf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns 2 raised to the power of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f16(x: f16) -> f16; - /// Returns 2 raised to the power of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f32(x: f32) -> f32; - /// Returns 2 raised to the power of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f64(x: f64) -> f64; - /// Returns 2 raised to the power of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) - #[rustc_nounwind] - pub fn exp2f128(x: f128) -> f128; +/// Returns 2 raised to the power of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn exp2f16(_x: f16) -> f16 { + unreachable!() +} +/// Returns 2 raised to the power of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn exp2f32(_x: f32) -> f32 { + unreachable!() +} +/// Returns 2 raised to the power of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn exp2f64(_x: f64) -> f64 { + unreachable!() +} +/// Returns 2 raised to the power of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn exp2f128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the natural logarithm of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::ln`](../../std/primitive.f16.html#method.ln) - #[rustc_nounwind] - pub fn logf16(x: f16) -> f16; - /// Returns the natural logarithm of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::ln`](../../std/primitive.f32.html#method.ln) - #[rustc_nounwind] - pub fn logf32(x: f32) -> f32; - /// Returns the natural logarithm of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::ln`](../../std/primitive.f64.html#method.ln) - #[rustc_nounwind] - pub fn logf64(x: f64) -> f64; - /// Returns the natural logarithm of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::ln`](../../std/primitive.f128.html#method.ln) - #[rustc_nounwind] - pub fn logf128(x: f128) -> f128; +/// Returns the natural logarithm of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::ln`](../../std/primitive.f16.html#method.ln) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn logf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the natural logarithm of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::ln`](../../std/primitive.f32.html#method.ln) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn logf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the natural logarithm of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::ln`](../../std/primitive.f64.html#method.ln) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn logf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the natural logarithm of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::ln`](../../std/primitive.f128.html#method.ln) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn logf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the base 10 logarithm of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::log10`](../../std/primitive.f16.html#method.log10) - #[rustc_nounwind] - pub fn log10f16(x: f16) -> f16; - /// Returns the base 10 logarithm of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::log10`](../../std/primitive.f32.html#method.log10) - #[rustc_nounwind] - pub fn log10f32(x: f32) -> f32; - /// Returns the base 10 logarithm of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::log10`](../../std/primitive.f64.html#method.log10) - #[rustc_nounwind] - pub fn log10f64(x: f64) -> f64; - /// Returns the base 10 logarithm of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::log10`](../../std/primitive.f128.html#method.log10) - #[rustc_nounwind] - pub fn log10f128(x: f128) -> f128; +/// Returns the base 10 logarithm of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::log10`](../../std/primitive.f16.html#method.log10) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log10f16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the base 10 logarithm of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::log10`](../../std/primitive.f32.html#method.log10) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log10f32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the base 10 logarithm of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::log10`](../../std/primitive.f64.html#method.log10) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log10f64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the base 10 logarithm of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::log10`](../../std/primitive.f128.html#method.log10) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log10f128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the base 2 logarithm of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::log2`](../../std/primitive.f16.html#method.log2) - #[rustc_nounwind] - pub fn log2f16(x: f16) -> f16; - /// Returns the base 2 logarithm of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::log2`](../../std/primitive.f32.html#method.log2) - #[rustc_nounwind] - pub fn log2f32(x: f32) -> f32; - /// Returns the base 2 logarithm of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::log2`](../../std/primitive.f64.html#method.log2) - #[rustc_nounwind] - pub fn log2f64(x: f64) -> f64; - /// Returns the base 2 logarithm of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::log2`](../../std/primitive.f128.html#method.log2) - #[rustc_nounwind] - pub fn log2f128(x: f128) -> f128; +/// Returns the base 2 logarithm of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::log2`](../../std/primitive.f16.html#method.log2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log2f16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the base 2 logarithm of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::log2`](../../std/primitive.f32.html#method.log2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log2f32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the base 2 logarithm of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::log2`](../../std/primitive.f64.html#method.log2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log2f64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the base 2 logarithm of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::log2`](../../std/primitive.f128.html#method.log2) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn log2f128(_x: f128) -> f128 { + unreachable!() +} - /// Returns `a * b + c` for `f16` values. - /// - /// The stabilized version of this intrinsic is - /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; - /// Returns `a * b + c` for `f32` values. - /// - /// The stabilized version of this intrinsic is - /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; - /// Returns `a * b + c` for `f64` values. - /// - /// The stabilized version of this intrinsic is - /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; - /// Returns `a * b + c` for `f128` values. - /// - /// The stabilized version of this intrinsic is - /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) - #[rustc_nounwind] - pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; +/// Returns `a * b + c` for `f16` values. +/// +/// The stabilized version of this intrinsic is +/// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmaf16(_a: f16, _b: f16, _c: f16) -> f16 { + unreachable!() +} +/// Returns `a * b + c` for `f32` values. +/// +/// The stabilized version of this intrinsic is +/// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmaf32(_a: f32, _b: f32, _c: f32) -> f32 { + unreachable!() +} +/// Returns `a * b + c` for `f64` values. +/// +/// The stabilized version of this intrinsic is +/// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmaf64(_a: f64, _b: f64, _c: f64) -> f64 { + unreachable!() +} +/// Returns `a * b + c` for `f128` values. +/// +/// The stabilized version of this intrinsic is +/// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmaf128(_a: f128, _b: f128, _c: f128) -> f128 { + unreachable!() +} - /// Returns `a * b + c` for `f16` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; - /// Returns `a * b + c` for `f32` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; - /// Returns `a * b + c` for `f64` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; - /// Returns `a * b + c` for `f128` values, non-deterministically executing - /// either a fused multiply-add or two operations with rounding of the - /// intermediate result. - /// - /// The operation is fused if the code generator determines that target - /// instruction set has support for a fused operation, and that the fused - /// operation is more efficient than the equivalent, separate pair of mul - /// and add instructions. It is unspecified whether or not a fused operation - /// is selected, and that may depend on optimization level and context, for - /// example. - #[rustc_nounwind] - pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; +/// Returns `a * b + c` for `f16` values, non-deterministically executing +/// either a fused multiply-add or two operations with rounding of the +/// intermediate result. +/// +/// The operation is fused if the code generator determines that target +/// instruction set has support for a fused operation, and that the fused +/// operation is more efficient than the equivalent, separate pair of mul +/// and add instructions. It is unspecified whether or not a fused operation +/// is selected, and that may depend on optimization level and context, for +/// example. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmuladdf16(_a: f16, _b: f16, _c: f16) -> f16 { + unreachable!() +} +/// Returns `a * b + c` for `f32` values, non-deterministically executing +/// either a fused multiply-add or two operations with rounding of the +/// intermediate result. +/// +/// The operation is fused if the code generator determines that target +/// instruction set has support for a fused operation, and that the fused +/// operation is more efficient than the equivalent, separate pair of mul +/// and add instructions. It is unspecified whether or not a fused operation +/// is selected, and that may depend on optimization level and context, for +/// example. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmuladdf32(_a: f32, _b: f32, _c: f32) -> f32 { + unreachable!() +} +/// Returns `a * b + c` for `f64` values, non-deterministically executing +/// either a fused multiply-add or two operations with rounding of the +/// intermediate result. +/// +/// The operation is fused if the code generator determines that target +/// instruction set has support for a fused operation, and that the fused +/// operation is more efficient than the equivalent, separate pair of mul +/// and add instructions. It is unspecified whether or not a fused operation +/// is selected, and that may depend on optimization level and context, for +/// example. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmuladdf64(_a: f64, _b: f64, _c: f64) -> f64 { + unreachable!() +} +/// Returns `a * b + c` for `f128` values, non-deterministically executing +/// either a fused multiply-add or two operations with rounding of the +/// intermediate result. +/// +/// The operation is fused if the code generator determines that target +/// instruction set has support for a fused operation, and that the fused +/// operation is more efficient than the equivalent, separate pair of mul +/// and add instructions. It is unspecified whether or not a fused operation +/// is selected, and that may depend on optimization level and context, for +/// example. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmuladdf128(_a: f128, _b: f128, _c: f128) -> f128 { + unreachable!() +} - /// Returns the largest integer less than or equal to an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::floor`](../../std/primitive.f16.html#method.floor) - #[rustc_nounwind] - pub fn floorf16(x: f16) -> f16; - /// Returns the largest integer less than or equal to an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::floor`](../../std/primitive.f32.html#method.floor) - #[rustc_nounwind] - pub fn floorf32(x: f32) -> f32; - /// Returns the largest integer less than or equal to an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::floor`](../../std/primitive.f64.html#method.floor) - #[rustc_nounwind] - pub fn floorf64(x: f64) -> f64; - /// Returns the largest integer less than or equal to an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::floor`](../../std/primitive.f128.html#method.floor) - #[rustc_nounwind] - pub fn floorf128(x: f128) -> f128; +/// Returns the largest integer less than or equal to an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::floor`](../../std/primitive.f16.html#method.floor) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn floorf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the largest integer less than or equal to an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::floor`](../../std/primitive.f32.html#method.floor) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn floorf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the largest integer less than or equal to an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::floor`](../../std/primitive.f64.html#method.floor) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn floorf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the largest integer less than or equal to an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::floor`](../../std/primitive.f128.html#method.floor) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn floorf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the smallest integer greater than or equal to an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf16(x: f16) -> f16; - /// Returns the smallest integer greater than or equal to an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf32(x: f32) -> f32; - /// Returns the smallest integer greater than or equal to an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf64(x: f64) -> f64; - /// Returns the smallest integer greater than or equal to an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) - #[rustc_nounwind] - pub fn ceilf128(x: f128) -> f128; +/// Returns the smallest integer greater than or equal to an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn ceilf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the smallest integer greater than or equal to an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn ceilf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the smallest integer greater than or equal to an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn ceilf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the smallest integer greater than or equal to an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn ceilf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the integer part of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) - #[rustc_nounwind] - pub fn truncf16(x: f16) -> f16; - /// Returns the integer part of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) - #[rustc_nounwind] - pub fn truncf32(x: f32) -> f32; - /// Returns the integer part of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) - #[rustc_nounwind] - pub fn truncf64(x: f64) -> f64; - /// Returns the integer part of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) - #[rustc_nounwind] - pub fn truncf128(x: f128) -> f128; +/// Returns the integer part of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn truncf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the integer part of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn truncf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the integer part of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn truncf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the integer part of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn truncf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf32` and `roundevenf32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf64` and `roundevenf64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// May raise an inexact floating-point exception if the argument is not an integer. - /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions - /// cannot actually be utilized from Rust code. - /// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) - #[rustc_nounwind] - pub fn rintf128(x: f128) -> f128; +/// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// May raise an inexact floating-point exception if the argument is not an integer. +/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions +/// cannot actually be utilized from Rust code. +/// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn rintf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// May raise an inexact floating-point exception if the argument is not an integer. +/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions +/// cannot actually be utilized from Rust code. +/// In other words, this intrinsic is equivalent in behavior to `nearbyintf32` and `roundevenf32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn rintf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// May raise an inexact floating-point exception if the argument is not an integer. +/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions +/// cannot actually be utilized from Rust code. +/// In other words, this intrinsic is equivalent in behavior to `nearbyintf64` and `roundevenf64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn rintf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// May raise an inexact floating-point exception if the argument is not an integer. +/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions +/// cannot actually be utilized from Rust code. +/// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn rintf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, - /// so this rounds half-way cases to the number with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn nearbyintf128(x: f128) -> f128; +/// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn nearbyintf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn nearbyintf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn nearbyintf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, +/// so this rounds half-way cases to the number with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn nearbyintf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f16::round`](../../std/primitive.f16.html#method.round) - #[rustc_nounwind] - pub fn roundf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f32::round`](../../std/primitive.f32.html#method.round) - #[rustc_nounwind] - pub fn roundf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f64::round`](../../std/primitive.f64.html#method.round) - #[rustc_nounwind] - pub fn roundf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. - /// - /// The stabilized version of this intrinsic is - /// [`f128::round`](../../std/primitive.f128.html#method.round) - #[rustc_nounwind] - pub fn roundf128(x: f128) -> f128; +/// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. +/// +/// The stabilized version of this intrinsic is +/// [`f16::round`](../../std/primitive.f16.html#method.round) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. +/// +/// The stabilized version of this intrinsic is +/// [`f32::round`](../../std/primitive.f32.html#method.round) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. +/// +/// The stabilized version of this intrinsic is +/// [`f64::round`](../../std/primitive.f64.html#method.round) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. +/// +/// The stabilized version of this intrinsic is +/// [`f128::round`](../../std/primitive.f128.html#method.round) +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundf128(_x: f128) -> f128 { + unreachable!() +} - /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf16(x: f16) -> f16; - /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf32(x: f32) -> f32; - /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf64(x: f64) -> f64; - /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn roundevenf128(x: f128) -> f128; +/// Returns the nearest integer to an `f16`. Rounds half-way cases to the number +/// with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundevenf16(_x: f16) -> f16 { + unreachable!() +} +/// Returns the nearest integer to an `f32`. Rounds half-way cases to the number +/// with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundevenf32(_x: f32) -> f32 { + unreachable!() +} +/// Returns the nearest integer to an `f64`. Rounds half-way cases to the number +/// with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundevenf64(_x: f64) -> f64 { + unreachable!() +} +/// Returns the nearest integer to an `f128`. Rounds half-way cases to the number +/// with an even least significant digit. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn roundevenf128(_x: f128) -> f128 { + unreachable!() +} - /// Float addition that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fadd_fast(a: T, b: T) -> T; +/// Float addition that allows optimizations based on algebraic rules. +/// May assume inputs are finite. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fadd_fast(_a: T, _b: T) -> T { + unreachable!() +} - /// Float subtraction that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fsub_fast(a: T, b: T) -> T; +/// Float subtraction that allows optimizations based on algebraic rules. +/// May assume inputs are finite. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fsub_fast(_a: T, _b: T) -> T { + unreachable!() +} - /// Float multiplication that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fmul_fast(a: T, b: T) -> T; +/// Float multiplication that allows optimizations based on algebraic rules. +/// May assume inputs are finite. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fmul_fast(_a: T, _b: T) -> T { + unreachable!() +} - /// Float division that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn fdiv_fast(a: T, b: T) -> T; +/// Float division that allows optimizations based on algebraic rules. +/// May assume inputs are finite. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn fdiv_fast(_a: T, _b: T) -> T { + unreachable!() +} - /// Float remainder that allows optimizations based on algebraic rules. - /// May assume inputs are finite. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn frem_fast(a: T, b: T) -> T; +/// Float remainder that allows optimizations based on algebraic rules. +/// May assume inputs are finite. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn frem_fast(_a: T, _b: T) -> T { + unreachable!() +} - /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range - /// () - /// - /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. - #[rustc_nounwind] - pub fn float_to_int_unchecked(value: Float) -> Int; +/// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range +/// () +/// +/// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn float_to_int_unchecked(_value: Float) -> Int { + unreachable!() } /// Float addition that allows optimizations based on algebraic rules. From 026ec885a1f1fa8d6d359f4897d63ddc0412a843 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Tue, 26 Nov 2024 14:01:49 +0100 Subject: [PATCH 031/481] thread::available_parallelism for wasm32-wasip1-threads The target has limited POSIX support and provides the sysconf function which allows querying the number of available CPUs. --- std/src/sys/pal/wasi/thread.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/std/src/sys/pal/wasi/thread.rs b/std/src/sys/pal/wasi/thread.rs index 4b83870fdea6c..3b44f77631f51 100644 --- a/std/src/sys/pal/wasi/thread.rs +++ b/std/src/sys/pal/wasi/thread.rs @@ -2,7 +2,6 @@ use crate::ffi::CStr; use crate::num::NonZero; -use crate::sys::unsupported; use crate::time::Duration; use crate::{io, mem}; @@ -34,6 +33,8 @@ cfg_if::cfg_if! { #[allow(non_camel_case_types)] pub type pthread_t = *mut ffi::c_void; + pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84; + extern "C" { pub fn pthread_create( native: *mut pthread_t, @@ -121,7 +122,7 @@ impl Thread { } } else { pub unsafe fn new(_stack: usize, _p: Box) -> io::Result { - unsupported() + crate::sys::unsupported() } } } @@ -187,5 +188,15 @@ impl Thread { } pub fn available_parallelism() -> io::Result> { - unsupported() + cfg_if::cfg_if! { + if #[cfg(target_feature = "atomics")] { + match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { + -1 => Err(io::Error::last_os_error()), + 0 => Err(io::Error::UNKNOWN_THREAD_COUNT), + cpus => Ok(unsafe { NonZero::new_unchecked(cpus as usize) }), + } + } else { + crate::sys::unsupported() + } + } } From 9f2955c695214873039c6402720d3339b45c22f5 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Wed, 27 Nov 2024 13:30:18 +0100 Subject: [PATCH 032/481] Implement code review --- std/src/sys/pal/wasi/thread.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/src/sys/pal/wasi/thread.rs b/std/src/sys/pal/wasi/thread.rs index 3b44f77631f51..f5e19f26bfe17 100644 --- a/std/src/sys/pal/wasi/thread.rs +++ b/std/src/sys/pal/wasi/thread.rs @@ -192,8 +192,7 @@ pub fn available_parallelism() -> io::Result> { if #[cfg(target_feature = "atomics")] { match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { -1 => Err(io::Error::last_os_error()), - 0 => Err(io::Error::UNKNOWN_THREAD_COUNT), - cpus => Ok(unsafe { NonZero::new_unchecked(cpus as usize) }), + cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT), } } else { crate::sys::unsupported() From c244152386301571dcb88c82aace180dc7f322c5 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 14 Nov 2024 14:45:38 -0800 Subject: [PATCH 033/481] Add `BTreeSet` entry APIs to match `HashSet` * `fn get_or_insert(&mut self, value: T) -> &T` * `fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T` * `fn entry(&mut self, value: T) -> Entry<'_, T, A>` (+ `Entry` APIs) --- alloc/src/collections/btree/map.rs | 29 +- alloc/src/collections/btree/map/entry.rs | 5 + alloc/src/collections/btree/set.rs | 80 ++++- alloc/src/collections/btree/set/entry.rs | 388 +++++++++++++++++++++++ 4 files changed, 500 insertions(+), 2 deletions(-) create mode 100644 alloc/src/collections/btree/set/entry.rs diff --git a/alloc/src/collections/btree/map.rs b/alloc/src/collections/btree/map.rs index 213924d1d0203..d1ce4e215ed9c 100644 --- a/alloc/src/collections/btree/map.rs +++ b/alloc/src/collections/btree/map.rs @@ -308,11 +308,38 @@ impl BTreeMap { alloc: (*map.alloc).clone(), _marker: PhantomData, } - .insert(SetValZST::default()); + .insert(SetValZST); None } } } + + pub(super) fn get_or_insert_with(&mut self, q: &Q, f: F) -> &K + where + K: Borrow + Ord, + Q: Ord, + F: FnOnce(&Q) -> K, + { + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = + map.root.get_or_insert_with(|| Root::new((*map.alloc).clone())).borrow_mut(); + match root_node.search_tree(q) { + Found(handle) => handle.into_kv_mut().0, + GoDown(handle) => { + let key = f(q); + assert!(*key.borrow() == *q, "new value is not equal"); + VacantEntry { + key, + handle: Some(handle), + dormant_map, + alloc: (*map.alloc).clone(), + _marker: PhantomData, + } + .insert_entry(SetValZST) + .into_key() + } + } + } } /// An iterator over the entries of a `BTreeMap`. diff --git a/alloc/src/collections/btree/map/entry.rs b/alloc/src/collections/btree/map/entry.rs index 0da6af54bc22b..ea8fa363c3805 100644 --- a/alloc/src/collections/btree/map/entry.rs +++ b/alloc/src/collections/btree/map/entry.rs @@ -449,6 +449,11 @@ impl<'a, K: Ord, V, A: Allocator + Clone> OccupiedEntry<'a, K, V, A> { self.handle.reborrow().into_kv().0 } + /// Converts the entry into a reference to its key. + pub(crate) fn into_key(self) -> &'a K { + self.handle.into_kv_mut().0 + } + /// Take ownership of the key and value from the map. /// /// # Examples diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 8daee6030c270..9b7c345e0c319 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -7,12 +7,17 @@ use core::iter::{FusedIterator, Peekable}; use core::mem::ManuallyDrop; use core::ops::{BitAnd, BitOr, BitXor, Bound, RangeBounds, Sub}; -use super::map::{BTreeMap, Keys}; +use super::map::{self, BTreeMap, Keys}; use super::merge_iter::MergeIterInner; use super::set_val::SetValZST; use crate::alloc::{Allocator, Global}; use crate::vec::Vec; +mod entry; + +#[unstable(feature = "btree_set_entry", issue = "none")] +pub use self::entry::{Entry, OccupiedEntry, VacantEntry}; + /// An ordered set based on a B-Tree. /// /// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance @@ -928,6 +933,79 @@ impl BTreeSet { self.map.replace(value) } + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::from([1, 2, 3]); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn get_or_insert(&mut self, value: T) -> &T + where + T: Ord, + { + self.map.entry(value).insert_entry(SetValZST).into_key() + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// + /// let mut set: BTreeSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + T: Borrow + Ord, + Q: Ord, + F: FnOnce(&Q) -> T, + { + self.map.get_or_insert_with(value, f) + } + + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// TODO + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn entry(&mut self, value: T) -> Entry<'_, T, A> + where + T: Ord, + { + match self.map.entry(value) { + map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }), + map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }), + } + } + /// If the set contains an element equal to the value, removes it from the /// set and drops it. Returns whether such an element was present. /// diff --git a/alloc/src/collections/btree/set/entry.rs b/alloc/src/collections/btree/set/entry.rs new file mode 100644 index 0000000000000..4f2b0282a2da7 --- /dev/null +++ b/alloc/src/collections/btree/set/entry.rs @@ -0,0 +1,388 @@ +use core::fmt::{self, Debug}; + +use Entry::*; + +use super::{SetValZST, map}; +use crate::alloc::{Allocator, Global}; + +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`BTreeSet`]. +/// +/// [`BTreeSet`]: super::BTreeSet +/// [`entry`]: super::BTreeSet::entry +/// +/// # Examples +/// +/// ``` +/// #![feature(btree_set_entry)] +/// +/// use std::collections::btree_set::BTreeSet; +/// +/// let mut set = BTreeSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry = set.entry("a"); +/// let _raw_o = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our BTreeSet: {:?}", set); +/// assert!(set.iter().eq(&["a", "b", "c", "d", "e"])); +/// ``` +#[unstable(feature = "btree_set_entry", issue = "none")] +pub enum Entry< + 'a, + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, +> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::btree_set::{Entry, BTreeSet}; + /// + /// let mut set = BTreeSet::from(["a", "b"]); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + #[unstable(feature = "btree_set_entry", issue = "none")] + Occupied(OccupiedEntry<'a, T, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::btree_set::{Entry, BTreeSet}; + /// + /// let mut set = BTreeSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + #[unstable(feature = "btree_set_entry", issue = "none")] + Vacant(VacantEntry<'a, T, A>), +} + +#[unstable(feature = "btree_set_entry", issue = "none")] +impl Debug for Entry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `BTreeSet`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// #![feature(btree_set_entry)] +/// +/// use std::collections::btree_set::{Entry, BTreeSet}; +/// +/// let mut set = BTreeSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +#[unstable(feature = "btree_set_entry", issue = "none")] +pub struct OccupiedEntry< + 'a, + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, +> { + pub(super) inner: map::OccupiedEntry<'a, T, SetValZST, A>, +} + +#[unstable(feature = "btree_set_entry", issue = "none")] +impl Debug for OccupiedEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry").field("value", self.get()).finish() + } +} + +/// A view into a vacant entry in a `BTreeSet`. +/// It is part of the [`Entry`] enum. +/// +/// # Examples +/// +/// ``` +/// #![feature(btree_set_entry)] +/// +/// use std::collections::btree_set::{Entry, BTreeSet}; +/// +/// let mut set = BTreeSet::<&str>::new(); +/// +/// let entry_v = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => view.insert(), +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +#[unstable(feature = "btree_set_entry", issue = "none")] +pub struct VacantEntry< + 'a, + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, +> { + pub(super) inner: map::VacantEntry<'a, T, SetValZST, A>, +} + +#[unstable(feature = "btree_set_entry", issue = "none")] +impl Debug for VacantEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T: Ord, A: Allocator + Clone> Entry<'a, T, A> { + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn insert(self) -> OccupiedEntry<'a, T, A> { + match self { + Occupied(entry) => entry, + Vacant(entry) => entry.insert_entry(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn or_insert(self) { + if let Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn get(&self) -> &T { + match *self { + Occupied(ref entry) => entry.get(), + Vacant(ref entry) => entry.get(), + } + } +} + +impl<'a, T: Ord, A: Allocator + Clone> OccupiedEntry<'a, T, A> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::btree_set::{Entry, BTreeSet}; + /// + /// let mut set = BTreeSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// use std::collections::btree_set::Entry; + /// + /// let mut set = BTreeSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn remove(self) -> T { + self.inner.remove_entry().0 + } +} + +impl<'a, T: Ord, A: Allocator + Clone> VacantEntry<'a, T, A> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::btree_set::{Entry, BTreeSet}; + /// + /// let mut set = BTreeSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn into_value(self) -> T { + self.inner.into_key() + } + + /// Sets the value of the entry with the VacantEntry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// use std::collections::btree_set::Entry; + /// + /// let mut set = BTreeSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[inline] + #[unstable(feature = "btree_set_entry", issue = "none")] + pub fn insert(self) { + self.inner.insert(SetValZST); + } + + #[inline] + fn insert_entry(self) -> OccupiedEntry<'a, T, A> { + OccupiedEntry { inner: self.inner.insert_entry(SetValZST) } + } +} From 88fa7fa1314548e43507b7c0594689a293655b4a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 27 Nov 2024 11:43:05 -0800 Subject: [PATCH 034/481] Add a tracking issue for `btree_set_entry` --- alloc/src/collections/btree/set.rs | 8 +++--- alloc/src/collections/btree/set/entry.rs | 32 ++++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 9b7c345e0c319..a9c64fd41d52a 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -15,7 +15,7 @@ use crate::vec::Vec; mod entry; -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] pub use self::entry::{Entry, OccupiedEntry, VacantEntry}; /// An ordered set based on a B-Tree. @@ -950,7 +950,7 @@ impl BTreeSet { /// assert_eq!(set.len(), 4); // 100 was inserted /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn get_or_insert(&mut self, value: T) -> &T where T: Ord, @@ -979,7 +979,7 @@ impl BTreeSet { /// assert_eq!(set.len(), 4); // a new "fish" was inserted /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T where T: Borrow + Ord, @@ -995,7 +995,7 @@ impl BTreeSet { /// /// TODO #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn entry(&mut self, value: T) -> Entry<'_, T, A> where T: Ord, diff --git a/alloc/src/collections/btree/set/entry.rs b/alloc/src/collections/btree/set/entry.rs index 4f2b0282a2da7..a60d22f9ece71 100644 --- a/alloc/src/collections/btree/set/entry.rs +++ b/alloc/src/collections/btree/set/entry.rs @@ -38,7 +38,7 @@ use crate::alloc::{Allocator, Global}; /// println!("Our BTreeSet: {:?}", set); /// assert!(set.iter().eq(&["a", "b", "c", "d", "e"])); /// ``` -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] pub enum Entry< 'a, T, @@ -60,7 +60,7 @@ pub enum Entry< /// Entry::Occupied(_) => { } /// } /// ``` - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] Occupied(OccupiedEntry<'a, T, A>), /// A vacant entry. @@ -79,11 +79,11 @@ pub enum Entry< /// Entry::Vacant(_) => { } /// } /// ``` - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] Vacant(VacantEntry<'a, T, A>), } -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] impl Debug for Entry<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -129,7 +129,7 @@ impl Debug for Entry<'_, T, A> { /// assert_eq!(set.get(&"c"), None); /// assert_eq!(set.len(), 2); /// ``` -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] pub struct OccupiedEntry< 'a, T, @@ -138,7 +138,7 @@ pub struct OccupiedEntry< pub(super) inner: map::OccupiedEntry<'a, T, SetValZST, A>, } -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] impl Debug for OccupiedEntry<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry").field("value", self.get()).finish() @@ -171,7 +171,7 @@ impl Debug for OccupiedEntry<'_, T, A> { /// } /// assert!(set.contains("b") && set.len() == 2); /// ``` -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] pub struct VacantEntry< 'a, T, @@ -180,7 +180,7 @@ pub struct VacantEntry< pub(super) inner: map::VacantEntry<'a, T, SetValZST, A>, } -#[unstable(feature = "btree_set_entry", issue = "none")] +#[unstable(feature = "btree_set_entry", issue = "133549")] impl Debug for VacantEntry<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.get()).finish() @@ -203,7 +203,7 @@ impl<'a, T: Ord, A: Allocator + Clone> Entry<'a, T, A> { /// assert_eq!(entry.get(), &"horseyland"); /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn insert(self) -> OccupiedEntry<'a, T, A> { match self { Occupied(entry) => entry, @@ -232,7 +232,7 @@ impl<'a, T: Ord, A: Allocator + Clone> Entry<'a, T, A> { /// assert_eq!(set.len(), 1); /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn or_insert(self) { if let Vacant(entry) = self { entry.insert(); @@ -257,7 +257,7 @@ impl<'a, T: Ord, A: Allocator + Clone> Entry<'a, T, A> { /// assert_eq!(set.entry("horseland").get(), &"horseland"); /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn get(&self) -> &T { match *self { Occupied(ref entry) => entry.get(), @@ -285,7 +285,7 @@ impl<'a, T: Ord, A: Allocator + Clone> OccupiedEntry<'a, T, A> { /// } /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn get(&self) -> &T { self.inner.key() } @@ -310,7 +310,7 @@ impl<'a, T: Ord, A: Allocator + Clone> OccupiedEntry<'a, T, A> { /// assert_eq!(set.contains("poneyland"), false); /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn remove(self) -> T { self.inner.remove_entry().0 } @@ -331,7 +331,7 @@ impl<'a, T: Ord, A: Allocator + Clone> VacantEntry<'a, T, A> { /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn get(&self) -> &T { self.inner.key() } @@ -353,7 +353,7 @@ impl<'a, T: Ord, A: Allocator + Clone> VacantEntry<'a, T, A> { /// } /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn into_value(self) -> T { self.inner.into_key() } @@ -376,7 +376,7 @@ impl<'a, T: Ord, A: Allocator + Clone> VacantEntry<'a, T, A> { /// assert!(set.contains("poneyland")); /// ``` #[inline] - #[unstable(feature = "btree_set_entry", issue = "none")] + #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn insert(self) { self.inner.insert(SetValZST); } From 5e835448813bc9dbc0dc6f307659f9c11dd3871e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 27 Nov 2024 12:22:21 -0800 Subject: [PATCH 035/481] Fill in a `BTreeSet::entry` example --- alloc/src/collections/btree/set.rs | 32 +++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index a9c64fd41d52a..6f8c3b2d152b8 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -993,7 +993,37 @@ impl BTreeSet { /// /// # Examples /// - /// TODO + /// ``` + /// #![feature(btree_set_entry)] + /// + /// use std::collections::BTreeSet; + /// use std::collections::btree_set::Entry::*; + /// + /// let mut singles = BTreeSet::new(); + /// let mut dupes = BTreeSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert() + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` #[inline] #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn entry(&mut self, value: T) -> Entry<'_, T, A> From b5d4f3a068d6aae82fd2bd7299d2c90c9e0f58d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 10:06:58 +0100 Subject: [PATCH 036/481] bump hashbrown version --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 197e0a8fedb8c..36f779d8acbb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,9 +135,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "compiler_builtins", From 8988d101069936c7a9b5b2016f280a6161f8d468 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 28 Oct 2024 16:56:22 +0100 Subject: [PATCH 037/481] std: refactor `pthread`-based synchronization The non-trivial code for `pthread_condvar` is duplicated across the thread parking and the `Mutex`/`Condvar` implementations. This PR moves that code into `sys::pal`, which now exposes a non-movable wrapper type for `pthread_mutex_t` and `pthread_condvar_t`. --- std/src/sys/pal/teeos/mod.rs | 8 + std/src/sys/pal/unix/mod.rs | 1 + std/src/sys/pal/unix/sync/condvar.rs | 172 +++++++++++++++++ std/src/sys/pal/unix/sync/mod.rs | 16 ++ std/src/sys/pal/unix/sync/mutex.rs | 133 +++++++++++++ std/src/sys/sync/condvar/pthread.rs | 210 +++++---------------- std/src/sys/sync/condvar/sgx.rs | 8 +- std/src/sys/sync/mutex/pthread.rs | 157 +++------------ std/src/sys/sync/mutex/sgx.rs | 4 +- std/src/sys/sync/once_box.rs | 25 +-- std/src/sys/sync/thread_parking/pthread.rs | 167 ++++------------ 11 files changed, 463 insertions(+), 438 deletions(-) create mode 100644 std/src/sys/pal/unix/sync/condvar.rs create mode 100644 std/src/sys/pal/unix/sync/mod.rs create mode 100644 std/src/sys/pal/unix/sync/mutex.rs diff --git a/std/src/sys/pal/teeos/mod.rs b/std/src/sys/pal/teeos/mod.rs index 60a227afb84e3..2bf2e2ceb314d 100644 --- a/std/src/sys/pal/teeos/mod.rs +++ b/std/src/sys/pal/teeos/mod.rs @@ -27,6 +27,14 @@ pub mod thread; #[path = "../unix/time.rs"] pub mod time; +#[path = "../unix/sync"] +pub mod sync { + mod condvar; + mod mutex; + pub use condvar::Condvar; + pub use mutex::Mutex; +} + use crate::io::ErrorKind; pub fn abort_internal() -> ! { diff --git a/std/src/sys/pal/unix/mod.rs b/std/src/sys/pal/unix/mod.rs index 4fe18daa2040f..8eaa50d7f81d2 100644 --- a/std/src/sys/pal/unix/mod.rs +++ b/std/src/sys/pal/unix/mod.rs @@ -27,6 +27,7 @@ pub mod pipe; pub mod process; pub mod stack_overflow; pub mod stdio; +pub mod sync; pub mod thread; pub mod thread_parking; pub mod time; diff --git a/std/src/sys/pal/unix/sync/condvar.rs b/std/src/sys/pal/unix/sync/condvar.rs new file mode 100644 index 0000000000000..13eeba9c88071 --- /dev/null +++ b/std/src/sys/pal/unix/sync/condvar.rs @@ -0,0 +1,172 @@ +use super::Mutex; +use crate::cell::UnsafeCell; +use crate::pin::Pin; +#[cfg(not(target_os = "nto"))] +use crate::sys::pal::time::TIMESPEC_MAX; +#[cfg(target_os = "nto")] +use crate::sys::pal::time::TIMESPEC_MAX_CAPPED; +use crate::sys::pal::time::Timespec; +use crate::time::Duration; + +pub struct Condvar { + inner: UnsafeCell, +} + +impl Condvar { + pub fn new() -> Condvar { + Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } + } + + #[inline] + fn raw(&self) -> *mut libc::pthread_cond_t { + self.inner.get() + } + + /// # Safety + /// `init` must have been called. + #[inline] + pub unsafe fn notify_one(self: Pin<&Self>) { + let r = unsafe { libc::pthread_cond_signal(self.raw()) }; + debug_assert_eq!(r, 0); + } + + /// # Safety + /// `init` must have been called. + #[inline] + pub unsafe fn notify_all(self: Pin<&Self>) { + let r = unsafe { libc::pthread_cond_broadcast(self.raw()) }; + debug_assert_eq!(r, 0); + } + + /// # Safety + /// * `init` must have been called. + /// * `mutex` must be locked by the current thread. + /// * This condition variable may only be used with the same mutex. + #[inline] + pub unsafe fn wait(self: Pin<&Self>, mutex: Pin<&Mutex>) { + let r = unsafe { libc::pthread_cond_wait(self.raw(), mutex.raw()) }; + debug_assert_eq!(r, 0); + } + + /// # Safety + /// * `init` must have been called. + /// * `mutex` must be locked by the current thread. + /// * This condition variable may only be used with the same mutex. + pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool { + let mutex = mutex.raw(); + + // OSX implementation of `pthread_cond_timedwait` is buggy + // with super long durations. When duration is greater than + // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` + // in macOS Sierra returns error 316. + // + // This program demonstrates the issue: + // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c + // + // To work around this issue, the timeout is clamped to 1000 years. + #[cfg(target_vendor = "apple")] + let dur = Duration::min(dur, Duration::from_secs(1000 * 365 * 86400)); + + let timeout = Timespec::now(Self::CLOCK).checked_add_duration(&dur); + + #[cfg(not(target_os = "nto"))] + let timeout = timeout.and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX); + + #[cfg(target_os = "nto")] + let timeout = timeout.and_then(|t| t.to_timespec_capped()).unwrap_or(TIMESPEC_MAX_CAPPED); + + let r = unsafe { libc::pthread_cond_timedwait(self.raw(), mutex, &timeout) }; + assert!(r == libc::ETIMEDOUT || r == 0); + r == 0 + } +} + +#[cfg(not(any( + target_os = "android", + target_vendor = "apple", + target_os = "espidf", + target_os = "horizon", + target_os = "l4re", + target_os = "redox", + target_os = "teeos", +)))] +impl Condvar { + pub const PRECISE_TIMEOUT: bool = true; + const CLOCK: libc::clockid_t = libc::CLOCK_MONOTONIC; + + /// # Safety + /// May only be called once. + pub unsafe fn init(self: Pin<&mut Self>) { + use crate::mem::MaybeUninit; + + struct AttrGuard<'a>(pub &'a mut MaybeUninit); + impl Drop for AttrGuard<'_> { + fn drop(&mut self) { + unsafe { + let result = libc::pthread_condattr_destroy(self.0.as_mut_ptr()); + assert_eq!(result, 0); + } + } + } + + unsafe { + let mut attr = MaybeUninit::::uninit(); + let r = libc::pthread_condattr_init(attr.as_mut_ptr()); + assert_eq!(r, 0); + let attr = AttrGuard(&mut attr); + let r = libc::pthread_condattr_setclock(attr.0.as_mut_ptr(), Self::CLOCK); + assert_eq!(r, 0); + let r = libc::pthread_cond_init(self.raw(), attr.0.as_ptr()); + assert_eq!(r, 0); + } + } +} + +// `pthread_condattr_setclock` is unfortunately not supported on these platforms. +#[cfg(any( + target_os = "android", + target_vendor = "apple", + target_os = "espidf", + target_os = "horizon", + target_os = "l4re", + target_os = "redox", + target_os = "teeos", +))] +impl Condvar { + pub const PRECISE_TIMEOUT: bool = false; + const CLOCK: libc::clockid_t = libc::CLOCK_REALTIME; + + /// # Safety + /// May only be called once. + pub unsafe fn init(self: Pin<&mut Self>) { + if cfg!(any(target_os = "espidf", target_os = "horizon", target_os = "teeos")) { + // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet + // So on that platform, init() should always be called. + // + // Similar story for the 3DS (horizon) and for TEEOS. + let r = unsafe { libc::pthread_cond_init(self.raw(), crate::ptr::null()) }; + assert_eq!(r, 0); + } + } +} + +impl !Unpin for Condvar {} + +unsafe impl Sync for Condvar {} +unsafe impl Send for Condvar {} + +impl Drop for Condvar { + #[inline] + fn drop(&mut self) { + let r = unsafe { libc::pthread_cond_destroy(self.raw()) }; + if cfg!(target_os = "dragonfly") { + // On DragonFly pthread_cond_destroy() returns EINVAL if called on + // a condvar that was just initialized with + // libc::PTHREAD_COND_INITIALIZER. Once it is used or + // pthread_cond_init() is called, this behaviour no longer occurs. + debug_assert!(r == 0 || r == libc::EINVAL); + } else { + debug_assert_eq!(r, 0); + } + } +} diff --git a/std/src/sys/pal/unix/sync/mod.rs b/std/src/sys/pal/unix/sync/mod.rs new file mode 100644 index 0000000000000..b430ff5d8ef5f --- /dev/null +++ b/std/src/sys/pal/unix/sync/mod.rs @@ -0,0 +1,16 @@ +#![cfg(not(any( + target_os = "linux", + target_os = "android", + all(target_os = "emscripten", target_feature = "atomics"), + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "fuchsia", +)))] +#![forbid(unsafe_op_in_unsafe_fn)] + +mod condvar; +mod mutex; + +pub use condvar::Condvar; +pub use mutex::Mutex; diff --git a/std/src/sys/pal/unix/sync/mutex.rs b/std/src/sys/pal/unix/sync/mutex.rs new file mode 100644 index 0000000000000..8ffd375bf91bd --- /dev/null +++ b/std/src/sys/pal/unix/sync/mutex.rs @@ -0,0 +1,133 @@ +use super::super::cvt_nz; +use crate::cell::UnsafeCell; +use crate::io::Error; +use crate::mem::MaybeUninit; +use crate::pin::Pin; + +pub struct Mutex { + inner: UnsafeCell, +} + +impl Mutex { + pub fn new() -> Mutex { + Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } + } + + pub(super) fn raw(&self) -> *mut libc::pthread_mutex_t { + self.inner.get() + } + + /// # Safety + /// Must only be called once. + pub unsafe fn init(self: Pin<&mut Self>) { + // Issue #33770 + // + // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have + // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you + // try to re-lock it from the same thread when you already hold a lock + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). + // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that + // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same + // as setting it to `PTHREAD_MUTEX_NORMAL`, but not setting any mode will result in + // a Mutex where re-locking is UB. + // + // In practice, glibc takes advantage of this undefined behavior to + // implement hardware lock elision, which uses hardware transactional + // memory to avoid acquiring the lock. While a transaction is in + // progress, the lock appears to be unlocked. This isn't a problem for + // other threads since the transactional memory will abort if a conflict + // is detected, however no abort is generated when re-locking from the + // same thread. + // + // Since locking the same mutex twice will result in two aliasing &mut + // references, we instead create the mutex with type + // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to + // re-lock it from the same thread, thus avoiding undefined behavior. + unsafe { + let mut attr = MaybeUninit::::uninit(); + cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap(); + let attr = AttrGuard(&mut attr); + cvt_nz(libc::pthread_mutexattr_settype( + attr.0.as_mut_ptr(), + libc::PTHREAD_MUTEX_NORMAL, + )) + .unwrap(); + cvt_nz(libc::pthread_mutex_init(self.raw(), attr.0.as_ptr())).unwrap(); + } + } + + /// # Safety + /// * If `init` was not called, reentrant locking causes undefined behaviour. + /// * Destroying a locked mutex causes undefined behaviour. + pub unsafe fn lock(self: Pin<&Self>) { + #[cold] + #[inline(never)] + fn fail(r: i32) -> ! { + let error = Error::from_raw_os_error(r); + panic!("failed to lock mutex: {error}"); + } + + let r = unsafe { libc::pthread_mutex_lock(self.raw()) }; + // As we set the mutex type to `PTHREAD_MUTEX_NORMAL` above, we expect + // the lock call to never fail. Unfortunately however, some platforms + // (Solaris) do not conform to the standard, and instead always provide + // deadlock detection. How kind of them! Unfortunately that means that + // we need to check the error code here. To save us from UB on other + // less well-behaved platforms in the future, we do it even on "good" + // platforms like macOS. See #120147 for more context. + if r != 0 { + fail(r) + } + } + + /// # Safety + /// * If `init` was not called, reentrant locking causes undefined behaviour. + /// * Destroying a locked mutex causes undefined behaviour. + pub unsafe fn try_lock(self: Pin<&Self>) -> bool { + unsafe { libc::pthread_mutex_trylock(self.raw()) == 0 } + } + + /// # Safety + /// The mutex must be locked by the current thread. + pub unsafe fn unlock(self: Pin<&Self>) { + let r = unsafe { libc::pthread_mutex_unlock(self.raw()) }; + debug_assert_eq!(r, 0); + } +} + +impl !Unpin for Mutex {} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +impl Drop for Mutex { + fn drop(&mut self) { + // SAFETY: + // If `lock` or `init` was called, the mutex must have been pinned, so + // it is still at the same location. Otherwise, `inner` must contain + // `PTHREAD_MUTEX_INITIALIZER`, which is valid at all locations. Thus, + // this call always destroys a valid mutex. + let r = unsafe { libc::pthread_mutex_destroy(self.raw()) }; + if cfg!(target_os = "dragonfly") { + // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a + // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. + // Once it is used (locked/unlocked) or pthread_mutex_init() is called, + // this behaviour no longer occurs. + debug_assert!(r == 0 || r == libc::EINVAL); + } else { + debug_assert_eq!(r, 0); + } + } +} + +struct AttrGuard<'a>(pub &'a mut MaybeUninit); + +impl Drop for AttrGuard<'_> { + fn drop(&mut self) { + unsafe { + let result = libc::pthread_mutexattr_destroy(self.0.as_mut_ptr()); + assert_eq!(result, 0); + } + } +} diff --git a/std/src/sys/sync/condvar/pthread.rs b/std/src/sys/sync/condvar/pthread.rs index cee728e35cdfc..4d2f9c0aaba48 100644 --- a/std/src/sys/sync/condvar/pthread.rs +++ b/std/src/sys/sync/condvar/pthread.rs @@ -1,196 +1,88 @@ -use crate::cell::UnsafeCell; +#![forbid(unsafe_op_in_unsafe_fn)] + +use crate::pin::Pin; use crate::ptr; -use crate::sync::atomic::AtomicPtr; +use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::Relaxed; +use crate::sys::pal::sync as pal; use crate::sys::sync::{Mutex, OnceBox}; -#[cfg(not(target_os = "nto"))] -use crate::sys::time::TIMESPEC_MAX; -#[cfg(target_os = "nto")] -use crate::sys::time::TIMESPEC_MAX_CAPPED; -use crate::time::Duration; - -struct AllocatedCondvar(UnsafeCell); +use crate::time::{Duration, Instant}; pub struct Condvar { - inner: OnceBox, - mutex: AtomicPtr, -} - -unsafe impl Send for AllocatedCondvar {} -unsafe impl Sync for AllocatedCondvar {} - -impl AllocatedCondvar { - fn new() -> Box { - let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); - - cfg_if::cfg_if! { - if #[cfg(any( - target_os = "l4re", - target_os = "android", - target_os = "redox", - target_vendor = "apple", - ))] { - // `pthread_condattr_setclock` is unfortunately not supported on these platforms. - } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "teeos"))] { - // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet - // So on that platform, init() should always be called - // Moreover, that platform does not have pthread_condattr_setclock support, - // hence that initialization should be skipped as well - // - // Similar story for the 3DS (horizon). - let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) }; - assert_eq!(r, 0); - } else { - use crate::mem::MaybeUninit; - let mut attr = MaybeUninit::::uninit(); - let r = unsafe { libc::pthread_condattr_init(attr.as_mut_ptr()) }; - assert_eq!(r, 0); - let r = unsafe { libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC) }; - assert_eq!(r, 0); - let r = unsafe { libc::pthread_cond_init(condvar.0.get(), attr.as_ptr()) }; - assert_eq!(r, 0); - let r = unsafe { libc::pthread_condattr_destroy(attr.as_mut_ptr()) }; - assert_eq!(r, 0); - } - } - - condvar - } -} - -impl Drop for AllocatedCondvar { - #[inline] - fn drop(&mut self) { - let r = unsafe { libc::pthread_cond_destroy(self.0.get()) }; - if cfg!(target_os = "dragonfly") { - // On DragonFly pthread_cond_destroy() returns EINVAL if called on - // a condvar that was just initialized with - // libc::PTHREAD_COND_INITIALIZER. Once it is used or - // pthread_cond_init() is called, this behavior no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - } + cvar: OnceBox, + mutex: AtomicUsize, } impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: OnceBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } + Condvar { cvar: OnceBox::new(), mutex: AtomicUsize::new(0) } } - fn get(&self) -> *mut libc::pthread_cond_t { - self.inner.get_or_init(AllocatedCondvar::new).0.get() + #[inline] + fn get(&self) -> Pin<&pal::Condvar> { + self.cvar.get_or_init(|| { + let mut cvar = Box::pin(pal::Condvar::new()); + // SAFETY: we only call `init` once, namely here. + unsafe { cvar.as_mut().init() }; + cvar + }) } #[inline] - fn verify(&self, mutex: *mut libc::pthread_mutex_t) { - // Relaxed is okay here because we never read through `self.addr`, and only use it to + fn verify(&self, mutex: Pin<&pal::Mutex>) { + let addr = ptr::from_ref::(&mutex).addr(); + // Relaxed is okay here because we never read through `self.mutex`, and only use it to // compare addresses. - match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) { - Ok(_) => {} // Stored the address - Err(n) if n == mutex => {} // Lost a race to store the same address + match self.mutex.compare_exchange(0, addr, Relaxed, Relaxed) { + Ok(_) => {} // Stored the address + Err(n) if n == addr => {} // Lost a race to store the same address _ => panic!("attempted to use a condition variable with two mutexes"), } } #[inline] pub fn notify_one(&self) { - let r = unsafe { libc::pthread_cond_signal(self.get()) }; - debug_assert_eq!(r, 0); + // SAFETY: we called `init` above. + unsafe { self.get().notify_one() } } #[inline] pub fn notify_all(&self) { - let r = unsafe { libc::pthread_cond_broadcast(self.get()) }; - debug_assert_eq!(r, 0); + // SAFETY: we called `init` above. + unsafe { self.get().notify_all() } } #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex.get_assert_locked(); + // SAFETY: the caller guarantees that the lock is owned, thus the mutex + // must have been initialized already. + let mutex = unsafe { mutex.pal.get_unchecked() }; self.verify(mutex); - let r = libc::pthread_cond_wait(self.get(), mutex); - debug_assert_eq!(r, 0); + // SAFETY: we called `init` above, we verified that this condition + // variable is only used with `mutex` and the caller guarantees that + // `mutex` is locked by the current thread. + unsafe { self.get().wait(mutex) } } - // This implementation is used on systems that support pthread_condattr_setclock - // where we configure condition variable to use monotonic clock (instead of - // default system clock). This approach avoids all problems that result - // from changes made to the system time. - #[cfg(not(any( - target_os = "android", - target_os = "espidf", - target_os = "horizon", - target_vendor = "apple", - )))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::sys::time::Timespec; - - let mutex = mutex.get_assert_locked(); + // SAFETY: the caller guarantees that the lock is owned, thus the mutex + // must have been initialized already. + let mutex = unsafe { mutex.pal.get_unchecked() }; self.verify(mutex); - #[cfg(not(target_os = "nto"))] - let timeout = Timespec::now(libc::CLOCK_MONOTONIC) - .checked_add_duration(&dur) - .and_then(|t| t.to_timespec()) - .unwrap_or(TIMESPEC_MAX); - - #[cfg(target_os = "nto")] - let timeout = Timespec::now(libc::CLOCK_MONOTONIC) - .checked_add_duration(&dur) - .and_then(|t| t.to_timespec_capped()) - .unwrap_or(TIMESPEC_MAX_CAPPED); - - let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout); - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } - - // This implementation is modeled after libcxx's condition_variable - // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 - // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 - #[cfg(any( - target_os = "android", - target_os = "espidf", - target_os = "horizon", - target_vendor = "apple", - ))] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::sys::time::SystemTime; - use crate::time::Instant; - - let mutex = mutex.get_assert_locked(); - self.verify(mutex); - - // OSX implementation of `pthread_cond_timedwait` is buggy - // with super long durations. When duration is greater than - // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` - // in macOS Sierra returns error 316. - // - // This program demonstrates the issue: - // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c - // - // To work around this issue, and possible bugs of other OSes, timeout - // is clamped to 1000 years, which is allowable per the API of `wait_timeout` - // because of spurious wakeups. - let dur = Duration::min(dur, Duration::from_secs(1000 * 365 * 86400)); - - // pthread_cond_timedwait uses system time, but we want to report timeout - // based on stable time. - let now = Instant::now(); - - let timeout = SystemTime::now() - .t - .checked_add_duration(&dur) - .and_then(|t| t.to_timespec()) - .unwrap_or(TIMESPEC_MAX); - - let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout); - debug_assert!(r == libc::ETIMEDOUT || r == 0); - - // ETIMEDOUT is not a totally reliable method of determining timeout due - // to clock shifts, so do the check ourselves - now.elapsed() < dur + if pal::Condvar::PRECISE_TIMEOUT { + // SAFETY: we called `init` above, we verified that this condition + // variable is only used with `mutex` and the caller guarantees that + // `mutex` is locked by the current thread. + unsafe { self.get().wait_timeout(mutex, dur) } + } else { + // Timeout reports are not reliable, so do the check ourselves. + let now = Instant::now(); + // SAFETY: we called `init` above, we verified that this condition + // variable is only used with `mutex` and the caller guarantees that + // `mutex` is locked by the current thread. + let woken = unsafe { self.get().wait_timeout(mutex, dur) }; + woken || now.elapsed() < dur + } } } diff --git a/std/src/sys/sync/condvar/sgx.rs b/std/src/sys/sync/condvar/sgx.rs index e60715e4b592e..2bde9d0694eda 100644 --- a/std/src/sys/sync/condvar/sgx.rs +++ b/std/src/sys/sync/condvar/sgx.rs @@ -13,17 +13,19 @@ impl Condvar { } fn get(&self) -> &SpinMutex> { - self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(())))) + self.inner.get_or_init(|| Box::pin(SpinMutex::new(WaitVariable::new(())))).get_ref() } #[inline] pub fn notify_one(&self) { - let _ = WaitQueue::notify_one(self.get().lock()); + let guard = self.get().lock(); + let _ = WaitQueue::notify_one(guard); } #[inline] pub fn notify_all(&self) { - let _ = WaitQueue::notify_all(self.get().lock()); + let guard = self.get().lock(); + let _ = WaitQueue::notify_all(guard); } pub unsafe fn wait(&self, mutex: &Mutex) { diff --git a/std/src/sys/sync/mutex/pthread.rs b/std/src/sys/sync/mutex/pthread.rs index abd58122523cf..5719bb10f7f96 100644 --- a/std/src/sys/sync/mutex/pthread.rs +++ b/std/src/sys/sync/mutex/pthread.rs @@ -1,163 +1,66 @@ -use crate::cell::UnsafeCell; -use crate::io::Error; -use crate::mem::{MaybeUninit, forget}; -use crate::sys::cvt_nz; -use crate::sys::sync::OnceBox; +#![forbid(unsafe_op_in_unsafe_fn)] -struct AllocatedMutex(UnsafeCell); +use crate::mem::forget; +use crate::pin::Pin; +use crate::sys::pal::sync as pal; +use crate::sys::sync::OnceBox; pub struct Mutex { - inner: OnceBox, -} - -unsafe impl Send for AllocatedMutex {} -unsafe impl Sync for AllocatedMutex {} - -impl AllocatedMutex { - fn new() -> Box { - let mutex = Box::new(AllocatedMutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))); - - // Issue #33770 - // - // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have - // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock - // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). - // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL - // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that - // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same - // as setting it to `PTHREAD_MUTEX_NORMAL`, but not setting any mode will result in - // a Mutex where re-locking is UB. - // - // In practice, glibc takes advantage of this undefined behavior to - // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. While a transaction is in - // progress, the lock appears to be unlocked. This isn't a problem for - // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated when re-locking from the - // same thread. - // - // Since locking the same mutex twice will result in two aliasing &mut - // references, we instead create the mutex with type - // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to - // re-lock it from the same thread, thus avoiding undefined behavior. - unsafe { - let mut attr = MaybeUninit::::uninit(); - cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap(); - let attr = PthreadMutexAttr(&mut attr); - cvt_nz(libc::pthread_mutexattr_settype( - attr.0.as_mut_ptr(), - libc::PTHREAD_MUTEX_NORMAL, - )) - .unwrap(); - cvt_nz(libc::pthread_mutex_init(mutex.0.get(), attr.0.as_ptr())).unwrap(); - } - - mutex - } -} - -impl Drop for AllocatedMutex { - #[inline] - fn drop(&mut self) { - let r = unsafe { libc::pthread_mutex_destroy(self.0.get()) }; - if cfg!(target_os = "dragonfly") { - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behavior no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - } + pub pal: OnceBox, } impl Mutex { #[inline] pub const fn new() -> Mutex { - Mutex { inner: OnceBox::new() } + Mutex { pal: OnceBox::new() } } - /// Gets access to the pthread mutex under the assumption that the mutex is - /// locked. - /// - /// This allows skipping the initialization check, as the mutex can only be - /// locked if it is already initialized, and allows relaxing the ordering - /// on the pointer load, since the allocation cannot have been modified - /// since the `lock` and the lock must have occurred on the current thread. - /// - /// # Safety - /// Causes undefined behavior if the mutex is not locked. #[inline] - pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t { - unsafe { self.inner.get_unchecked().0.get() } - } - - #[inline] - fn get(&self) -> *mut libc::pthread_mutex_t { - // If initialization fails, the mutex is destroyed. This is always sound, - // however, as the mutex cannot have been locked yet. - self.inner.get_or_init(AllocatedMutex::new).0.get() + fn get(&self) -> Pin<&pal::Mutex> { + // If the initialization race is lost, the new mutex is destroyed. + // This is sound however, as it cannot have been locked. + self.pal.get_or_init(|| { + let mut pal = Box::pin(pal::Mutex::new()); + // SAFETY: we only call `init` once, namely here. + unsafe { pal.as_mut().init() }; + pal + }) } #[inline] pub fn lock(&self) { - #[cold] - #[inline(never)] - fn fail(r: i32) -> ! { - let error = Error::from_raw_os_error(r); - panic!("failed to lock mutex: {error}"); - } - - let r = unsafe { libc::pthread_mutex_lock(self.get()) }; - // As we set the mutex type to `PTHREAD_MUTEX_NORMAL` above, we expect - // the lock call to never fail. Unfortunately however, some platforms - // (Solaris) do not conform to the standard, and instead always provide - // deadlock detection. How kind of them! Unfortunately that means that - // we need to check the error code here. To save us from UB on other - // less well-behaved platforms in the future, we do it even on "good" - // platforms like macOS. See #120147 for more context. - if r != 0 { - fail(r) - } + // SAFETY: we call `init` above, therefore reentrant locking is safe. + // In `drop` we ensure that the mutex is not destroyed while locked. + unsafe { self.get().lock() } } #[inline] pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(self.get_assert_locked()); - debug_assert_eq!(r, 0); + // SAFETY: the mutex can only be locked if it is already initialized + // and we observed this initialization since we observed the locking. + unsafe { self.pal.get_unchecked().unlock() } } #[inline] pub fn try_lock(&self) -> bool { - unsafe { libc::pthread_mutex_trylock(self.get()) == 0 } + // SAFETY: we call `init` above, therefore reentrant locking is safe. + // In `drop` we ensure that the mutex is not destroyed while locked. + unsafe { self.get().try_lock() } } } impl Drop for Mutex { fn drop(&mut self) { - let Some(mutex) = self.inner.take() else { return }; + let Some(pal) = self.pal.take() else { return }; // We're not allowed to pthread_mutex_destroy a locked mutex, // so check first if it's unlocked. - if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } { - unsafe { libc::pthread_mutex_unlock(mutex.0.get()) }; - drop(mutex); + if unsafe { pal.as_ref().try_lock() } { + unsafe { pal.as_ref().unlock() }; + drop(pal) } else { // The mutex is locked. This happens if a MutexGuard is leaked. // In this case, we just leak the Mutex too. - forget(mutex); - } - } -} - -pub(super) struct PthreadMutexAttr<'a>(pub &'a mut MaybeUninit); - -impl Drop for PthreadMutexAttr<'_> { - fn drop(&mut self) { - unsafe { - let result = libc::pthread_mutexattr_destroy(self.0.as_mut_ptr()); - debug_assert_eq!(result, 0); + forget(pal) } } } diff --git a/std/src/sys/sync/mutex/sgx.rs b/std/src/sys/sync/mutex/sgx.rs index 8529e85797043..3eb981bc65af6 100644 --- a/std/src/sys/sync/mutex/sgx.rs +++ b/std/src/sys/sync/mutex/sgx.rs @@ -13,7 +13,7 @@ impl Mutex { } fn get(&self) -> &SpinMutex> { - self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(false)))) + self.inner.get_or_init(|| Box::pin(SpinMutex::new(WaitVariable::new(false)))).get_ref() } #[inline] @@ -33,7 +33,7 @@ impl Mutex { pub unsafe fn unlock(&self) { // SAFETY: the mutex was locked by the current thread, so it has been // initialized already. - let guard = unsafe { self.inner.get_unchecked().lock() }; + let guard = unsafe { self.inner.get_unchecked().get_ref().lock() }; if let Err(mut guard) = WaitQueue::notify_one(guard) { // No other waiters, unlock *guard.lock_var_mut() = false; diff --git a/std/src/sys/sync/once_box.rs b/std/src/sys/sync/once_box.rs index 4105af503295f..6953b91999ad1 100644 --- a/std/src/sys/sync/once_box.rs +++ b/std/src/sys/sync/once_box.rs @@ -6,6 +6,7 @@ #![allow(dead_code)] // Only used on some platforms. use crate::mem::replace; +use crate::pin::Pin; use crate::ptr::null_mut; use crate::sync::atomic::AtomicPtr; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; @@ -27,46 +28,46 @@ impl OnceBox { /// pointer load in this function can be performed with relaxed ordering, /// potentially allowing the optimizer to turn code like this: /// ```rust, ignore - /// once_box.get_or_init(|| Box::new(42)); + /// once_box.get_or_init(|| Box::pin(42)); /// unsafe { once_box.get_unchecked() } /// ``` /// into /// ```rust, ignore - /// once_box.get_or_init(|| Box::new(42)) + /// once_box.get_or_init(|| Box::pin(42)) /// ``` /// /// # Safety /// This causes undefined behavior if the assumption above is violated. #[inline] - pub unsafe fn get_unchecked(&self) -> &T { - unsafe { &*self.ptr.load(Relaxed) } + pub unsafe fn get_unchecked(&self) -> Pin<&T> { + unsafe { Pin::new_unchecked(&*self.ptr.load(Relaxed)) } } #[inline] - pub fn get_or_init(&self, f: impl FnOnce() -> Box) -> &T { + pub fn get_or_init(&self, f: impl FnOnce() -> Pin>) -> Pin<&T> { let ptr = self.ptr.load(Acquire); match unsafe { ptr.as_ref() } { - Some(val) => val, + Some(val) => unsafe { Pin::new_unchecked(val) }, None => self.initialize(f), } } #[inline] - pub fn take(&mut self) -> Option> { + pub fn take(&mut self) -> Option>> { let ptr = replace(self.ptr.get_mut(), null_mut()); - if !ptr.is_null() { Some(unsafe { Box::from_raw(ptr) }) } else { None } + if !ptr.is_null() { Some(unsafe { Pin::new_unchecked(Box::from_raw(ptr)) }) } else { None } } #[cold] - fn initialize(&self, f: impl FnOnce() -> Box) -> &T { - let new_ptr = Box::into_raw(f()); + fn initialize(&self, f: impl FnOnce() -> Pin>) -> Pin<&T> { + let new_ptr = Box::into_raw(unsafe { Pin::into_inner_unchecked(f()) }); match self.ptr.compare_exchange(null_mut(), new_ptr, Release, Acquire) { - Ok(_) => unsafe { &*new_ptr }, + Ok(_) => unsafe { Pin::new_unchecked(&*new_ptr) }, Err(ptr) => { // Lost the race to another thread. // Drop the value we created, and use the one from the other thread instead. drop(unsafe { Box::from_raw(new_ptr) }); - unsafe { &*ptr } + unsafe { Pin::new_unchecked(&*ptr) } } } } diff --git a/std/src/sys/sync/thread_parking/pthread.rs b/std/src/sys/sync/thread_parking/pthread.rs index 76df73b2a8e06..19cabd7dd75c8 100644 --- a/std/src/sys/sync/thread_parking/pthread.rs +++ b/std/src/sys/sync/thread_parking/pthread.rs @@ -1,93 +1,19 @@ //! Thread parking without `futex` using the `pthread` synchronization primitives. -use crate::cell::UnsafeCell; -use crate::marker::PhantomPinned; use crate::pin::Pin; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -#[cfg(not(target_os = "nto"))] -use crate::sys::time::TIMESPEC_MAX; -#[cfg(target_os = "nto")] -use crate::sys::time::TIMESPEC_MAX_CAPPED; +use crate::sys::pal::sync::{Condvar, Mutex}; use crate::time::Duration; const EMPTY: usize = 0; const PARKED: usize = 1; const NOTIFIED: usize = 2; -unsafe fn lock(lock: *mut libc::pthread_mutex_t) { - let r = libc::pthread_mutex_lock(lock); - debug_assert_eq!(r, 0); -} - -unsafe fn unlock(lock: *mut libc::pthread_mutex_t) { - let r = libc::pthread_mutex_unlock(lock); - debug_assert_eq!(r, 0); -} - -unsafe fn notify_one(cond: *mut libc::pthread_cond_t) { - let r = libc::pthread_cond_signal(cond); - debug_assert_eq!(r, 0); -} - -unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) { - let r = libc::pthread_cond_wait(cond, lock); - debug_assert_eq!(r, 0); -} - -unsafe fn wait_timeout( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, - dur: Duration, -) { - // Use the system clock on systems that do not support pthread_condattr_setclock. - // This unfortunately results in problems when the system time changes. - #[cfg(any(target_os = "espidf", target_os = "horizon", target_vendor = "apple"))] - let (now, dur) = { - use crate::cmp::min; - use crate::sys::time::SystemTime; - - // OSX implementation of `pthread_cond_timedwait` is buggy - // with super long durations. When duration is greater than - // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` - // in macOS Sierra return error 316. - // - // This program demonstrates the issue: - // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c - // - // To work around this issue, and possible bugs of other OSes, timeout - // is clamped to 1000 years, which is allowable per the API of `park_timeout` - // because of spurious wakeups. - let dur = min(dur, Duration::from_secs(1000 * 365 * 86400)); - let now = SystemTime::now().t; - (now, dur) - }; - // Use the monotonic clock on other systems. - #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_vendor = "apple")))] - let (now, dur) = { - use crate::sys::time::Timespec; - - (Timespec::now(libc::CLOCK_MONOTONIC), dur) - }; - - #[cfg(not(target_os = "nto"))] - let timeout = - now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX); - #[cfg(target_os = "nto")] - let timeout = now - .checked_add_duration(&dur) - .and_then(|t| t.to_timespec_capped()) - .unwrap_or(TIMESPEC_MAX_CAPPED); - let r = libc::pthread_cond_timedwait(cond, lock, &timeout); - debug_assert!(r == libc::ETIMEDOUT || r == 0); -} - pub struct Parker { state: AtomicUsize, - lock: UnsafeCell, - cvar: UnsafeCell, - // The `pthread` primitives require a stable address, so make this struct `!Unpin`. - _pinned: PhantomPinned, + lock: Mutex, + cvar: Condvar, } impl Parker { @@ -96,38 +22,21 @@ impl Parker { /// # Safety /// The constructed parker must never be moved. pub unsafe fn new_in_place(parker: *mut Parker) { - // Use the default mutex implementation to allow for simpler initialization. - // This could lead to undefined behavior when deadlocking. This is avoided - // by not deadlocking. Note in particular the unlocking operation before any - // panic, as code after the panic could try to park again. - (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY)); - (&raw mut (*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); + parker.write(Parker { + state: AtomicUsize::new(EMPTY), + lock: Mutex::new(), + cvar: Condvar::new(), + }); - cfg_if::cfg_if! { - if #[cfg(any( - target_os = "l4re", - target_os = "android", - target_os = "redox", - target_os = "vita", - target_vendor = "apple", - ))] { - (&raw mut (*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); - } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { - let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), crate::ptr::null()); - assert_eq!(r, 0); - } else { - use crate::mem::MaybeUninit; - let mut attr = MaybeUninit::::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - assert_eq!(r, 0); - let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), attr.as_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } - } + Pin::new_unchecked(&mut (*parker).cvar).init(); + } + + fn lock(self: Pin<&Self>) -> Pin<&Mutex> { + unsafe { self.map_unchecked(|p| &p.lock) } + } + + fn cvar(self: Pin<&Self>) -> Pin<&Condvar> { + unsafe { self.map_unchecked(|p| &p.cvar) } } // This implementation doesn't require `unsafe`, but other implementations @@ -142,7 +51,7 @@ impl Parker { } // Otherwise we need to coordinate going to sleep - lock(self.lock.get()); + self.lock().lock(); match self.state.compare_exchange(EMPTY, PARKED, Relaxed, Relaxed) { Ok(_) => {} Err(NOTIFIED) => { @@ -154,20 +63,20 @@ impl Parker { // read from the write it made to `state`. let old = self.state.swap(EMPTY, Acquire); - unlock(self.lock.get()); + self.lock().unlock(); assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); return; } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => { - unlock(self.lock.get()); + self.lock().unlock(); panic!("inconsistent park state") } } loop { - wait(self.cvar.get(), self.lock.get()); + self.cvar().wait(self.lock()); match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) { Ok(_) => break, // got a notification @@ -175,7 +84,7 @@ impl Parker { } } - unlock(self.lock.get()); + self.lock().unlock(); } // This implementation doesn't require `unsafe`, but other implementations @@ -189,19 +98,19 @@ impl Parker { return; } - lock(self.lock.get()); + self.lock().lock(); match self.state.compare_exchange(EMPTY, PARKED, Relaxed, Relaxed) { Ok(_) => {} Err(NOTIFIED) => { // We must read again here, see `park`. let old = self.state.swap(EMPTY, Acquire); - unlock(self.lock.get()); + self.lock().unlock(); assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); return; } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => { - unlock(self.lock.get()); + self.lock().unlock(); panic!("inconsistent park_timeout state") } } @@ -210,13 +119,13 @@ impl Parker { // from a notification we just want to unconditionally set the state back to // empty, either consuming a notification or un-flagging ourselves as // parked. - wait_timeout(self.cvar.get(), self.lock.get(), dur); + self.cvar().wait_timeout(self.lock(), dur); match self.state.swap(EMPTY, Acquire) { - NOTIFIED => unlock(self.lock.get()), // got a notification, hurray! - PARKED => unlock(self.lock.get()), // no notification, alas + NOTIFIED => self.lock().unlock(), // got a notification, hurray! + PARKED => self.lock().unlock(), // no notification, alas n => { - unlock(self.lock.get()); + self.lock().unlock(); panic!("inconsistent park_timeout state: {n}") } } @@ -248,21 +157,9 @@ impl Parker { // parked thread wakes it doesn't get woken only to have to wait for us // to release `lock`. unsafe { - lock(self.lock.get()); - unlock(self.lock.get()); - notify_one(self.cvar.get()); + self.lock().lock(); + self.lock().unlock(); + self.cvar().notify_one(); } } } - -impl Drop for Parker { - fn drop(&mut self) { - unsafe { - libc::pthread_cond_destroy(self.cvar.get_mut()); - libc::pthread_mutex_destroy(self.lock.get_mut()); - } - } -} - -unsafe impl Sync for Parker {} -unsafe impl Send for Parker {} From e1883a1c46c669c80fde3ae20a82ac8bbedad6d7 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 30 Nov 2024 16:22:56 +0100 Subject: [PATCH 038/481] std: clarify comments about initialization --- std/src/sys/pal/unix/sync/condvar.rs | 12 ++++++------ std/src/sys/pal/unix/sync/mutex.rs | 8 +++++--- std/src/sys/sync/condvar/pthread.rs | 2 +- std/src/sys/sync/mutex/pthread.rs | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/std/src/sys/pal/unix/sync/condvar.rs b/std/src/sys/pal/unix/sync/condvar.rs index 13eeba9c88071..73631053e9f47 100644 --- a/std/src/sys/pal/unix/sync/condvar.rs +++ b/std/src/sys/pal/unix/sync/condvar.rs @@ -23,7 +23,7 @@ impl Condvar { } /// # Safety - /// `init` must have been called. + /// `init` must have been called on this instance. #[inline] pub unsafe fn notify_one(self: Pin<&Self>) { let r = unsafe { libc::pthread_cond_signal(self.raw()) }; @@ -31,7 +31,7 @@ impl Condvar { } /// # Safety - /// `init` must have been called. + /// `init` must have been called on this instance. #[inline] pub unsafe fn notify_all(self: Pin<&Self>) { let r = unsafe { libc::pthread_cond_broadcast(self.raw()) }; @@ -39,7 +39,7 @@ impl Condvar { } /// # Safety - /// * `init` must have been called. + /// * `init` must have been called on this instance. /// * `mutex` must be locked by the current thread. /// * This condition variable may only be used with the same mutex. #[inline] @@ -49,7 +49,7 @@ impl Condvar { } /// # Safety - /// * `init` must have been called. + /// * `init` must have been called on this instance. /// * `mutex` must be locked by the current thread. /// * This condition variable may only be used with the same mutex. pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool { @@ -95,7 +95,7 @@ impl Condvar { const CLOCK: libc::clockid_t = libc::CLOCK_MONOTONIC; /// # Safety - /// May only be called once. + /// May only be called once per instance of `Self`. pub unsafe fn init(self: Pin<&mut Self>) { use crate::mem::MaybeUninit; @@ -137,7 +137,7 @@ impl Condvar { const CLOCK: libc::clockid_t = libc::CLOCK_REALTIME; /// # Safety - /// May only be called once. + /// May only be called once per instance of `Self`. pub unsafe fn init(self: Pin<&mut Self>) { if cfg!(any(target_os = "espidf", target_os = "horizon", target_os = "teeos")) { // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet diff --git a/std/src/sys/pal/unix/sync/mutex.rs b/std/src/sys/pal/unix/sync/mutex.rs index 8ffd375bf91bd..8ff6c3d3d15da 100644 --- a/std/src/sys/pal/unix/sync/mutex.rs +++ b/std/src/sys/pal/unix/sync/mutex.rs @@ -18,7 +18,7 @@ impl Mutex { } /// # Safety - /// Must only be called once. + /// May only be called once per instance of `Self`. pub unsafe fn init(self: Pin<&mut Self>) { // Issue #33770 // @@ -58,7 +58,8 @@ impl Mutex { } /// # Safety - /// * If `init` was not called, reentrant locking causes undefined behaviour. + /// * If `init` was not called on this instance, reentrant locking causes + /// undefined behaviour. /// * Destroying a locked mutex causes undefined behaviour. pub unsafe fn lock(self: Pin<&Self>) { #[cold] @@ -82,7 +83,8 @@ impl Mutex { } /// # Safety - /// * If `init` was not called, reentrant locking causes undefined behaviour. + /// * If `init` was not called on this instance, reentrant locking causes + /// undefined behaviour. /// * Destroying a locked mutex causes undefined behaviour. pub unsafe fn try_lock(self: Pin<&Self>) -> bool { unsafe { libc::pthread_mutex_trylock(self.raw()) == 0 } diff --git a/std/src/sys/sync/condvar/pthread.rs b/std/src/sys/sync/condvar/pthread.rs index 4d2f9c0aaba48..5bb7431eecf0c 100644 --- a/std/src/sys/sync/condvar/pthread.rs +++ b/std/src/sys/sync/condvar/pthread.rs @@ -22,7 +22,7 @@ impl Condvar { fn get(&self) -> Pin<&pal::Condvar> { self.cvar.get_or_init(|| { let mut cvar = Box::pin(pal::Condvar::new()); - // SAFETY: we only call `init` once, namely here. + // SAFETY: we only call `init` once per `pal::Condvar`, namely here. unsafe { cvar.as_mut().init() }; cvar }) diff --git a/std/src/sys/sync/mutex/pthread.rs b/std/src/sys/sync/mutex/pthread.rs index 5719bb10f7f96..75b4b9c6dad9b 100644 --- a/std/src/sys/sync/mutex/pthread.rs +++ b/std/src/sys/sync/mutex/pthread.rs @@ -21,7 +21,7 @@ impl Mutex { // This is sound however, as it cannot have been locked. self.pal.get_or_init(|| { let mut pal = Box::pin(pal::Mutex::new()); - // SAFETY: we only call `init` once, namely here. + // SAFETY: we only call `init` once per `pal::Mutex`, namely here. unsafe { pal.as_mut().init() }; pal }) From 6acfa1f61e231562265fc802b418665e2089ee57 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 30 Nov 2024 19:04:58 +0800 Subject: [PATCH 039/481] fix: hurd build, stat64.st_fsid was renamed to st_dev --- Cargo.lock | 4 ++-- std/Cargo.toml | 2 +- std/src/os/hurd/fs.rs | 2 +- std/src/sys/pal/unix/os.rs | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36f779d8acbb9..f9b0af2c6e84c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.162" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" dependencies = [ "rustc-std-workspace-core", ] diff --git a/std/Cargo.toml b/std/Cargo.toml index 260732dee188e..ca8b6af056550 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -34,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.162", default-features = false, features = [ +libc = { version = "0.2.167", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } diff --git a/std/src/os/hurd/fs.rs b/std/src/os/hurd/fs.rs index 00ff1560f31d9..e3087fa8af1cc 100644 --- a/std/src/os/hurd/fs.rs +++ b/std/src/os/hurd/fs.rs @@ -298,7 +298,7 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_fsid as u64 + self.as_inner().as_inner().st_dev as u64 } fn st_ino(&self) -> u64 { self.as_inner().as_inner().st_ino as u64 diff --git a/std/src/sys/pal/unix/os.rs b/std/src/sys/pal/unix/os.rs index 789a40c13e61b..b83772e34c173 100644 --- a/std/src/sys/pal/unix/os.rs +++ b/std/src/sys/pal/unix/os.rs @@ -427,11 +427,13 @@ pub fn current_exe() -> io::Result { pub fn current_exe() -> io::Result { unsafe { let mut sz: u32 = 0; + #[expect(deprecated)] libc::_NSGetExecutablePath(ptr::null_mut(), &mut sz); if sz == 0 { return Err(io::Error::last_os_error()); } let mut v: Vec = Vec::with_capacity(sz as usize); + #[expect(deprecated)] let err = libc::_NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz); if err != 0 { return Err(io::Error::last_os_error()); From 597932bb85345b685906d3ac1367b45caa5c5e82 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Fri, 29 Nov 2024 03:50:26 +0530 Subject: [PATCH 040/481] fix: fix codeblocks in `PathBuf` example --- std/src/path.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/src/path.rs b/std/src/path.rs index 635c7bca0e010..5b277a982eeb8 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -1158,6 +1158,7 @@ impl FusedIterator for Ancestors<'_> {} /// Note that `PathBuf` does not always sanitize arguments, for example /// [`push`] allows paths built from strings which include separators: /// +/// ``` /// use std::path::PathBuf; /// /// let mut path = PathBuf::new(); @@ -1166,6 +1167,7 @@ impl FusedIterator for Ancestors<'_> {} /// path.push("windows"); /// path.push(r"..\otherdir"); /// path.push("system32"); +/// ``` /// /// The behavior of `PathBuf` may be changed to a panic on such inputs /// in the future. [`Extend::extend`] should be used to add multi-part paths. From 440fd2c1f93d98e44180713b1d6701613ab5b768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Fri, 29 Nov 2024 11:46:34 +0100 Subject: [PATCH 041/481] update link to "C++ Exceptions under the hood" blog The link was introduced in 0ec321f7b541fcbfbf20286beb497e6d9d3352b2. For the old link see https://web.archive.org/web/20170409223244/https://monoinfinito.wordpress.com/series/exception-handling-in-c/. The blog has migrated from WordPress to Blogger in 2021 and to GitHub pages in 2024. --- panic_unwind/src/gcc.rs | 2 +- std/src/sys/personality/gcc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panic_unwind/src/gcc.rs b/panic_unwind/src/gcc.rs index 925af6c08322e..b2389078afd0f 100644 --- a/panic_unwind/src/gcc.rs +++ b/panic_unwind/src/gcc.rs @@ -5,7 +5,7 @@ //! documents linked from it. //! These are also good reads: //! * -//! * +//! * //! * //! //! ## A brief summary diff --git a/std/src/sys/personality/gcc.rs b/std/src/sys/personality/gcc.rs index ad596ecff65d5..88a25caeff0df 100644 --- a/std/src/sys/personality/gcc.rs +++ b/std/src/sys/personality/gcc.rs @@ -5,7 +5,7 @@ //! documents linked from it. //! These are also good reads: //! * -//! * +//! * //! * //! //! ## A brief summary From 85a51744152958c2434f2f8501c0600fec1e9172 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 30 Nov 2024 19:47:50 +0100 Subject: [PATCH 042/481] Add diagnostic item for `std::ops::ControlFlow` This will be used in Clippy to detect useless conversions done through `ControlFlow::map_break()` and `ControlFlow::map_continue()`. --- core/src/ops/control_flow.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/ops/control_flow.rs b/core/src/ops/control_flow.rs index 55deabbee8fb5..c4429b3cd7d45 100644 --- a/core/src/ops/control_flow.rs +++ b/core/src/ops/control_flow.rs @@ -79,6 +79,7 @@ use crate::{convert, ops}; /// [`Break`]: ControlFlow::Break /// [`Continue`]: ControlFlow::Continue #[stable(feature = "control_flow_enum_type", since = "1.55.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "ControlFlow")] // ControlFlow should not implement PartialOrd or Ord, per RFC 3058: // https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] From 111e23152f354e00335973db0c8252a8502ba5a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 09:52:20 +0100 Subject: [PATCH 043/481] move slice::swap_unchecked constness to slice_swap_unchecked feature gate --- core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index a24417dba8cc2..ec04852d44b44 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -959,7 +959,7 @@ impl [T] { /// [`swap`]: slice::swap /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[unstable(feature = "slice_swap_unchecked", issue = "88539")] - #[rustc_const_unstable(feature = "const_swap", issue = "83163")] + #[rustc_const_unstable(feature = "slice_swap_unchecked", issue = "88539")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { assert_unsafe_precondition!( check_library_ub, From 2c42c697a2e720b6c354fcf67ae10ef3659067b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 09:57:19 +0100 Subject: [PATCH 044/481] move swap_nonoverlapping constness to separate feature gate --- core/src/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 6147e9f5e6190..b6fc0caebd020 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1009,6 +1009,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] #[rustc_diagnostic_item = "ptr_swap"] +#[rustc_const_stable_indirect] pub const unsafe fn swap(x: *mut T, y: *mut T) { // Give ourselves some scratch space to work with. // We do not have to worry about drops: `MaybeUninit` does nothing when dropped. @@ -1069,7 +1070,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// ``` #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { #[allow(unused)] @@ -1129,7 +1130,6 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { /// LLVM can vectorize this (at least it can for the power-of-two-sized types /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, count: usize) { let x = x.cast::>(); let y = y.cast::>(); From e9431a55b201ee73e8c0f4fa91774c8916e07f08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 10:04:41 +0100 Subject: [PATCH 045/481] add test for bytewise ptr::swap of a pointer --- core/tests/lib.rs | 1 + core/tests/ptr.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 40129619ce50e..29de66852a426 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -18,6 +18,7 @@ #![feature(const_eval_select)] #![feature(const_heap)] #![feature(const_nonnull_new)] +#![feature(const_swap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index 91f8c977d088a..7e9773f2fb952 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -897,6 +897,25 @@ fn test_const_copy() { }; } +#[test] +fn test_const_swap() { + const { + let mut ptr1 = &1; + let mut ptr2 = &666; + + // Swap ptr1 and ptr2, bytewise. `swap` does not take a count + // so the best we can do is use an array. + type T = [u8; mem::size_of::<&i32>()]; + unsafe { + ptr::swap(ptr::from_mut(&mut ptr1).cast::(), ptr::from_mut(&mut ptr2).cast::()); + } + + // Make sure they still work. + assert!(*ptr1 == 666); + assert!(*ptr2 == 1); + }; +} + #[test] fn test_null_array_as_slice() { let arr: *mut [u8; 4] = null_mut(); From c10d7bdeb480f3aa4864306b3ff6dd0e9972f700 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 30 Nov 2024 01:59:17 -0800 Subject: [PATCH 046/481] Fix chaining `carrying_add`s Something about the MIR lowering for `||` ended up breaking this, but it's fixed by changing the code to use `|` instead. I also added an assembly test to ensure it *keeps* being `adc`. --- core/src/num/uint_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 90b986f4998db..0ebd765b54900 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -2354,7 +2354,7 @@ macro_rules! uint_impl { // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic let (a, b) = self.overflowing_add(rhs); let (c, d) = a.overflowing_add(carry as $SelfT); - (c, b || d) + (c, b | d) } /// Calculates `self` + `rhs` with a signed `rhs`. From 97e107840c9f55ca272f88906835658f5231ed92 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:37:36 -0400 Subject: [PATCH 047/481] Mark `slice::copy_from_slice` unstably const --- core/src/slice/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index ec04852d44b44..bc49b7d97972b 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -11,6 +11,7 @@ use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub}; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive}; +use crate::panic::const_panic; use crate::simd::{self, Simd}; use crate::ub_checks::assert_unsafe_precondition; use crate::{fmt, hint, ptr, range, slice}; @@ -3703,8 +3704,9 @@ impl [T] { /// [`split_at_mut`]: slice::split_at_mut #[doc(alias = "memcpy")] #[stable(feature = "copy_from_slice", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_copy_from_slice", issue = "131415")] #[track_caller] - pub fn copy_from_slice(&mut self, src: &[T]) + pub const fn copy_from_slice(&mut self, src: &[T]) where T: Copy, { @@ -3713,11 +3715,13 @@ impl [T] { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] - fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { - panic!( - "source slice length ({}) does not match destination slice length ({})", - src_len, dst_len, - ); + const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { + const_panic!( + "copy_from_slice: source slice length does not match destination slice length", + "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", + src_len: usize, + dst_len: usize, + ) } if self.len() != src.len() { From 925b06cb805969da132e92fab3f50bfae0ce71c4 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 16 Oct 2024 16:24:43 +0200 Subject: [PATCH 048/481] Stabilize unsigned `num_midpoint` feature --- core/src/num/f128.rs | 5 ++--- core/src/num/f16.rs | 5 ++--- core/src/num/f32.rs | 20 ++++++++++---------- core/src/num/f64.rs | 6 +++--- core/src/num/mod.rs | 28 ++++++++++++++-------------- core/src/num/nonzero.rs | 5 ++--- core/tests/lib.rs | 2 +- 7 files changed, 34 insertions(+), 37 deletions(-) diff --git a/core/src/num/f128.rs b/core/src/num/f128.rs index abeccb7eea248..4ebeaf046114a 100644 --- a/core/src/num/f128.rs +++ b/core/src/num/f128.rs @@ -807,7 +807,6 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// #![feature(num_midpoint)] /// # // Using aarch64 because `reliable_f128_math` is needed /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { /// @@ -817,8 +816,8 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - // #[unstable(feature = "num_midpoint", issue = "110840")] - pub fn midpoint(self, other: f128) -> f128 { + #[rustc_const_unstable(feature = "f128", issue = "116909")] + pub const fn midpoint(self, other: f128) -> f128 { const LO: f128 = f128::MIN_POSITIVE * 2.; const HI: f128 = f128::MAX / 2.; diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index 0d3e92695707c..5e1098c877f5b 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -795,7 +795,6 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// #![feature(num_midpoint)] /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 /// /// assert_eq!(1f16.midpoint(4.0), 2.5); @@ -804,8 +803,8 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - // #[unstable(feature = "num_midpoint", issue = "110840")] - pub fn midpoint(self, other: f16) -> f16 { + #[rustc_const_unstable(feature = "f128", issue = "116909")] + pub const fn midpoint(self, other: f16) -> f16 { const LO: f16 = f16::MIN_POSITIVE * 2.; const HI: f16 = f16::MAX / 2.; diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index 47dfce7530fb7..4c0d95f95e562 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -984,27 +984,27 @@ impl f32 { /// # Examples /// /// ``` - /// #![feature(num_midpoint)] /// assert_eq!(1f32.midpoint(4.0), 2.5); /// assert_eq!((-5.5f32).midpoint(8.0), 1.25); /// ``` #[inline] - #[unstable(feature = "num_midpoint", issue = "110840")] - pub fn midpoint(self, other: f32) -> f32 { + #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + pub const fn midpoint(self, other: f32) -> f32 { cfg_if! { + // Allow faster implementation that have known good 64-bit float + // implementations. Falling back to the branchy code on targets that don't + // have 64-bit hardware floats or buggy implementations. + // https://github.com/rust-lang/rust/pull/121062#issuecomment-2123408114 if #[cfg(any( target_arch = "x86_64", target_arch = "aarch64", - all(any(target_arch="riscv32", target_arch= "riscv64"), target_feature="d"), - all(target_arch = "arm", target_feature="vfp2"), + all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "d"), + all(target_arch = "arm", target_feature = "vfp2"), target_arch = "wasm32", target_arch = "wasm64", ))] { - // whitelist the faster implementation to targets that have known good 64-bit float - // implementations. Falling back to the branchy code on targets that don't have - // 64-bit hardware floats or buggy implementations. - // see: https://github.com/rust-lang/rust/pull/121062#issuecomment-2123408114 - ((f64::from(self) + f64::from(other)) / 2.0) as f32 + ((self as f64 + other as f64) / 2.0) as f32 } else { const LO: f32 = f32::MIN_POSITIVE * 2.; const HI: f32 = f32::MAX / 2.; diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index c89023c1ae490..77ca56df06705 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -1002,13 +1002,13 @@ impl f64 { /// # Examples /// /// ``` - /// #![feature(num_midpoint)] /// assert_eq!(1f64.midpoint(4.0), 2.5); /// assert_eq!((-5.5f64).midpoint(8.0), 1.25); /// ``` #[inline] - #[unstable(feature = "num_midpoint", issue = "110840")] - pub fn midpoint(self, other: f64) -> f64 { + #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + pub const fn midpoint(self, other: f64) -> f64 { const LO: f64 = f64::MIN_POSITIVE * 2.; const HI: f64 = f64::MAX / 2.; diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 995ed6eac3015..e36f20fd576ff 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -103,18 +103,18 @@ macro_rules! midpoint_impl { ($SelfT:ty, unsigned) => { /// Calculates the middle point of `self` and `rhs`. /// - /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a - /// sufficiently-large signed integral type. This implies that the result is - /// always rounded towards negative infinity and that no overflow will ever occur. + /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a + /// sufficiently-large unsigned integral type. This implies that the result is + /// always rounded towards zero and that no overflow will ever occur. /// /// # Examples /// /// ``` - /// #![feature(num_midpoint)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] + #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -134,14 +134,14 @@ macro_rules! midpoint_impl { /// # Examples /// /// ``` - /// #![feature(num_midpoint)] + /// #![feature(num_midpoint_signed)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] + #[unstable(feature = "num_midpoint_signed", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -157,18 +157,18 @@ macro_rules! midpoint_impl { ($SelfT:ty, $WideT:ty, unsigned) => { /// Calculates the middle point of `self` and `rhs`. /// - /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a - /// sufficiently-large signed integral type. This implies that the result is - /// always rounded towards negative infinity and that no overflow will ever occur. + /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a + /// sufficiently-large unsigned integral type. This implies that the result is + /// always rounded towards zero and that no overflow will ever occur. /// /// # Examples /// /// ``` - /// #![feature(num_midpoint)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] + #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -186,14 +186,14 @@ macro_rules! midpoint_impl { /// # Examples /// /// ``` - /// #![feature(num_midpoint)] + /// #![feature(num_midpoint_signed)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] + #[unstable(feature = "num_midpoint_signed", issue = "110840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index dba64d5dc8e34..10aca6e998013 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -1509,8 +1509,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - /// #![feature(num_midpoint)] - /// /// # use std::num::NonZero; /// # /// # fn main() { test().unwrap(); } @@ -1524,7 +1522,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] + #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 29de66852a426..4fbf47e20039a 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -64,7 +64,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(noop_waker)] -#![feature(num_midpoint)] +#![feature(num_midpoint_signed)] #![feature(numfmt)] #![feature(pattern)] #![feature(pointer_is_aligned_to)] From 608bdaccb3f78c4c32ae82753a10f7fb83b8a0ee Mon Sep 17 00:00:00 2001 From: cod10129 <110200933+cod10129@users.noreply.github.com> Date: Sun, 1 Dec 2024 13:54:04 -0600 Subject: [PATCH 049/481] add isatty alias for is_terminal --- std/src/io/stdio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/io/stdio.rs b/std/src/io/stdio.rs index 35b38ed783ff2..318c350822168 100644 --- a/std/src/io/stdio.rs +++ b/std/src/io/stdio.rs @@ -1200,6 +1200,7 @@ pub trait IsTerminal: crate::sealed::Sealed { /// /// [changes]: io#platform-specific-behavior /// [`Stdin`]: crate::io::Stdin + #[doc(alias = "isatty")] #[stable(feature = "is_terminal", since = "1.70.0")] fn is_terminal(&self) -> bool; } From 677a7701b898216c769b1f674f6546bab724da10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 10:23:39 +0100 Subject: [PATCH 050/481] remove a whole bunch of unnecessary const feature gates --- alloc/src/lib.rs | 8 -------- alloc/tests/lib.rs | 2 -- core/src/lib.rs | 19 ------------------- core/tests/lib.rs | 1 - std/src/lib.rs | 2 -- 5 files changed, 32 deletions(-) diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 108224b27fa80..84f4202c02a9b 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -91,8 +91,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] -#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))] #![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] @@ -107,13 +105,8 @@ #![feature(box_uninit_write)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] -#![feature(const_align_of_val)] -#![feature(const_box)] #![feature(const_eval_select)] #![feature(const_heap)] -#![feature(const_maybe_uninit_write)] -#![feature(const_size_of_val)] -#![feature(const_vec_string_slice)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] @@ -170,7 +163,6 @@ #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] #![feature(const_precise_live_drops)] -#![feature(const_try)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] #![feature(fundamental)] diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs index 02bbb40ef81d2..bcab17e7b2ddc 100644 --- a/alloc/tests/lib.rs +++ b/alloc/tests/lib.rs @@ -4,8 +4,6 @@ #![feature(assert_matches)] #![feature(btree_extract_if)] #![feature(cow_is_borrowed)] -#![feature(const_heap)] -#![feature(const_try)] #![feature(core_intrinsics)] #![feature(extract_if)] #![feature(exact_size_is_empty)] diff --git a/core/src/lib.rs b/core/src/lib.rs index 1b9a9ea3ecffc..ab9c33ee75477 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -109,23 +109,7 @@ // tidy-alphabetical-start #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] -#![feature(const_align_of_val)] -#![feature(const_align_of_val_raw)] -#![feature(const_alloc_layout)] -#![feature(const_black_box)] -#![feature(const_eq_ignore_ascii_case)] #![feature(const_eval_select)] -#![feature(const_heap)] -#![feature(const_nonnull_new)] -#![feature(const_ptr_sub_ptr)] -#![feature(const_raw_ptr_comparison)] -#![feature(const_size_of_val)] -#![feature(const_size_of_val_raw)] -#![feature(const_sockaddr_setters)] -#![feature(const_swap)] -#![feature(const_try)] -#![feature(const_type_id)] -#![feature(const_type_name)] #![feature(const_typed_swap)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] @@ -165,10 +149,7 @@ #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_ub_checks)] -#![feature(const_for)] -#![feature(const_is_char_boundary)] #![feature(const_precise_live_drops)] -#![feature(const_str_split_at)] #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 4fbf47e20039a..ec4b42b966b33 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -16,7 +16,6 @@ #![feature(const_align_of_val_raw)] #![feature(const_black_box)] #![feature(const_eval_select)] -#![feature(const_heap)] #![feature(const_nonnull_new)] #![feature(const_swap)] #![feature(const_trait_impl)] diff --git a/std/src/lib.rs b/std/src/lib.rs index 059c8d8309c83..143878170f087 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -409,9 +409,7 @@ // // Only for const-ness: // tidy-alphabetical-start -#![feature(const_collections_with_hasher)] #![feature(io_const_error)] -#![feature(thread_local_internals)] // tidy-alphabetical-end // #![default_lib_allocator] From 41b46c27ef5e64e35bbb7d56a6cf828e62456975 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 10:33:09 +0100 Subject: [PATCH 051/481] get rid of a bunch of unnecessary rustc_const_unstable --- alloc/src/collections/binary_heap/mod.rs | 1 - core/src/cell.rs | 1 - core/src/num/nonzero.rs | 1 - core/src/num/uint_macros.rs | 1 - core/src/ptr/const_ptr.rs | 3 --- core/src/ptr/mut_ptr.rs | 5 ----- core/src/ptr/unique.rs | 1 + core/src/slice/mod.rs | 2 -- 8 files changed, 1 insertion(+), 14 deletions(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 0bc65cdbc55a3..5d3997e14e3e9 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -486,7 +486,6 @@ impl BinaryHeap { /// heap.push(4); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "125961")] #[must_use] pub const fn new_in(alloc: A) -> BinaryHeap { BinaryHeap { data: Vec::new_in(alloc) } diff --git a/core/src/cell.rs b/core/src/cell.rs index c553979032777..cfa4c1fb56479 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -713,7 +713,6 @@ impl Cell<[T; N]> { /// let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); /// ``` #[unstable(feature = "as_array_of_cells", issue = "88248")] - #[rustc_const_unstable(feature = "as_array_of_cells", issue = "88248")] pub const fn as_array_of_cells(&self) -> &[Cell; N] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T; N]> as *const [Cell; N]) } diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 10aca6e998013..e97af081143b5 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -614,7 +614,6 @@ macro_rules! nonzero_integer { /// ``` /// #[unstable(feature = "non_zero_count_ones", issue = "120287")] - #[rustc_const_unstable(feature = "non_zero_count_ones", issue = "120287")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 0ebd765b54900..c853db181cee7 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -3162,7 +3162,6 @@ macro_rules! uint_impl { #[inline] #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", reason = "needs decision on wrapping behavior")] - #[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn wrapping_next_power_of_two(self) -> Self { diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 6f6815f49cd29..f100adecbbb76 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -346,7 +346,6 @@ impl *const T { /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit> where T: Sized, @@ -1528,7 +1527,6 @@ impl *const [T] { /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. #[unstable(feature = "slice_as_array", issue = "133508")] - #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] #[inline] #[must_use] pub const fn as_array(self) -> Option<*const [T; N]> { @@ -1608,7 +1606,6 @@ impl *const [T] { /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { if self.is_null() { None diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 678c6029158b5..6d0361b8c63f4 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -342,7 +342,6 @@ impl *mut T { /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit> where T: Sized, @@ -676,7 +675,6 @@ impl *mut T { /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit> where T: Sized, @@ -1762,7 +1760,6 @@ impl *mut [T] { /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. #[unstable(feature = "slice_as_array", issue = "133508")] - #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] #[inline] #[must_use] pub const fn as_mut_array(self) -> Option<*mut [T; N]> { @@ -1963,7 +1960,6 @@ impl *mut [T] { /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { if self.is_null() { None @@ -2015,7 +2011,6 @@ impl *mut [T] { /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit]> { if self.is_null() { None diff --git a/core/src/ptr/unique.rs b/core/src/ptr/unique.rs index a796820a7e468..ebdc918a729c7 100644 --- a/core/src/ptr/unique.rs +++ b/core/src/ptr/unique.rs @@ -92,6 +92,7 @@ impl Unique { /// Creates a new `Unique` if `ptr` is non-null. #[inline] + // rustc_const_unstable attribute can be removed when `const_nonnull_new` is stable #[rustc_const_unstable(feature = "ptr_internals", issue = "none")] pub const fn new(ptr: *mut T) -> Option { if let Some(pointer) = NonNull::new(ptr) { diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index bc49b7d97972b..a5507f0f33812 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -860,7 +860,6 @@ impl [T] { /// /// If `N` is not exactly equal to slice's the length of `self`, then this method returns `None`. #[unstable(feature = "slice_as_array", issue = "133508")] - #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] #[inline] #[must_use] pub const fn as_array(&self) -> Option<&[T; N]> { @@ -879,7 +878,6 @@ impl [T] { /// /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. #[unstable(feature = "slice_as_array", issue = "133508")] - #[rustc_const_unstable(feature = "slice_as_array", issue = "133508")] #[inline] #[must_use] pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { From c6b0f21f33923201ee985f0b8e1e66198c736f88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2024 10:35:09 +0100 Subject: [PATCH 052/481] rustc_allow_const_fn_unstable is not used in proc_macro --- proc_macro/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index 15770248b3106..4aa47ce4e4f51 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -22,7 +22,6 @@ // This library is copied into rust-analyzer to allow loading rustc compiled proc macros. // Please avoid unstable features where possible to minimize the amount of changes necessary // to make it compile with rust-analyzer on stable. -#![feature(rustc_allow_const_fn_unstable)] #![feature(staged_api)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] From a629815ace7693cbeaca8117758383ac0f0cb6ec Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 30 Nov 2024 16:15:47 +0100 Subject: [PATCH 053/481] Stabilize `ptr::fn_addr_eq` --- core/src/ptr/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index b6fc0caebd020..bc4c4e168a369 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -2111,7 +2111,6 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// when compiled with optimization: /// /// ``` -/// # #![feature(ptr_fn_addr_eq)] /// let f: fn(i32) -> i32 = |x| x; /// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body /// let h: fn(u32) -> u32 = |x| x + 0; // different signature too @@ -2136,7 +2135,6 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// # Examples /// /// ``` -/// #![feature(ptr_fn_addr_eq)] /// use std::ptr; /// /// fn a() { println!("a"); } @@ -2145,7 +2143,7 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// ``` /// /// [subtype]: https://doc.rust-lang.org/reference/subtyping.html -#[unstable(feature = "ptr_fn_addr_eq", issue = "129322")] +#[stable(feature = "ptr_fn_addr_eq", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[must_use = "function pointer comparison produces a value"] pub fn fn_addr_eq(f: T, g: U) -> bool { From 8124b177f69e3cb8055a63a064a6aff4caf9acff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Mon, 2 Dec 2024 10:38:40 +0100 Subject: [PATCH 054/481] Fix docs for '<[T]>::as_array'; --- core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index a5507f0f33812..191eaccff9899 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -858,7 +858,7 @@ impl [T] { /// Gets a reference to the underlying array. /// - /// If `N` is not exactly equal to slice's the length of `self`, then this method returns `None`. + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. #[unstable(feature = "slice_as_array", issue = "133508")] #[inline] #[must_use] From c52f82d17661e94bc8468112cefb9168d09f834f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 14 Oct 2024 18:32:54 -0400 Subject: [PATCH 055/481] Stabilize `const_maybe_uninit_write` Mark the following API const stable: impl MaybeUninit { pub const fn write(&mut self, val: T) -> &mut T; } This depends on `const_mut_refs` and `const_maybe_uninit_assume_init`, both of which have recently been stabilized. Tracking issue: --- core/src/mem/maybe_uninit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 3c1a098374ef9..9b3d690209856 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -485,9 +485,9 @@ impl MaybeUninit { /// } /// } /// ``` - #[stable(feature = "maybe_uninit_write", since = "1.55.0")] - #[rustc_const_unstable(feature = "const_maybe_uninit_write", issue = "63567")] #[inline(always)] + #[stable(feature = "maybe_uninit_write", since = "1.55.0")] + #[rustc_const_stable(feature = "const_maybe_uninit_write", since = "CURRENT_RUSTC_VERSION")] pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. From c20979b5b0ece6179de5da7a00c9714056d0bcf4 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sat, 30 Nov 2024 20:32:00 +0000 Subject: [PATCH 056/481] Use c"lit" for CStrings without unwrap --- alloc/src/ffi/c_str.rs | 32 +++++++++---------- alloc/src/ffi/c_str/tests.rs | 2 +- alloc/src/rc/tests.rs | 4 +-- alloc/src/sync/tests.rs | 4 +-- .../sys/pal/unix/process/process_common.rs | 2 +- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index c739832bc7843..9c074383a5ecb 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -384,7 +384,7 @@ impl CString { /// fn some_extern_function(s: *mut c_char); /// } /// - /// let c_string = CString::new("Hello!").expect("CString::new failed"); + /// let c_string = CString::from(c"Hello!"); /// let raw = c_string.into_raw(); /// unsafe { /// some_extern_function(raw); @@ -429,7 +429,7 @@ impl CString { /// ``` /// use std::ffi::CString; /// - /// let c_string = CString::new("foo").expect("CString::new failed"); + /// let c_string = CString::from(c"foo"); /// /// let ptr = c_string.into_raw(); /// @@ -487,7 +487,7 @@ impl CString { /// ``` /// use std::ffi::CString; /// - /// let c_string = CString::new("foo").expect("CString::new failed"); + /// let c_string = CString::from(c"foo"); /// let bytes = c_string.into_bytes(); /// assert_eq!(bytes, vec![b'f', b'o', b'o']); /// ``` @@ -508,7 +508,7 @@ impl CString { /// ``` /// use std::ffi::CString; /// - /// let c_string = CString::new("foo").expect("CString::new failed"); + /// let c_string = CString::from(c"foo"); /// let bytes = c_string.into_bytes_with_nul(); /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); /// ``` @@ -530,7 +530,7 @@ impl CString { /// ``` /// use std::ffi::CString; /// - /// let c_string = CString::new("foo").expect("CString::new failed"); + /// let c_string = CString::from(c"foo"); /// let bytes = c_string.as_bytes(); /// assert_eq!(bytes, &[b'f', b'o', b'o']); /// ``` @@ -550,7 +550,7 @@ impl CString { /// ``` /// use std::ffi::CString; /// - /// let c_string = CString::new("foo").expect("CString::new failed"); + /// let c_string = CString::from(c"foo"); /// let bytes = c_string.as_bytes_with_nul(); /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); /// ``` @@ -568,7 +568,7 @@ impl CString { /// ``` /// use std::ffi::{CString, CStr}; /// - /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); + /// let c_string = CString::from(c"foo"); /// let cstr = c_string.as_c_str(); /// assert_eq!(cstr, /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); @@ -586,12 +586,9 @@ impl CString { /// # Examples /// /// ``` - /// use std::ffi::{CString, CStr}; - /// - /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); + /// let c_string = c"foo".to_owned(); /// let boxed = c_string.into_boxed_c_str(); - /// assert_eq!(&*boxed, - /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); + /// assert_eq!(boxed.to_bytes_with_nul(), b"foo\0"); /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "into_boxed_c_str", since = "1.20.0")] @@ -658,7 +655,7 @@ impl CString { /// assert_eq!( /// CString::from_vec_with_nul(b"abc\0".to_vec()) /// .expect("CString::from_vec_with_nul failed"), - /// CString::new(b"abc".to_vec()).expect("CString::new failed") + /// c"abc".to_owned() /// ); /// ``` /// @@ -1168,11 +1165,12 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::CString; + /// use std::ffi::{CStr, CString}; /// - /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); - /// let boxed = c_string.into_boxed_c_str(); - /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed")); + /// let boxed: Box = Box::from(c"foo"); + /// let c_string: CString = c"foo".to_owned(); + /// + /// assert_eq!(boxed.into_c_string(), c_string); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "`self` will be dropped if the result is not used"] diff --git a/alloc/src/ffi/c_str/tests.rs b/alloc/src/ffi/c_str/tests.rs index 8b7172b3f20a9..d6b797347c2ec 100644 --- a/alloc/src/ffi/c_str/tests.rs +++ b/alloc/src/ffi/c_str/tests.rs @@ -159,7 +159,7 @@ fn boxed_default() { #[test] fn test_c_str_clone_into() { - let mut c_string = CString::new("lorem").unwrap(); + let mut c_string = c"lorem".to_owned(); let c_ptr = c_string.as_ptr(); let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); c_str.clone_into(&mut c_string); diff --git a/alloc/src/rc/tests.rs b/alloc/src/rc/tests.rs index 333e1bde31c1e..2210a7c24c06a 100644 --- a/alloc/src/rc/tests.rs +++ b/alloc/src/rc/tests.rs @@ -349,9 +349,9 @@ fn test_unsized() { #[test] fn test_maybe_thin_unsized() { // If/when custom thin DSTs exist, this test should be updated to use one - use std::ffi::{CStr, CString}; + use std::ffi::CStr; - let x: Rc = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str()); + let x: Rc = Rc::from(c"swordfish"); assert_eq!(format!("{x:?}"), "\"swordfish\""); let y: Weak = Rc::downgrade(&x); drop(x); diff --git a/alloc/src/sync/tests.rs b/alloc/src/sync/tests.rs index 3f66c88992344..de5816fda974a 100644 --- a/alloc/src/sync/tests.rs +++ b/alloc/src/sync/tests.rs @@ -412,9 +412,9 @@ fn test_unsized() { #[test] fn test_maybe_thin_unsized() { // If/when custom thin DSTs exist, this test should be updated to use one - use std::ffi::{CStr, CString}; + use std::ffi::CStr; - let x: Arc = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str()); + let x: Arc = Arc::from(c"swordfish"); assert_eq!(format!("{x:?}"), "\"swordfish\""); let y: Weak = Arc::downgrade(&x); drop(x); diff --git a/std/src/sys/pal/unix/process/process_common.rs b/std/src/sys/pal/unix/process/process_common.rs index 13290fed762ae..342818ac91183 100644 --- a/std/src/sys/pal/unix/process/process_common.rs +++ b/std/src/sys/pal/unix/process/process_common.rs @@ -393,7 +393,7 @@ impl Command { fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { CString::new(s.as_bytes()).unwrap_or_else(|_e| { *saw_nul = true; - CString::new("").unwrap() + c"".to_owned() }) } From 347f3ec84d81b880edd9929cc70bbbc6b2a45787 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 2 Dec 2024 18:26:00 +0100 Subject: [PATCH 057/481] Fix `f16::midpoint` const feature gate --- core/src/num/f16.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index 5e1098c877f5b..c82f0d7cd4ad5 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -803,7 +803,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn midpoint(self, other: f16) -> f16 { const LO: f16 = f16::MIN_POSITIVE * 2.; const HI: f16 = f16::MAX / 2.; From 51c6fef9882f3fe327411fd178414f5c3d01e3a1 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 23 Nov 2024 14:31:20 -0500 Subject: [PATCH 058/481] Add simd_relaxed_fma intrinsic --- core/src/intrinsics/simd.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/intrinsics/simd.rs b/core/src/intrinsics/simd.rs index 5ddca9c4dce88..945bbe34df319 100644 --- a/core/src/intrinsics/simd.rs +++ b/core/src/intrinsics/simd.rs @@ -612,6 +612,16 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_fma(x: T, y: T, z: T) -> T; + /// Computes `(x*y) + z` for each element, with unspecified rounding. + /// + /// This may be equivalent to `simd_fma`, or it may relax to rounding each + /// operation if that's more efficient. + /// + /// `T` must be a vector of floats. + #[cfg(not(bootstrap))] + #[rustc_nounwind] + pub fn simd_relaxed_fma(x: T, y: T, z: T) -> T; + // Computes the sine of each element. /// /// `T` must be a vector of floats. From 3e530502e58c0e63e1f0d17bde629f8123b5b7c7 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 23 Nov 2024 19:17:27 -0500 Subject: [PATCH 059/481] Match simd_relaxed_fma documentation to fmuladd intrinsic --- core/src/intrinsics/simd.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/src/intrinsics/simd.rs b/core/src/intrinsics/simd.rs index 945bbe34df319..0d24b0558c594 100644 --- a/core/src/intrinsics/simd.rs +++ b/core/src/intrinsics/simd.rs @@ -612,10 +612,14 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_fma(x: T, y: T, z: T) -> T; - /// Computes `(x*y) + z` for each element, with unspecified rounding. - /// - /// This may be equivalent to `simd_fma`, or it may relax to rounding each - /// operation if that's more efficient. + /// Computes `(x*y) + z` for each element, non-deterministically executing either + /// a fused multiply-add or two operations with rounding of the intermediate result. + /// + /// The operation is fused if the code generator determines that target instruction + /// set has support for a fused operation, and that the fused operation is more efficient + /// than the equivalent, separate pair of mul and add instructions. It is unspecified + /// whether or not a fused operation is selected, and that may depend on optimization + /// level and context, for example. /// /// `T` must be a vector of floats. #[cfg(not(bootstrap))] From 986e152d56d31516d97d4933d7e6d3764a280d91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2024 10:39:09 +0100 Subject: [PATCH 060/481] stabilize const_collections_with_hasher and build_hasher_default_const_new --- core/src/hash/mod.rs | 6 +++--- std/src/collections/hash/map.rs | 24 +++++++++++++++++++++++- std/src/collections/hash/set.rs | 24 +++++++++++++++++++++++- std/src/lib.rs | 1 - 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/core/src/hash/mod.rs b/core/src/hash/mod.rs index 061690e88ddf8..84bbf985e8be4 100644 --- a/core/src/hash/mod.rs +++ b/core/src/hash/mod.rs @@ -752,10 +752,10 @@ pub struct BuildHasherDefault(marker::PhantomData H>); impl BuildHasherDefault { /// Creates a new BuildHasherDefault for Hasher `H`. - #[unstable( + #[stable(feature = "build_hasher_default_const_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable( feature = "build_hasher_default_const_new", - issue = "123197", - reason = "recently added" + since = "CURRENT_RUSTC_VERSION" )] pub const fn new() -> Self { BuildHasherDefault(marker::PhantomData) diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 09c0b61fb2b89..59dcdfd08cb3c 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -204,6 +204,25 @@ use crate::ops::Index; /// println!("{viking:?} has {health} hp"); /// } /// ``` +/// +/// # Usage in `const` and `static` +/// +/// As explained above, `HashMap` is randomly seeded: each `HashMap` instance uses a different seed, +/// which means that `HashMap::new` cannot be used in const context. To construct a `HashMap` in the +/// initializer of a `const` or `static` item, you will have to use a different hasher that does not +/// involve a random seed, as demonstrated in the following example. **`HashMap` constructed this +/// way are not resistant against HashDoS!** +/// +/// ```rust +/// use std::collections::HashMap; +/// use std::hash::{BuildHasherDefault, DefaultHasher}; +/// use std::sync::Mutex; +/// +/// const EMPTY_MAP: HashMap, BuildHasherDefault> = +/// HashMap::with_hasher(BuildHasherDefault::new()); +/// static MAP: Mutex, BuildHasherDefault>> = +/// Mutex::new(HashMap::with_hasher(BuildHasherDefault::new())); +/// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] #[stable(feature = "rust1", since = "1.0.0")] @@ -277,7 +296,10 @@ impl HashMap { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575")] + #[rustc_const_stable( + feature = "const_collections_with_hasher", + since = "CURRENT_RUSTC_VERSION" + )] pub const fn with_hasher(hash_builder: S) -> HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } } diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index 21a73259f6179..2a481dbaa6271 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -101,6 +101,25 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; /// [`HashMap`]: crate::collections::HashMap /// [`RefCell`]: crate::cell::RefCell /// [`Cell`]: crate::cell::Cell +/// +/// # Usage in `const` and `static` +/// +/// Like `HashMap`, `HashSet` is randomly seeded: each `HashSet` instance uses a different seed, +/// which means that `HashSet::new` cannot be used in const context. To construct a `HashSet` in the +/// initializer of a `const` or `static` item, you will have to use a different hasher that does not +/// involve a random seed, as demonstrated in the following example. **`HashSet` constructed this +/// way are not resistant against HashDoS!** +/// +/// ```rust +/// use std::collections::HashSet; +/// use std::hash::{BuildHasherDefault, DefaultHasher}; +/// use std::sync::Mutex; +/// +/// const EMPTY_SET: HashSet> = +/// HashSet::with_hasher(BuildHasherDefault::new()); +/// static SET: Mutex>> = +/// Mutex::new(HashSet::with_hasher(BuildHasherDefault::new())); +/// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { @@ -369,7 +388,10 @@ impl HashSet { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575")] + #[rustc_const_stable( + feature = "const_collections_with_hasher", + since = "CURRENT_RUSTC_VERSION" + )] pub const fn with_hasher(hasher: S) -> HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } } diff --git a/std/src/lib.rs b/std/src/lib.rs index 143878170f087..585946c1d50e0 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -320,7 +320,6 @@ // Library features (core): // tidy-alphabetical-start #![feature(array_chunks)] -#![feature(build_hasher_default_const_new)] #![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] From 6c3fe75e64a2f4a7d2604a8ef0c5f39a5633e564 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2024 11:31:12 +0100 Subject: [PATCH 061/481] ./x miri: fix sysroot build --- std/src/collections/hash/map.rs | 4 ++-- std/src/collections/hash/set.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 59dcdfd08cb3c..109bc3946346f 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -210,8 +210,8 @@ use crate::ops::Index; /// As explained above, `HashMap` is randomly seeded: each `HashMap` instance uses a different seed, /// which means that `HashMap::new` cannot be used in const context. To construct a `HashMap` in the /// initializer of a `const` or `static` item, you will have to use a different hasher that does not -/// involve a random seed, as demonstrated in the following example. **`HashMap` constructed this -/// way are not resistant against HashDoS!** +/// involve a random seed, as demonstrated in the following example. **A `HashMap` constructed this +/// way is not resistant against HashDoS!** /// /// ```rust /// use std::collections::HashMap; diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index 2a481dbaa6271..4c81aaff45886 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -107,8 +107,8 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; /// Like `HashMap`, `HashSet` is randomly seeded: each `HashSet` instance uses a different seed, /// which means that `HashSet::new` cannot be used in const context. To construct a `HashSet` in the /// initializer of a `const` or `static` item, you will have to use a different hasher that does not -/// involve a random seed, as demonstrated in the following example. **`HashSet` constructed this -/// way are not resistant against HashDoS!** +/// involve a random seed, as demonstrated in the following example. **A `HashSet` constructed this +/// way is not resistant against HashDoS!** /// /// ```rust /// use std::collections::HashSet; From 8939060027ac894fe02c0244358d8fbc30cb5f32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2024 18:03:29 +0100 Subject: [PATCH 062/481] stabilize const_{size,align}_of_val --- core/src/alloc/layout.rs | 2 +- core/src/intrinsics/mod.rs | 2 ++ core/src/mem/mod.rs | 6 ++---- core/tests/lib.rs | 1 - 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index 60936da2e0b0d..d884fa69efbb0 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -179,6 +179,7 @@ impl Layout { /// or other unsized type like a slice). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[rustc_const_stable_indirect] #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { @@ -215,7 +216,6 @@ impl Layout { /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html #[unstable(feature = "layout_for_ptr", issue = "69835")] - #[rustc_const_unstable(feature = "layout_for_ptr", issue = "69835")] #[must_use] pub const unsafe fn for_value_raw(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 46873fdc0479f..ea41cecfec24f 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -4099,6 +4099,7 @@ pub const fn variant_count() -> usize { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] +#[rustc_intrinsic_const_stable_indirect] pub const unsafe fn size_of_val(_ptr: *const T) -> usize { unreachable!() } @@ -4114,6 +4115,7 @@ pub const unsafe fn size_of_val(_ptr: *const T) -> usize { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] +#[rustc_intrinsic_const_stable_indirect] pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { unreachable!() } diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 4cf52042a57f6..78ad6880709fb 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -333,7 +333,7 @@ pub const fn size_of() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[rustc_const_stable(feature = "const_size_of_val", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] pub const fn size_of_val(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer @@ -390,7 +390,6 @@ pub const fn size_of_val(val: &T) -> usize { #[inline] #[must_use] #[unstable(feature = "layout_for_ptr", issue = "69835")] -#[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")] pub const unsafe fn size_of_val_raw(val: *const T) -> usize { // SAFETY: the caller must provide a valid raw pointer unsafe { intrinsics::size_of_val(val) } @@ -485,7 +484,7 @@ pub const fn align_of() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] +#[rustc_const_stable(feature = "const_align_of_val", since = "CURRENT_RUSTC_VERSION")] #[allow(deprecated)] pub const fn align_of_val(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer @@ -534,7 +533,6 @@ pub const fn align_of_val(val: &T) -> usize { #[inline] #[must_use] #[unstable(feature = "layout_for_ptr", issue = "69835")] -#[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")] pub const unsafe fn align_of_val_raw(val: *const T) -> usize { // SAFETY: the caller must provide a valid raw pointer unsafe { intrinsics::min_align_of_val(val) } diff --git a/core/tests/lib.rs b/core/tests/lib.rs index ec4b42b966b33..e0b1c21e1ecb9 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -13,7 +13,6 @@ #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(clone_to_uninit)] -#![feature(const_align_of_val_raw)] #![feature(const_black_box)] #![feature(const_eval_select)] #![feature(const_nonnull_new)] From 68f6c4c98c10d569da2f8b4577c9037469f97dda Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 3 Dec 2024 12:40:00 +0100 Subject: [PATCH 063/481] Update the definition of `borrowing_sub` This ensures that it matches the one in `carrying_add`. --- core/src/num/uint_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index c853db181cee7..c79b2f7ad8ed3 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -2445,7 +2445,7 @@ macro_rules! uint_impl { // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic let (a, b) = self.overflowing_sub(rhs); let (c, d) = a.overflowing_sub(borrow as $SelfT); - (c, b || d) + (c, b | d) } /// Calculates `self` - `rhs` with a signed `rhs` From 4d7e9a167db2b37b6e6716f2b620033d1e8abb76 Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Tue, 12 Nov 2024 09:46:41 +0800 Subject: [PATCH 064/481] a release operation synchronizes with an acquire operation --- std/src/thread/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 2ff44fcd4c6b7..cfbf6548a380c 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -1021,11 +1021,11 @@ impl Drop for PanicGuard { /// /// # Memory Ordering /// -/// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory +/// Calls to `unpark` _synchronize-with_ calls to `park`, meaning that memory /// operations performed before a call to `unpark` are made visible to the thread that /// consumes the token and returns from `park`. Note that all `park` and `unpark` -/// operations for a given thread form a total order and `park` synchronizes-with -/// _all_ prior `unpark` operations. +/// operations for a given thread form a total order and _all_ prior `unpark` operations +/// synchronize-with `park`. /// /// In atomic ordering terms, `unpark` performs a `Release` operation and `park` /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same From 71c430d300ab8f854966d467b4fbe63d9d80ce17 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 1 Dec 2024 19:07:13 -0800 Subject: [PATCH 065/481] Add `core::arch::breakpoint` and test Approved in [ACP 491](https://github.com/rust-lang/libs-team/issues/491). Remove the `unsafe` on `core::intrinsics::breakpoint()`, since it's a safe intrinsic to call and has no prerequisites. (Thanks to @zachs18 for figuring out the `bootstrap`/`not(bootstrap)` logic.) --- core/src/arch.rs | 27 +++++++++++++++++++++++++++ core/src/intrinsics/mod.rs | 12 ++++++++++++ 2 files changed, 39 insertions(+) diff --git a/core/src/arch.rs b/core/src/arch.rs index 57f456c98b3c6..95d88c7f67991 100644 --- a/core/src/arch.rs +++ b/core/src/arch.rs @@ -42,3 +42,30 @@ pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ } + +/// Compiles to a target-specific software breakpoint instruction or equivalent. +/// +/// This will typically abort the program. It may result in a core dump, and/or the system logging +/// debug information. Additional target-specific capabilities may be possible depending on +/// debuggers or other tooling; in particular, a debugger may be able to resume execution. +/// +/// If possible, this will produce an instruction sequence that allows a debugger to resume *after* +/// the breakpoint, rather than resuming *at* the breakpoint; however, the exact behavior is +/// target-specific and debugger-specific, and not guaranteed. +/// +/// If the target platform does not have any kind of debug breakpoint instruction, this may compile +/// to a trapping instruction (e.g. an undefined instruction) instead, or to some other form of +/// target-specific abort that may or may not support convenient resumption. +/// +/// The precise behavior and the precise instruction generated are not guaranteed, except that in +/// normal execution with no debug tooling involved this will not continue executing. +/// +/// - On x86 targets, this produces an `int3` instruction. +/// - On aarch64 targets, this produces a `brk #0xf000` instruction. +// When stabilizing this, update the comment on `core::intrinsics::breakpoint`. +#[unstable(feature = "breakpoint", issue = "133724")] +#[inline(always)] +#[cfg(not(bootstrap))] +pub fn breakpoint() { + core::intrinsics::breakpoint(); +} diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index ea41cecfec24f..802b571c51067 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1381,6 +1381,18 @@ pub unsafe fn prefetch_write_instruction(_data: *const T, _locality: i32) { #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] +#[cfg(not(bootstrap))] +pub fn breakpoint() { + unreachable!() +} + +/// Executes a breakpoint trap, for inspection by a debugger. +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +#[cfg(bootstrap)] pub unsafe fn breakpoint() { unreachable!() } From d6cd36af747fa7078dd14c31b4ab567e30a30347 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 21 Nov 2024 09:15:22 -0800 Subject: [PATCH 066/481] Update `NonZero` and `NonNull` to not field-project (per MCP807) --- core/src/num/nonzero.rs | 34 +++++++++++++++++++++----- core/src/ptr/non_null.rs | 53 +++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 29 deletions(-) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index e97af081143b5..a9294306b1b61 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -37,6 +37,8 @@ pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed { macro_rules! impl_zeroable_primitive { ($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => { mod private { + use super::*; + #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", @@ -45,7 +47,11 @@ macro_rules! impl_zeroable_primitive { pub trait Sealed {} $( - #[derive(Debug, Clone, Copy, PartialEq)] + // This inner type is never shown directly, so intentionally does not have Debug + #[expect(missing_debug_implementations)] + // Since this struct is non-generic and derives Copy, + // the derived Clone is `*self` and thus doesn't field-project. + #[derive(Clone, Copy)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] @@ -55,6 +61,16 @@ macro_rules! impl_zeroable_primitive { issue = "none" )] pub struct $NonZeroInner($primitive); + + // This is required to allow matching a constant. We don't get it from a derive + // because the derived `PartialEq` would do a field projection, which is banned + // by . + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + impl StructuralPartialEq for $NonZeroInner {} )+ } @@ -172,7 +188,7 @@ where { #[inline] fn clone(&self) -> Self { - Self(self.0) + *self } } @@ -440,15 +456,21 @@ where #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")] #[inline] pub const fn get(self) -> T { - // FIXME: This can be changed to simply `self.0` once LLVM supports `!range` metadata - // for function arguments: https://github.com/llvm/llvm-project/issues/76628 - // // Rustc can set range metadata only if it loads `self` from // memory somewhere. If the value of `self` was from by-value argument // of some not-inlined function, LLVM don't have range metadata // to understand that the value cannot be zero. // - // For now, using the transmute `assume`s the range at runtime. + // Using the transmute `assume`s the range at runtime. + // + // Even once LLVM supports `!range` metadata for function arguments + // (see ), this can't + // be `.0` because MCP#807 bans field-projecting into `scalar_valid_range` + // types, and it arguably wouldn't want to be anyway because if this is + // MIR-inlined, there's no opportunity to put that argument metadata anywhere. + // + // The good answer here will eventually be pattern types, which will hopefully + // allow it to go back to `.0`, maybe with a cast of some sort. // // SAFETY: `ZeroablePrimitive` guarantees that the size and bit validity // of `.0` is such that this transmute is sound. diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index d37b7eedfcbdb..0ad1cad6914ad 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -7,7 +7,7 @@ use crate::pin::PinCoerceUnsized; use crate::ptr::Unique; use crate::slice::{self, SliceIndex}; use crate::ub_checks::assert_unsafe_precondition; -use crate::{fmt, hash, intrinsics, ptr}; +use crate::{fmt, hash, intrinsics, mem, ptr}; /// `*mut T` but non-zero and [covariant]. /// @@ -69,6 +69,8 @@ use crate::{fmt, hash, intrinsics, ptr}; #[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = "NonNull"] pub struct NonNull { + // Remember to use `.as_ptr()` instead of `.pointer`, as field projecting to + // this is banned by . pointer: *const T, } @@ -282,7 +284,7 @@ impl NonNull { pub fn addr(self) -> NonZero { // SAFETY: The pointer is guaranteed by the type to be non-null, // meaning that the address will be non-zero. - unsafe { NonZero::new_unchecked(self.pointer.addr()) } + unsafe { NonZero::new_unchecked(self.as_ptr().addr()) } } /// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of @@ -296,7 +298,7 @@ impl NonNull { #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn with_addr(self, addr: NonZero) -> Self { // SAFETY: The result of `ptr::from::with_addr` is non-null because `addr` is guaranteed to be non-zero. - unsafe { NonNull::new_unchecked(self.pointer.with_addr(addr.get()) as *mut _) } + unsafe { NonNull::new_unchecked(self.as_ptr().with_addr(addr.get()) as *mut _) } } /// Creates a new pointer by mapping `self`'s address to a new one, preserving the @@ -335,7 +337,12 @@ impl NonNull { #[must_use] #[inline(always)] pub const fn as_ptr(self) -> *mut T { - self.pointer as *mut T + // This is a transmute for the same reasons as `NonZero::get`. + + // SAFETY: `NonNull` is `transparent` over a `*const T`, and `*const T` + // and `*mut T` have the same layout, so transitively we can transmute + // our `NonNull` to a `*mut T` directly. + unsafe { mem::transmute::(self) } } /// Returns a shared reference to the value. If the value may be uninitialized, [`as_uninit_ref`] @@ -484,7 +491,7 @@ impl NonNull { // Additionally safety contract of `offset` guarantees that the resulting pointer is // pointing to an allocation, there can't be an allocation at null, thus it's safe to // construct `NonNull`. - unsafe { NonNull { pointer: intrinsics::offset(self.pointer, count) } } + unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } } } /// Calculates the offset from a pointer in bytes. @@ -508,7 +515,7 @@ impl NonNull { // Additionally safety contract of `offset` guarantees that the resulting pointer is // pointing to an allocation, there can't be an allocation at null, thus it's safe to // construct `NonNull`. - unsafe { NonNull { pointer: self.pointer.byte_offset(count) } } + unsafe { NonNull { pointer: self.as_ptr().byte_offset(count) } } } /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). @@ -560,7 +567,7 @@ impl NonNull { // Additionally safety contract of `offset` guarantees that the resulting pointer is // pointing to an allocation, there can't be an allocation at null, thus it's safe to // construct `NonNull`. - unsafe { NonNull { pointer: intrinsics::offset(self.pointer, count) } } + unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } } } /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). @@ -584,7 +591,7 @@ impl NonNull { // Additionally safety contract of `add` guarantees that the resulting pointer is pointing // to an allocation, there can't be an allocation at null, thus it's safe to construct // `NonNull`. - unsafe { NonNull { pointer: self.pointer.byte_add(count) } } + unsafe { NonNull { pointer: self.as_ptr().byte_add(count) } } } /// Subtracts an offset from a pointer (convenience for @@ -666,7 +673,7 @@ impl NonNull { // Additionally safety contract of `sub` guarantees that the resulting pointer is pointing // to an allocation, there can't be an allocation at null, thus it's safe to construct // `NonNull`. - unsafe { NonNull { pointer: self.pointer.byte_sub(count) } } + unsafe { NonNull { pointer: self.as_ptr().byte_sub(count) } } } /// Calculates the distance between two pointers within the same allocation. The returned value is in @@ -763,7 +770,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `offset_from`. - unsafe { self.pointer.offset_from(origin.pointer) } + unsafe { self.as_ptr().offset_from(origin.as_ptr()) } } /// Calculates the distance between two pointers within the same allocation. The returned value is in @@ -781,7 +788,7 @@ impl NonNull { #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_offset_from(self, origin: NonNull) -> isize { // SAFETY: the caller must uphold the safety contract for `byte_offset_from`. - unsafe { self.pointer.byte_offset_from(origin.pointer) } + unsafe { self.as_ptr().byte_offset_from(origin.as_ptr()) } } // N.B. `wrapping_offset``, `wrapping_add`, etc are not implemented because they can wrap to null @@ -856,7 +863,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `sub_ptr`. - unsafe { self.pointer.sub_ptr(subtracted.pointer) } + unsafe { self.as_ptr().sub_ptr(subtracted.as_ptr()) } } /// Calculates the distance between two pointers within the same allocation, *where it's known that @@ -875,7 +882,7 @@ impl NonNull { #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] pub const unsafe fn byte_sub_ptr(self, origin: NonNull) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_sub_ptr`. - unsafe { self.pointer.byte_sub_ptr(origin.pointer) } + unsafe { self.as_ptr().byte_sub_ptr(origin.as_ptr()) } } /// Reads the value from `self` without moving it. This leaves the @@ -893,7 +900,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `read`. - unsafe { ptr::read(self.pointer) } + unsafe { ptr::read(self.as_ptr()) } } /// Performs a volatile read of the value from `self` without moving it. This @@ -914,7 +921,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `read_volatile`. - unsafe { ptr::read_volatile(self.pointer) } + unsafe { ptr::read_volatile(self.as_ptr()) } } /// Reads the value from `self` without moving it. This leaves the @@ -934,7 +941,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `read_unaligned`. - unsafe { ptr::read_unaligned(self.pointer) } + unsafe { ptr::read_unaligned(self.as_ptr()) } } /// Copies `count * size_of` bytes from `self` to `dest`. The source @@ -954,7 +961,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `copy`. - unsafe { ptr::copy(self.pointer, dest.as_ptr(), count) } + unsafe { ptr::copy(self.as_ptr(), dest.as_ptr(), count) } } /// Copies `count * size_of` bytes from `self` to `dest`. The source @@ -974,7 +981,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. - unsafe { ptr::copy_nonoverlapping(self.pointer, dest.as_ptr(), count) } + unsafe { ptr::copy_nonoverlapping(self.as_ptr(), dest.as_ptr(), count) } } /// Copies `count * size_of` bytes from `src` to `self`. The source @@ -994,7 +1001,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `copy`. - unsafe { ptr::copy(src.pointer, self.as_ptr(), count) } + unsafe { ptr::copy(src.as_ptr(), self.as_ptr(), count) } } /// Copies `count * size_of` bytes from `src` to `self`. The source @@ -1014,7 +1021,7 @@ impl NonNull { T: Sized, { // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. - unsafe { ptr::copy_nonoverlapping(src.pointer, self.as_ptr(), count) } + unsafe { ptr::copy_nonoverlapping(src.as_ptr(), self.as_ptr(), count) } } /// Executes the destructor (if any) of the pointed-to value. @@ -1201,7 +1208,7 @@ impl NonNull { { // SAFETY: `align` has been checked to be a power of 2 above. - unsafe { ptr::align_offset(self.pointer, align) } + unsafe { ptr::align_offset(self.as_ptr(), align) } } } @@ -1229,7 +1236,7 @@ impl NonNull { where T: Sized, { - self.pointer.is_aligned() + self.as_ptr().is_aligned() } /// Returns whether the pointer is aligned to `align`. @@ -1266,7 +1273,7 @@ impl NonNull { #[must_use] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] pub fn is_aligned_to(self, align: usize) -> bool { - self.pointer.is_aligned_to(align) + self.as_ptr().is_aligned_to(align) } } From d8c496ee0dcd4203f8026c889b3602d6b7cdfd86 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 12 Dec 2023 13:10:13 +0100 Subject: [PATCH 067/481] Allow fn pointers comparisons lint in library --- core/tests/ptr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index 7e9773f2fb952..454b13a7ee389 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -304,6 +304,7 @@ fn test_const_nonnull_new() { #[test] #[cfg(unix)] // printf may not be available on other platforms #[allow(deprecated)] // For SipHasher +#[cfg_attr(not(bootstrap), allow(unpredictable_function_pointer_comparisons))] pub fn test_variadic_fnptr() { use core::ffi; use core::hash::{Hash, SipHasher}; From 579b2d1b23da075743887121671cf3ecf1d65602 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Dec 2024 16:01:31 +0000 Subject: [PATCH 068/481] Rename `core_pattern_type` and `core_pattern_types` lib feature gates to `pattern_type_macro` That's what the gates are actually gating, and the single char difference in naming was not helpful either --- core/src/lib.rs | 2 +- core/src/pat.rs | 2 +- std/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index ab9c33ee75477..fde6887c5abae 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -345,7 +345,7 @@ pub mod net; pub mod option; pub mod panic; pub mod panicking; -#[unstable(feature = "core_pattern_types", issue = "123646")] +#[unstable(feature = "pattern_type_macro", issue = "123646")] pub mod pat; pub mod pin; #[unstable(feature = "random", issue = "130703")] diff --git a/core/src/pat.rs b/core/src/pat.rs index 1f89d960be67b..752e79c2dacee 100644 --- a/core/src/pat.rs +++ b/core/src/pat.rs @@ -6,7 +6,7 @@ /// ``` #[macro_export] #[rustc_builtin_macro(pattern_type)] -#[unstable(feature = "core_pattern_type", issue = "123646")] +#[unstable(feature = "pattern_type_macro", issue = "123646")] macro_rules! pattern_type { ($($arg:tt)*) => { /* compiler built-in */ diff --git a/std/src/lib.rs b/std/src/lib.rs index 585946c1d50e0..6be27b283b291 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -589,7 +589,7 @@ pub mod net; pub mod num; pub mod os; pub mod panic; -#[unstable(feature = "core_pattern_types", issue = "123646")] +#[unstable(feature = "pattern_type_macro", issue = "123646")] pub mod pat; pub mod path; #[unstable(feature = "anonymous_pipe", issue = "127154")] From 35184bd1c8b1a400b6ac1ba17385f4a0b8442856 Mon Sep 17 00:00:00 2001 From: "Brian J. Tarricone" Date: Mon, 15 Feb 2021 23:32:16 -0800 Subject: [PATCH 069/481] Teach rust core about Xtensa VaListImpl and add a custom lowering of vaarg for xtensa. LLVM does not include an implementation of the va_arg instruction for Xtensa. From what I understand, this is a conscious decision and instead language frontends are encouraged to implement it themselves. The rationale seems to be that loading values correctly requires language and ABI-specific knowledge that LLVM lacks. This is true of most architectures, and rustc already provides implementation for a number of them. This commit extends the support to include Xtensa. See https://lists.llvm.org/pipermail/llvm-dev/2017-August/116337.html for some discussion on the topic. Unfortunately there does not seem to be a reference document for the semantics of the va_list and va_arg on Xtensa. The most reliable source is the GCC implementation, which this commit tries to follow. Clang also provides its own compatible implementation. This was tested for all the types that rustc allows in variadics. Co-authored-by: Brian Tarricone Co-authored-by: Jonathan Bastien-Filiatrault Co-authored-by: Paul Lietar --- core/Cargo.toml | 1 + core/src/ffi/va_list.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/core/Cargo.toml b/core/Cargo.toml index cace4582b489a..46c55c437cce5 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -43,6 +43,7 @@ check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', 'cfg(stdarch_intel_sde)', + 'cfg(target_arch, values("xtensa"))', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/core/src/ffi/va_list.rs b/core/src/ffi/va_list.rs index 3a224e4d8fe5f..f67c592d8d8f7 100644 --- a/core/src/ffi/va_list.rs +++ b/core/src/ffi/va_list.rs @@ -15,6 +15,7 @@ use crate::ops::{Deref, DerefMut}; not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "s390x"), + not(target_arch = "xtensa"), not(target_arch = "x86_64") ), all(target_arch = "aarch64", target_vendor = "apple"), @@ -37,6 +38,7 @@ pub struct VaListImpl<'f> { not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "s390x"), + not(target_arch = "xtensa"), not(target_arch = "x86_64") ), all(target_arch = "aarch64", target_vendor = "apple"), @@ -113,6 +115,18 @@ pub struct VaListImpl<'f> { _marker: PhantomData<&'f mut &'f c_void>, } +/// Xtensa ABI implementation of a `va_list`. +#[cfg(target_arch = "xtensa")] +#[repr(C)] +#[derive(Debug)] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + stk: *mut i32, + reg: *mut i32, + ndx: i32, + _marker: PhantomData<&'f mut &'f c_void>, +} + /// A wrapper for a `va_list` #[repr(transparent)] #[derive(Debug)] @@ -124,6 +138,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), + target_arch = "xtensa", all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", @@ -138,6 +153,7 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), + not(target_arch = "xtensa"), any(not(target_arch = "aarch64"), not(target_vendor = "apple")), not(target_family = "wasm"), not(target_os = "uefi"), @@ -155,6 +171,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), + target_arch = "xtensa", all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", @@ -173,8 +190,10 @@ impl<'f> VaListImpl<'f> { target_arch = "aarch64", target_arch = "powerpc", target_arch = "s390x", + target_arch = "xtensa", target_arch = "x86_64" ), + not(target_arch = "xtensa"), any(not(target_arch = "aarch64"), not(target_vendor = "apple")), not(target_family = "wasm"), not(target_os = "uefi"), From b759d590909a3c760b5b9615db689e1f380d5428 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2024 08:37:23 +0100 Subject: [PATCH 070/481] clarify simd_relaxed_fma non-determinism --- core/src/intrinsics/simd.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/intrinsics/simd.rs b/core/src/intrinsics/simd.rs index 0d24b0558c594..f80a60d471c04 100644 --- a/core/src/intrinsics/simd.rs +++ b/core/src/intrinsics/simd.rs @@ -619,7 +619,8 @@ extern "rust-intrinsic" { /// set has support for a fused operation, and that the fused operation is more efficient /// than the equivalent, separate pair of mul and add instructions. It is unspecified /// whether or not a fused operation is selected, and that may depend on optimization - /// level and context, for example. + /// level and context, for example. It may even be the case that some SIMD lanes get fused + /// and others do not. /// /// `T` must be a vector of floats. #[cfg(not(bootstrap))] From ea4441673629b9f9e0d139bb9d3a5ce547120d43 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 4 Dec 2024 20:54:37 -0500 Subject: [PATCH 071/481] Improve comments for the default backtrace printer The existing comments were misleading, confusing, and wrong. Take this comment for example: ``` // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be // called before the panic hook, so we won't ignore any frames if there is no // invoke of `__rust_begin_short_backtrace`. ``` this is just wrong. here is an example (full) backtrace: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s Running `/home/jyn/.local/lib/cargo/target/debug/example` called `Option::unwrap()` on a `None` value stack backtrace: 0: 0x56499698c595 - std::backtrace_rs::backtrace::libunwind::trace::h5ef2cc16e9a7415a 1: 0x56499698c595 - std::backtrace_rs::backtrace::trace_unsynchronized::h9b5e016e9075f714 2: 0x56499698c595 - std::sys_common::backtrace::_print_fmt::h2f62c7f9ff224e93 3: 0x56499698c595 - ::fmt::hbe51682735731910 4: 0x5649969aa26b - core::fmt::rt::Argument::fmt::h1994ab2b310d665e 5: 0x5649969aa26b - core::fmt::write::hade58a36d63468d7 6: 0x56499698a43f - std::io::Write::write_fmt::h16145587d801a9ab 7: 0x56499698c36e - std::sys_common::backtrace::_print::ha8082e56201dadb4 8: 0x56499698c36e - std::sys_common::backtrace::print::he30f96b4e7f6cbfd 9: 0x56499698d709 - std::panicking::default_hook::{{closure}}::hf0801f6b18a968d3 10: 0x56499698d4ac - std::panicking::default_hook::hd2defec7eda5aeb0 11: 0x56499698dc31 - std::panicking::rust_panic_with_hook::hde93283600065c53 12: 0x56499698daf3 - std::panicking::begin_panic_handler::{{closure}}::h5e151adbdb7ec0c1 13: 0x56499698ca59 - std::sys_common::backtrace::__rust_end_short_backtrace::he36a1407e0f77700 14: 0x56499698d7d4 - rust_begin_unwind 15: 0x5649969a9503 - core::panicking::panic_fmt::h2380d41365f95412 16: 0x5649969a958c - core::panicking::panic::h38cf8db80e8c6e67 17: 0x5649969a93e9 - core::option::unwrap_failed::he72696e53ff29a05 18: 0x5649969722b6 - core::option::Option::unwrap::hb574dc0dc1703062 19: 0x5649969722b6 - example::main::h7a867aafacd93d75 20: 0x5649969721db - core::ops::function::FnOnce::call_once::h734f99a5e57291b7 21: 0x56499697226e - std::sys_common::backtrace::__rust_begin_short_backtrace::h02f5d58c351c4756 22: 0x564996972241 - std::rt::lang_start::{{closure}}::h8b134fe2c31a4355 23: 0x564996988662 - core::ops::function::impls:: for &F>::call_once::h88d7bb571ee2aaf4 24: 0x564996988662 - std::panicking::try::do_call::hfb78dfb6599c871d 25: 0x564996988662 - std::panicking::try::habd041c8c4c8e50c 27: 0x564996988662 - std::rt::lang_start_internal::{{closure}}::h227591a6f9c0879e 28: 0x564996988662 - std::panicking::try::do_call::h3c5878333c38916a 29: 0x564996988662 - std::panicking::try::h5af7b3a127cdae70 31: 0x564996988662 - std::rt::lang_start_internal::hbc85e809eeace0dd 32: 0x56499697221a - std::rt::lang_start::ha1eb16922c9cb224 33: 0x5649969722ee - main 34: 0x7f031962a1ca - __libc_start_call_main 35: 0x7f031962a28b - __libc_start_main_impl 36: 0x5649969720a5 - _start 37: 0x0 - ``` note particularly frames 13-21, from start_backtrace to end_backtrace. with PrintFmt::Short, these are the *only* frames that are printed; i.e. we are doing the exact opposite of the comment. --- std/src/sys/backtrace.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/std/src/sys/backtrace.rs b/std/src/sys/backtrace.rs index 4d939e175cf2e..efa6a896dad8f 100644 --- a/std/src/sys/backtrace.rs +++ b/std/src/sys/backtrace.rs @@ -58,8 +58,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: let mut res = Ok(()); let mut omitted_count: usize = 0; let mut first_omit = true; - // Start immediately if we're not using a short backtrace. - let mut start = print_fmt != PrintFmt::Short; + // If we're using a short backtrace, ignore all frames until we're told to start printing. + let mut print = print_fmt != PrintFmt::Short; set_image_base(); // SAFETY: we roll our own locking in this town unsafe { @@ -72,27 +72,25 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { hit = true; - // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` - // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be - // called before the panic hook, so we won't ignore any frames if there is no - // invoke of `__rust_begin_short_backtrace`. + // `__rust_end_short_backtrace` means we are done hiding symbols + // for now. Print until we see `__rust_begin_short_backtrace`. if print_fmt == PrintFmt::Short { if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if start && sym.contains("__rust_begin_short_backtrace") { - start = false; + if sym.contains("__rust_end_short_backtrace") { + print = true; return; } - if sym.contains("__rust_end_short_backtrace") { - start = true; + if print && sym.contains("__rust_begin_short_backtrace") { + print = false; return; } - if !start { + if !print { omitted_count += 1; } } } - if start { + if print { if omitted_count > 0 { debug_assert!(print_fmt == PrintFmt::Short); // only print the message between the middle of frames @@ -112,7 +110,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: }); #[cfg(target_os = "nto")] if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { - if !hit && start { + if !hit && print { use crate::backtrace_rs::SymbolName; res = bt_fmt.frame().print_raw( frame.ip(), @@ -123,7 +121,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: } return false; } - if !hit && start { + if !hit && print { res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } From 61bbc6221a4a97e8a40a1d03d4003313c03a1e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 4 Dec 2024 23:02:25 +0100 Subject: [PATCH 072/481] Reformat Python code with `ruff` --- core/src/unicode/printable.py | 53 ++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/core/src/unicode/printable.py b/core/src/unicode/printable.py index 4d39ace066c46..260fa9f9e6ad2 100755 --- a/core/src/unicode/printable.py +++ b/core/src/unicode/printable.py @@ -9,7 +9,8 @@ import os import subprocess -NUM_CODEPOINTS=0x110000 +NUM_CODEPOINTS = 0x110000 + def to_ranges(iter): current = None @@ -23,11 +24,15 @@ def to_ranges(iter): if current is not None: yield tuple(current) + def get_escaped(codepoints): for c in codepoints: - if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): + if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord( + " " + ): yield c.value + def get_file(f): try: return open(os.path.basename(f)) @@ -35,7 +40,9 @@ def get_file(f): subprocess.run(["curl", "-O", f], check=True) return open(os.path.basename(f)) -Codepoint = namedtuple('Codepoint', 'value class_') + +Codepoint = namedtuple("Codepoint", "value class_") + def get_codepoints(f): r = csv.reader(f, delimiter=";") @@ -66,13 +73,14 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) + def compress_singletons(singletons): - uppers = [] # (upper, # items in lowers) + uppers = [] # (upper, # items in lowers) lowers = [] for i in singletons: upper = i >> 8 - lower = i & 0xff + lower = i & 0xFF if len(uppers) == 0 or uppers[-1][0] != upper: uppers.append((upper, 1)) else: @@ -82,10 +90,11 @@ def compress_singletons(singletons): return uppers, lowers + def compress_normal(normal): # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff - compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] prev_start = 0 for start, count in normal: @@ -95,21 +104,22 @@ def compress_normal(normal): assert truelen < 0x8000 and falselen < 0x8000 entry = [] - if truelen > 0x7f: + if truelen > 0x7F: entry.append(0x80 | (truelen >> 8)) - entry.append(truelen & 0xff) + entry.append(truelen & 0xFF) else: - entry.append(truelen & 0x7f) - if falselen > 0x7f: + entry.append(truelen & 0x7F) + if falselen > 0x7F: entry.append(0x80 | (falselen >> 8)) - entry.append(falselen & 0xff) + entry.append(falselen & 0xFF) else: - entry.append(falselen & 0x7f) + entry.append(falselen & 0x7F) compressed.append(entry) return compressed + def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[(u8, u8)] = &[".format(uppersname)) @@ -119,9 +129,12 @@ def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(lowersname)) for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(x) for x in lowers[i:i+8]))) + print( + " {}".format(" ".join("{:#04x},".format(x) for x in lowers[i : i + 8])) + ) print("];") + def print_normal(normal, normalname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(normalname)) @@ -129,12 +142,13 @@ def print_normal(normal, normalname): print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) print("];") + def main(): file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt") codepoints = get_codepoints(file) - CUTOFF=0x10000 + CUTOFF = 0x10000 singletons0 = [] singletons1 = [] normal0 = [] @@ -234,10 +248,11 @@ def main(): }\ """) print() - print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') - print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') - print_normal(normal0, 'NORMAL0') - print_normal(normal1, 'NORMAL1') + print_singletons(singletons0u, singletons0l, "SINGLETONS0U", "SINGLETONS0L") + print_singletons(singletons1u, singletons1l, "SINGLETONS1U", "SINGLETONS1L") + print_normal(normal0, "NORMAL0") + print_normal(normal1, "NORMAL1") + -if __name__ == '__main__': +if __name__ == "__main__": main() From d730060ff82a34a338f0c9b094e03622b14e50e7 Mon Sep 17 00:00:00 2001 From: Xelph Date: Tue, 3 Dec 2024 01:23:28 -0700 Subject: [PATCH 073/481] Improve documentation Fix missing newlines that rustfmt removed. fix trailing whitespace Fix duplicate word. Reformat panic reasons into a list remove trailing whitespace 2 electric boogaloo Change verbe tense. Integrate suggestions --- alloc/src/vec/mod.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 4b706086e0770..457be3ae77fc6 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -3025,26 +3025,29 @@ impl Vec { self.spec_extend(other.iter()) } - /// Copies elements from `src` range to the end of the vector. + /// Given a range `src`, clones a slice of elements in that range and appends it to the end. + /// + /// `src` must be a range that can form a valid subslice of the `Vec`. /// /// # Panics /// - /// Panics if the starting point is greater than the end point or if - /// the end point is greater than the length of the vector. + /// Panics if starting index is greater than the end index + /// or if the index is greater than the length of the vector. /// /// # Examples /// /// ``` - /// let mut vec = vec![0, 1, 2, 3, 4]; - /// - /// vec.extend_from_within(2..); - /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4]); + /// let mut characters = vec!['a', 'b', 'c', 'd', 'e']; + /// characters.extend_from_within(2..); + /// assert_eq!(characters, ['a', 'b', 'c', 'd', 'e', 'c', 'd', 'e']); /// - /// vec.extend_from_within(..2); - /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]); + /// let mut numbers = vec![0, 1, 2, 3, 4]; + /// numbers.extend_from_within(..2); + /// assert_eq!(numbers, [0, 1, 2, 3, 4, 0, 1]); /// - /// vec.extend_from_within(4..8); - /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]); + /// let mut strings = vec![String::from("hello"), String::from("world"), String::from("!")]; + /// strings.extend_from_within(1..=2); + /// assert_eq!(strings, ["hello", "world", "!", "world", "!"]); /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_within", since = "1.53.0")] From c7ddb1783e8bdd7866d03bebefe319dbf6e366b4 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 15 Nov 2024 17:42:09 -0800 Subject: [PATCH 074/481] Stabilize noop_waker Co-authored-by: zachs18 <8355914+zachs18@users.noreply.github.com> --- alloc/src/task.rs | 1 - core/src/task/wake.rs | 13 +++++-------- core/tests/lib.rs | 1 - 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/alloc/src/task.rs b/alloc/src/task.rs index 0f8e74300a491..b4116f4988b64 100644 --- a/alloc/src/task.rs +++ b/alloc/src/task.rs @@ -199,7 +199,6 @@ fn raw_waker(waker: Arc) -> RawWaker { /// /// ```rust /// #![feature(local_waker)] -/// #![feature(noop_waker)] /// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker}; /// use std::future::Future; /// use std::pin::Pin; diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index 41e9c593ebdb3..6762ed54e5c9b 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -60,7 +60,8 @@ impl RawWaker { RawWaker { data, vtable } } - #[unstable(feature = "noop_waker", issue = "98286")] + #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] const NOOP: RawWaker = { const VTABLE: RawWakerVTable = RawWakerVTable::new( // Cloning just returns a new no-op raw waker @@ -283,7 +284,6 @@ impl fmt::Debug for Context<'_> { /// # Examples /// ``` /// #![feature(local_waker)] -/// #![feature(noop_waker)] /// use std::task::{ContextBuilder, LocalWaker, Waker, Poll}; /// use std::future::Future; /// @@ -555,8 +555,6 @@ impl Waker { /// # Examples /// /// ``` - /// #![feature(noop_waker)] - /// /// use std::future::Future; /// use std::task; /// @@ -567,7 +565,8 @@ impl Waker { /// ``` #[inline] #[must_use] - #[unstable(feature = "noop_waker", issue = "98286")] + #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] pub const fn noop() -> &'static Waker { const WAKER: &Waker = &Waker { waker: RawWaker::NOOP }; WAKER @@ -850,8 +849,6 @@ impl LocalWaker { /// /// ``` /// #![feature(local_waker)] - /// #![feature(noop_waker)] - /// /// use std::future::Future; /// use std::task::{ContextBuilder, LocalWaker, Waker, Poll}; /// @@ -864,7 +861,7 @@ impl LocalWaker { /// ``` #[inline] #[must_use] - #[unstable(feature = "noop_waker", issue = "98286")] + #[unstable(feature = "local_waker", issue = "118959")] pub const fn noop() -> &'static LocalWaker { const WAKER: &LocalWaker = &LocalWaker { waker: RawWaker::NOOP }; WAKER diff --git a/core/tests/lib.rs b/core/tests/lib.rs index e0b1c21e1ecb9..cb7c52bc3c5f2 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -61,7 +61,6 @@ #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(never_type)] -#![feature(noop_waker)] #![feature(num_midpoint_signed)] #![feature(numfmt)] #![feature(pattern)] From b9598856377d9b1664287f8cdc780797a39bca08 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:14:41 +0100 Subject: [PATCH 075/481] Formatter: Access members via getter methods wherever possible The idea behind this is to make implementing `fmt::FormattingOptions` (as well as any future changes to `std::Formatter`) easier. In theory, this might have a negative performance impact because of the additional function calls. However, I strongly believe that those will be inlined anyway, thereby producing assembly code that has comparable performance. --- core/src/fmt/float.rs | 6 +++--- core/src/fmt/mod.rs | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/src/fmt/float.rs b/core/src/fmt/float.rs index 04230b1610aae..ee7a8f08f1986 100644 --- a/core/src/fmt/float.rs +++ b/core/src/fmt/float.rs @@ -86,7 +86,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.precision { + if let Some(precision) = fmt.precision() { float_to_decimal_common_exact(fmt, num, sign, precision) } else { let min_precision = 0; @@ -162,7 +162,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.precision { + if let Some(precision) = fmt.precision() { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { @@ -180,7 +180,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.precision { + if let Some(precision) = fmt.precision() { // this behavior of {:.PREC?} predates exponential formatting for {:?} float_to_decimal_common_exact(fmt, num, sign, precision) } else { diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 7fc9dd21fdd81..1023fad803771 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -1365,7 +1365,7 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.width { + match self.width() { // If there's no minimum length requirements then we can just // write the bytes. None => { @@ -1433,12 +1433,12 @@ impl<'a> Formatter<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front - if self.width.is_none() && self.precision.is_none() { + if self.width().is_none() && self.precision().is_none() { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the // string being formatted. - let s = if let Some(max) = self.precision { + let s = if let Some(max) = self.precision() { // If our string is longer that the precision, then we must have // truncation. However other flags like `fill`, `width` and `align` // must act as always. @@ -1455,7 +1455,7 @@ impl<'a> Formatter<'a> { &s }; // The `width` field is more of a `min-width` parameter at this point. - match self.width { + match self.width() { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string None => self.buf.write_str(s), @@ -1501,10 +1501,10 @@ impl<'a> Formatter<'a> { }; for _ in 0..pre_pad { - self.buf.write_char(self.fill)?; + self.buf.write_char(self.fill())?; } - Ok(PostPadding::new(self.fill, post_pad)) + Ok(PostPadding::new(self.fill(), post_pad)) } /// Takes the formatted parts and applies the padding. @@ -1516,12 +1516,12 @@ impl<'a> Formatter<'a> { /// /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - if let Some(mut width) = self.width { + if let Some(mut width) = self.width() { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. let mut formatted = formatted.clone(); - let old_fill = self.fill; - let old_align = self.align; + let old_fill = self.fill(); + let old_align = self.align(); if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -2502,7 +2502,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - if f.width.is_none() && f.precision.is_none() { + if f.width().is_none() && f.precision().is_none() { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; 4])) @@ -2526,8 +2526,8 @@ impl Pointer for *const T { /// /// [problematic]: https://github.com/rust-lang/rust/issues/95489 pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result { - let old_width = f.width; - let old_flags = f.flags; + let old_width = f.width(); + let old_flags = f.flags(); // The alternate flag is already treated by LowerHex as being special- // it denotes whether to prefix with 0x. We use it to work out whether @@ -2536,7 +2536,7 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul if f.alternate() { f.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); - if f.width.is_none() { + if f.width().is_none() { f.width = Some((usize::BITS / 4) as usize + 2); } } From a8bdd278a1fda287be72e56de31740ab32728b13 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:52:13 +0100 Subject: [PATCH 076/481] Added struct `fmt::FormattingOptions` This allows to build custom `std::Formatter`s at runtime. Also added some related enums and two related methods on `std::Formatter`. --- alloc/src/fmt.rs | 2 + alloc/src/lib.rs | 1 + alloc/src/string.rs | 3 +- core/src/fmt/mod.rs | 381 ++++++++++++++++++++++++++++++++++-------- core/tests/fmt/mod.rs | 28 ++++ core/tests/lib.rs | 1 + std/src/lib.rs | 1 + std/src/panicking.rs | 2 +- 8 files changed, 349 insertions(+), 70 deletions(-) diff --git a/alloc/src/fmt.rs b/alloc/src/fmt.rs index 695dddb25eeb4..e40de13f3d4a9 100644 --- a/alloc/src/fmt.rs +++ b/alloc/src/fmt.rs @@ -596,6 +596,8 @@ pub use core::fmt::{Arguments, write}; pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Debug, Display}; +#[unstable(feature = "formatting_options", issue = "118117")] +pub use core::fmt::{DebugAsHex, FormattingOptions, Sign}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 84f4202c02a9b..927c3aa23b9f7 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -117,6 +117,7 @@ #![feature(extend_one_unchecked)] #![feature(fmt_internals)] #![feature(fn_traits)] +#![feature(formatting_options)] #![feature(hasher_prefixfree_extras)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] diff --git a/alloc/src/string.rs b/alloc/src/string.rs index e0576c2551545..d0d0276c55e7d 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -43,6 +43,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::error::Error; +use core::fmt::FormattingOptions; use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::iter::from_fn; @@ -2682,7 +2683,7 @@ impl ToString for T { #[inline] default fn to_string(&self) -> String { let mut buf = String::new(); - let mut formatter = core::fmt::Formatter::new(&mut buf); + let mut formatter = core::fmt::Formatter::new(&mut buf, FormattingOptions::new()); // Bypass format_args!() to avoid write_str with zero-length strs fmt::Display::fmt(self, &mut formatter) .expect("a Display implementation returned an error unexpectedly"); diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 1023fad803771..8e08b7fe983df 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -33,6 +33,19 @@ pub enum Alignment { Center, } +#[doc(hidden)] +#[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] +impl From for Option { + fn from(value: rt::Alignment) -> Self { + match value { + rt::Alignment::Left => Some(Alignment::Left), + rt::Alignment::Right => Some(Alignment::Right), + rt::Alignment::Center => Some(Alignment::Center), + rt::Alignment::Unknown => None, + } + } +} + #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[unstable(feature = "debug_closure_helpers", issue = "117729")] @@ -247,6 +260,243 @@ impl Write for &mut W { } } +/// The signedness of a [`Formatter`] (or of a [`FormattingOptions`]). +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[unstable(feature = "formatting_options", issue = "118117")] +pub enum Sign { + /// Represents the `+` flag. + Plus, + /// Represents the `-` flag. + Minus, +} + +/// Specifies whether the [`Debug`] trait should use lower-/upper-case +/// hexadecimal or normal integers. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[unstable(feature = "formatting_options", issue = "118117")] +pub enum DebugAsHex { + /// Use lower-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). + Lower, + /// Use upper-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). + Upper, +} + +/// Options for formatting. +/// +/// `FormattingOptions` is a [`Formatter`] without an attached [`Write`] trait. +/// It is mainly used to construct `Formatter` instances. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[unstable(feature = "formatting_options", issue = "118117")] +pub struct FormattingOptions { + sign: Option, + sign_aware_zero_pad: bool, + alternate: bool, + fill: char, + alignment: Option, + width: Option, + precision: Option, + debug_as_hex: Option, +} + +impl FormattingOptions { + /// Construct a new `FormatterBuilder` with the supplied `Write` trait + /// object for output that is equivalent to the `{}` formatting + /// specifier: + /// + /// - no flags, + /// - filled with spaces, + /// - no alignment, + /// - no width, + /// - no precision, and + /// - no [`DebugAsHex`] output mode. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn new() -> Self { + Self { + sign: None, + sign_aware_zero_pad: false, + alternate: false, + fill: ' ', + alignment: None, + width: None, + precision: None, + debug_as_hex: None, + } + } + + /// 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. + /// - `-`: Currently not used + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn sign(&mut self, sign: Option) -> &mut Self { + self.sign = sign; + self + } + /// Sets or unsets the `0` flag. + /// + /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + self.sign_aware_zero_pad = sign_aware_zero_pad; + self + } + /// Sets or unsets the `#` flag. + /// + /// This flag indicates that the "alternate" form of printing should be + /// used. The alternate forms are: + /// - [`Debug`] : pretty-print the [`Debug`] formatting (adds linebreaks and indentation) + /// - [`LowerHex`] as well as [`UpperHex`] - precedes the argument with a `0x` + /// - [`Octal`] - precedes the argument with a `0b` + /// - [`Binary`] - precedes the argument with a `0o` + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn alternate(&mut self, alternate: bool) -> &mut Self { + self.alternate = alternate; + self + } + /// Sets the fill character. + /// + /// The optional fill character and alignment is provided normally in + /// conjunction with the width parameter. This indicates that if the value + /// being formatted is smaller than width some extra characters will be + /// printed around it. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn fill(&mut self, fill: char) -> &mut Self { + self.fill = fill; + self + } + /// Sets or removes the alignment. + /// + /// The alignment specifies how the value being formatted should be + /// positioned if it is smaller than the width of the formatter. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn alignment(&mut self, alignment: Option) -> &mut Self { + self.alignment = alignment; + self + } + /// Sets or removes the width. + /// + /// This is a parameter for the “minimum width” that the format should take + /// up. If the value’s string does not fill up this many characters, then + /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::alignment`] + /// will be used to take up the required space. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn width(&mut self, width: Option) -> &mut Self { + self.width = width; + self + } + /// 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. + /// - For integral types, this is ignored. + /// - For floating-point types, this indicates how many digits after the + /// decimal point should be printed. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn precision(&mut self, precision: Option) -> &mut Self { + self.precision = precision; + self + } + /// Specifies whether the [`Debug`] trait should use lower-/upper-case + /// hexadecimal or normal integers + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { + self.debug_as_hex = debug_as_hex; + self + } + + /// Returns the current sign (the `+` or the `-` flag). + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_sign(&self) -> Option { + self.sign + } + /// Returns the current `0` flag. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_sign_aware_zero_pad(&self) -> bool { + self.sign_aware_zero_pad + } + /// Returns the current `#` flag. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_alternate(&self) -> bool { + self.alternate + } + /// Returns the current fill character. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_fill(&self) -> char { + self.fill + } + /// Returns the current alignment. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_alignment(&self) -> Option { + self.alignment + } + /// Returns the current width. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_width(&self) -> Option { + self.width + } + /// Returns the current precision. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_precision(&self) -> Option { + self.precision + } + /// Returns the current precision. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn get_debug_as_hex(&self) -> Option { + self.debug_as_hex + } + + /// Creates a [`Formatter`] that writes its output to the given [`Write`] trait. + /// + /// You may alternatively use [`Formatter::new()`]. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + Formatter { options: self, buf: write } + } + + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + /// Flags for formatting + pub fn flags(&mut self, flags: u32) { + self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { + Some(Sign::Plus) + } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { + Some(Sign::Minus) + } else { + None + }; + self.alternate = (flags & (1 << rt::Flag::Alternate as u32)) != 0; + self.sign_aware_zero_pad = (flags & (1 << rt::Flag::SignAwareZeroPad as u32)) != 0; + self.debug_as_hex = if flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 { + Some(DebugAsHex::Lower) + } else if flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 { + Some(DebugAsHex::Upper) + } else { + None + }; + } + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + /// Flags for formatting + pub fn get_flags(&self) -> u32 { + >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 + | >::into(self.get_sign() == Some(Sign::Minus)) + << rt::Flag::SignMinus as u32 + | >::into(self.get_alternate()) << rt::Flag::Alternate as u32 + | >::into(self.get_sign_aware_zero_pad()) + << rt::Flag::SignAwareZeroPad as u32 + | >::into(self.debug_as_hex == Some(DebugAsHex::Lower)) + << rt::Flag::DebugLowerHex as u32 + | >::into(self.debug_as_hex == Some(DebugAsHex::Upper)) + << rt::Flag::DebugUpperHex as u32 + } +} + /// Configuration for formatting. /// /// A `Formatter` represents various options related to formatting. Users do not @@ -260,34 +510,28 @@ impl Write for &mut W { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Formatter"] pub struct Formatter<'a> { - flags: u32, - fill: char, - align: rt::Alignment, - width: Option, - precision: Option, + options: FormattingOptions, buf: &'a mut (dyn Write + 'a), } impl<'a> Formatter<'a> { - /// Creates a new formatter with default settings. + /// Creates a new formatter with given [`FormattingOptions`]. /// - /// This can be used as a micro-optimization in cases where a full `Arguments` - /// structure (as created by `format_args!`) is not necessary; `Arguments` - /// is a little more expensive to use in simple formatting scenarios. + /// If `write` is a reference to a formatter, it is recommended to use + /// [`Formatter::with_options`] instead as this can borrow the underlying + /// `write`, thereby bypassing one layer of indirection. /// - /// Currently not intended for use outside of the standard library. - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] - #[doc(hidden)] - pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> { - Formatter { - flags: 0, - fill: ' ', - align: rt::Alignment::Unknown, - width: None, - precision: None, - buf, - } + /// You may alternatively use [`FormattingOptions::create_formatter()`]. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + Formatter { options, buf: write } + } + + /// Creates a new formatter based on this one with given [`FormattingOptions`]. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn with_options(&'a mut self, options: FormattingOptions) -> Self { + Formatter { options, buf: self.buf } } } @@ -1165,7 +1409,7 @@ pub trait UpperExp { /// [`write!`]: crate::write! #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { - let mut formatter = Formatter::new(output); + let mut formatter = Formatter::new(output, FormattingOptions::new()); let mut idx = 0; match args.fmt { @@ -1214,14 +1458,14 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.fill = arg.fill; - fmt.align = arg.align; - fmt.flags = arg.flags; + fmt.options.fill(arg.fill); + fmt.options.alignment(arg.align.into()); + fmt.options.flags(arg.flags); // SAFETY: arg and args come from the same Arguments, // which guarantees the indexes are always within bounds. unsafe { - fmt.width = getcount(args, &arg.width); - fmt.precision = getcount(args, &arg.precision); + fmt.options.width(getcount(args, &arg.width)); + fmt.options.precision(getcount(args, &arg.precision)); } // Extract the correct argument @@ -1280,11 +1524,7 @@ impl<'a> Formatter<'a> { buf: wrap(self.buf), // And preserve these - flags: self.flags, - fill: self.fill, - align: self.align, - width: self.width, - precision: self.precision, + options: self.options, } } @@ -1381,14 +1621,15 @@ impl<'a> Formatter<'a> { // The sign and prefix goes before the padding if the fill character // is zero Some(min) if self.sign_aware_zero_pad() => { - let old_fill = crate::mem::replace(&mut self.fill, '0'); - let old_align = crate::mem::replace(&mut self.align, rt::Alignment::Right); + let old_fill = crate::mem::replace(&mut self.options.fill, '0'); + let old_align = + crate::mem::replace(&mut self.options.alignment, Some(Alignment::Right)); write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, Alignment::Right)?; self.buf.write_str(buf)?; post_padding.write(self)?; - self.fill = old_fill; - self.align = old_align; + self.options.fill = old_fill; + self.options.alignment = old_align; Ok(()) } // Otherwise, the sign and prefix goes after the padding @@ -1487,12 +1728,7 @@ impl<'a> Formatter<'a> { padding: usize, default: Alignment, ) -> result::Result { - let align = match self.align { - rt::Alignment::Unknown => default, - rt::Alignment::Left => Alignment::Left, - rt::Alignment::Right => Alignment::Right, - rt::Alignment::Center => Alignment::Center, - }; + let align = self.align().unwrap_or(default); let (pre_pad, post_pad) = match align { Alignment::Left => (0, padding), @@ -1530,8 +1766,8 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len()); - self.fill = '0'; - self.align = rt::Alignment::Right; + self.options.fill('0'); + self.options.alignment(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1548,8 +1784,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.fill = old_fill; - self.align = old_align; + self.options.fill(old_fill); + self.options.alignment(old_align); ret } else { // this is the common case and we take a shortcut @@ -1675,7 +1911,7 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.flags + self.options.get_flags() } /// Returns the character used as 'fill' whenever there is alignment. @@ -1708,7 +1944,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.fill + self.options.get_fill() } /// Returns a flag indicating what form of alignment was requested. @@ -1743,12 +1979,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - match self.align { - rt::Alignment::Left => Some(Alignment::Left), - rt::Alignment::Right => Some(Alignment::Right), - rt::Alignment::Center => Some(Alignment::Center), - rt::Alignment::Unknown => None, - } + self.options.get_alignment() } /// Returns the optionally specified integer width that the output should be. @@ -1778,7 +2009,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.width + self.options.get_width() } /// Returns the optionally specified precision for numeric types. @@ -1809,7 +2040,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.precision + self.options.get_precision() } /// Determines if the `+` flag was specified. @@ -1841,7 +2072,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.flags & (1 << rt::Flag::SignPlus as u32) != 0 + self.options.get_sign() == Some(Sign::Plus) } /// Determines if the `-` flag was specified. @@ -1870,7 +2101,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.flags & (1 << rt::Flag::SignMinus as u32) != 0 + self.options.get_sign() == Some(Sign::Minus) } /// Determines if the `#` flag was specified. @@ -1898,7 +2129,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.flags & (1 << rt::Flag::Alternate as u32) != 0 + self.options.get_alternate() } /// Determines if the `0` flag was specified. @@ -1924,17 +2155,17 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 + self.options.get_sign_aware_zero_pad() } // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 + self.options.debug_as_hex == Some(DebugAsHex::Lower) } fn debug_upper_hex(&self) -> bool { - self.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 + self.options.debug_as_hex == Some(DebugAsHex::Upper) } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2350,6 +2581,18 @@ impl<'a> Formatter<'a> { pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, 'a> { builders::debug_map_new(self) } + + /// Returns the sign of this formatter (`+` or `-`). + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn sign(&self) -> Option { + self.options.get_sign() + } + + /// Returns the formatting options this formatter corresponds to. + #[unstable(feature = "formatting_options", issue = "118117")] + pub fn options(&self) -> FormattingOptions { + self.options + } } #[stable(since = "1.2.0", feature = "formatter_write")] @@ -2527,25 +2770,27 @@ impl Pointer for *const T { /// [problematic]: https://github.com/rust-lang/rust/issues/95489 pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result { let old_width = f.width(); - let old_flags = f.flags(); + let old_alternate = f.alternate(); + let old_zero_pad = f.sign_aware_zero_pad(); // The alternate flag is already treated by LowerHex as being special- // it denotes whether to prefix with 0x. We use it to work out whether // or not to zero extend, and then unconditionally set it to get the // prefix. if f.alternate() { - f.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); + f.options.sign_aware_zero_pad(true); if f.width().is_none() { - f.width = Some((usize::BITS / 4) as usize + 2); + f.options.width(Some((usize::BITS / 4) as usize + 2)); } } - f.flags |= 1 << (rt::Flag::Alternate as u32); + f.options.alternate(true); let ret = LowerHex::fmt(&ptr_addr, f); - f.width = old_width; - f.flags = old_flags; + f.options.width(old_width); + f.options.alternate(old_alternate); + f.options.sign_aware_zero_pad(old_zero_pad); ret } diff --git a/core/tests/fmt/mod.rs b/core/tests/fmt/mod.rs index f7512abae3820..9aedfdefa688d 100644 --- a/core/tests/fmt/mod.rs +++ b/core/tests/fmt/mod.rs @@ -50,3 +50,31 @@ fn test_maybe_uninit_short() { let x = core::mem::MaybeUninit::new(0u32); assert_eq!(format!("{x:?}"), "MaybeUninit"); } + +#[test] +fn formatting_options_flags() { + use core::fmt::*; + for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] { + for alternate in [true, false] { + for sign_aware_zero_pad in [true, false] { + for debug_as_hex in [None, Some(DebugAsHex::Lower), Some(DebugAsHex::Upper)] { + let mut original_formatting_options = FormattingOptions::new(); + original_formatting_options + .sign(sign) + .sign_aware_zero_pad(sign_aware_zero_pad) + .alternate(alternate) + .debug_as_hex(debug_as_hex); + + let mut formatting_options_with_flags_set_to_self = original_formatting_options; + formatting_options_with_flags_set_to_self + .flags(formatting_options_with_flags_set_to_self.get_flags()); + + assert_eq!( + original_formatting_options, formatting_options_with_flags_set_to_self, + "Reading and setting flags changes FormattingOptions; Sign({sign:?}), Alternate({alternate:?}). DebugAsHex({debug_as_hex:?})" + ) + } + } + } + } +} diff --git a/core/tests/lib.rs b/core/tests/lib.rs index cb7c52bc3c5f2..a4a794691fe38 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -31,6 +31,7 @@ #![feature(float_minimum_maximum)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(formatting_options)] #![feature(freeze)] #![feature(future_join)] #![feature(generic_assert_internals)] diff --git a/std/src/lib.rs b/std/src/lib.rs index 6be27b283b291..49a0322003905 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -292,6 +292,7 @@ #![feature(dropck_eyepatch)] #![feature(f128)] #![feature(f16)] +#![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(lang_items)] diff --git a/std/src/panicking.rs b/std/src/panicking.rs index 97f800dddaa43..dca5ccca0c404 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -623,7 +623,7 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { // Lazily, the first time this gets called, run the actual string formatting. self.string.get_or_insert_with(|| { let mut s = String::new(); - let mut fmt = fmt::Formatter::new(&mut s); + let mut fmt = fmt::Formatter::new(&mut s, fmt::FormattingOptions::new()); let _err = fmt::Display::fmt(&inner, &mut fmt); s }) From 0a2bec4c7e230c7b1ee709770de8162c25bd24a3 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Wed, 22 Nov 2023 23:40:01 +0100 Subject: [PATCH 077/481] Fixed another broken test --- alloc/src/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index d0d0276c55e7d..c5378d78d591b 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -43,7 +43,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::error::Error; -use core::fmt::FormattingOptions; use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::iter::from_fn; @@ -2683,7 +2682,8 @@ impl ToString for T { #[inline] default fn to_string(&self) -> String { let mut buf = String::new(); - let mut formatter = core::fmt::Formatter::new(&mut buf, FormattingOptions::new()); + let mut formatter = + core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new()); // Bypass format_args!() to avoid write_str with zero-length strs fmt::Display::fmt(self, &mut formatter) .expect("a Display implementation returned an error unexpectedly"); From 0baf8fe83061e6ccbbdbf19d797da1dd4b24253f Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Mon, 27 Nov 2023 03:31:29 +0100 Subject: [PATCH 078/481] Formatter::with_options: Use different lifetimes Formatter::with_options takes self as a mutable reference (`&'a mut Formatter<'b>`). `'a` and `'b` need to be different lifetimes. Just taking `&'a mut Formatter<'a>` and trusting in Rust being able to implicitely convert from `&'a mut Formatter<'b>` if necessary (after all, `'a` must be smaller than `'b` anyway) fails because `'b` is behind a *mutable* reference. For background on on this behavior, see https://doc.rust-lang.org/nomicon/subtyping.html#variance. --- core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 8e08b7fe983df..a5c0e1ce4e30d 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -530,7 +530,7 @@ impl<'a> Formatter<'a> { /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn with_options(&'a mut self, options: FormattingOptions) -> Self { + pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } From 8b88222aca1f04769f10e8b284bbf41f8dd5afdc Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Mon, 27 Nov 2023 04:06:00 +0100 Subject: [PATCH 079/481] fmt::FormattingOptions: Renamed `alignment` to `align` Likewise for `get_alignment`. This is how the method is named on `Formatter`, I want to keep it consistent. --- core/src/fmt/mod.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index a5c0e1ce4e30d..8e1d5d1ae6209 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -292,7 +292,7 @@ pub struct FormattingOptions { sign_aware_zero_pad: bool, alternate: bool, fill: char, - alignment: Option, + align: Option, width: Option, precision: Option, debug_as_hex: Option, @@ -316,7 +316,7 @@ impl FormattingOptions { sign_aware_zero_pad: false, alternate: false, fill: ' ', - alignment: None, + align: None, width: None, precision: None, debug_as_hex: None, @@ -373,15 +373,15 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn alignment(&mut self, alignment: Option) -> &mut Self { - self.alignment = alignment; + pub fn align(&mut self, align: Option) -> &mut Self { + self.align = align; self } /// Sets or removes the width. /// /// This is a parameter for the “minimum width” that the format should take /// up. If the value’s string does not fill up this many characters, then - /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::alignment`] + /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] pub fn width(&mut self, width: Option) -> &mut Self { @@ -432,8 +432,8 @@ impl FormattingOptions { } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_alignment(&self) -> Option { - self.alignment + pub fn get_align(&self) -> Option { + self.align } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] @@ -1459,7 +1459,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { fmt.options.fill(arg.fill); - fmt.options.alignment(arg.align.into()); + fmt.options.align(arg.align.into()); fmt.options.flags(arg.flags); // SAFETY: arg and args come from the same Arguments, // which guarantees the indexes are always within bounds. @@ -1623,13 +1623,13 @@ impl<'a> Formatter<'a> { Some(min) if self.sign_aware_zero_pad() => { let old_fill = crate::mem::replace(&mut self.options.fill, '0'); let old_align = - crate::mem::replace(&mut self.options.alignment, Some(Alignment::Right)); + crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, Alignment::Right)?; self.buf.write_str(buf)?; post_padding.write(self)?; self.options.fill = old_fill; - self.options.alignment = old_align; + self.options.align = old_align; Ok(()) } // Otherwise, the sign and prefix goes after the padding @@ -1767,7 +1767,7 @@ impl<'a> Formatter<'a> { formatted.sign = ""; width = width.saturating_sub(sign.len()); self.options.fill('0'); - self.options.alignment(Some(Alignment::Right)); + self.options.align(Some(Alignment::Right)); } // remaining parts go through the ordinary padding process. @@ -1785,7 +1785,7 @@ impl<'a> Formatter<'a> { post_padding.write(self) }; self.options.fill(old_fill); - self.options.alignment(old_align); + self.options.align(old_align); ret } else { // this is the common case and we take a shortcut @@ -1979,7 +1979,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - self.options.get_alignment() + self.options.get_align() } /// Returns the optionally specified integer width that the output should be. From 00f527852527cd4d2148cf5f9718cd7de179cbe0 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:29:06 +0100 Subject: [PATCH 080/481] Fixed copy+paste error in comment Co-authored-by: Mara Bos --- core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 8e1d5d1ae6209..a3b907df8ee10 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -277,7 +277,7 @@ pub enum Sign { pub enum DebugAsHex { /// Use lower-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). Lower, - /// Use upper-case hexadecimal integers for the `Debug` trait (like [the `x?` type](../../std/fmt/index.html#formatting-traits)). + /// Use upper-case hexadecimal integers for the `Debug` trait (like [the `X?` type](../../std/fmt/index.html#formatting-traits)). Upper, } From 7992f74eb118453f4938228b4a4d4345aa5f1bf7 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:30:59 +0100 Subject: [PATCH 081/481] impl Default for fmt::FormattingOptions --- core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index a3b907df8ee10..42afc903c83c2 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -285,7 +285,7 @@ pub enum DebugAsHex { /// /// `FormattingOptions` is a [`Formatter`] without an attached [`Write`] trait. /// It is mainly used to construct `Formatter` instances. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { sign: Option, From 8dbaa55201c1696b6cd6dfbedd6f12f8ad809a52 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:19:22 +0100 Subject: [PATCH 082/481] Made all fns const --- core/src/fmt/mod.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 42afc903c83c2..e2f0597b74d92 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -310,7 +310,7 @@ impl FormattingOptions { /// - no precision, and /// - no [`DebugAsHex`] output mode. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn new() -> Self { + pub const fn new() -> Self { Self { sign: None, sign_aware_zero_pad: false, @@ -332,7 +332,7 @@ impl FormattingOptions { /// always be printed. /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign(&mut self, sign: Option) -> &mut Self { + pub const fn sign(&mut self, sign: Option) -> &mut Self { self.sign = sign; self } @@ -340,7 +340,7 @@ impl FormattingOptions { /// /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { self.sign_aware_zero_pad = sign_aware_zero_pad; self } @@ -353,7 +353,7 @@ impl FormattingOptions { /// - [`Octal`] - precedes the argument with a `0b` /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] - pub fn alternate(&mut self, alternate: bool) -> &mut Self { + pub const fn alternate(&mut self, alternate: bool) -> &mut Self { self.alternate = alternate; self } @@ -364,7 +364,7 @@ impl FormattingOptions { /// being formatted is smaller than width some extra characters will be /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn fill(&mut self, fill: char) -> &mut Self { + pub const fn fill(&mut self, fill: char) -> &mut Self { self.fill = fill; self } @@ -373,7 +373,7 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn align(&mut self, align: Option) -> &mut Self { + pub const fn align(&mut self, align: Option) -> &mut Self { self.align = align; self } @@ -384,7 +384,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn width(&mut self, width: Option) -> &mut Self { + pub const fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -398,56 +398,56 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn precision(&mut self, precision: Option) -> &mut Self { + pub const fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; self } /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] - pub fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { + pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { self.debug_as_hex = debug_as_hex; self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_sign(&self) -> Option { + pub const fn get_sign(&self) -> Option { self.sign } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_sign_aware_zero_pad(&self) -> bool { + pub const fn get_sign_aware_zero_pad(&self) -> bool { self.sign_aware_zero_pad } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_alternate(&self) -> bool { + pub const fn get_alternate(&self) -> bool { self.alternate } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_fill(&self) -> char { + pub const fn get_fill(&self) -> char { self.fill } /// Returns the current alignment. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_align(&self) -> Option { + pub const fn get_align(&self) -> Option { self.align } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_width(&self) -> Option { + pub const fn get_width(&self) -> Option { self.width } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_precision(&self) -> Option { + pub const fn get_precision(&self) -> Option { self.precision } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn get_debug_as_hex(&self) -> Option { + pub const fn get_debug_as_hex(&self) -> Option { self.debug_as_hex } @@ -455,7 +455,7 @@ impl FormattingOptions { /// /// You may alternatively use [`Formatter::new()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + pub const fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } @@ -524,13 +524,13 @@ impl<'a> Formatter<'a> { /// /// You may alternatively use [`FormattingOptions::create_formatter()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + pub const fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { Formatter { options, buf: write } } /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { + pub const fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } @@ -2584,13 +2584,13 @@ impl<'a> Formatter<'a> { /// Returns the sign of this formatter (`+` or `-`). #[unstable(feature = "formatting_options", issue = "118117")] - pub fn sign(&self) -> Option { + pub const fn sign(&self) -> Option { self.options.get_sign() } /// Returns the formatting options this formatter corresponds to. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn options(&self) -> FormattingOptions { + pub const fn options(&self) -> FormattingOptions { self.options } } From ed043c523757863259a27a6111a3e21c6dc1fbc1 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 01:30:20 +0100 Subject: [PATCH 083/481] Turned public+unstable+hidden functions into private functions --- core/src/fmt/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index e2f0597b74d92..4fda439881173 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -459,10 +459,8 @@ impl FormattingOptions { Formatter { options: self, buf: write } } - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - pub fn flags(&mut self, flags: u32) { + fn flags(&mut self, flags: u32) { self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { Some(Sign::Plus) } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { @@ -480,10 +478,8 @@ impl FormattingOptions { None }; } - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - pub fn get_flags(&self) -> u32 { + fn get_flags(&self) -> u32 { >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 | >::into(self.get_sign() == Some(Sign::Minus)) << rt::Flag::SignMinus as u32 From 412a7746f3233ef962b6f4c2bf201dd942a37724 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 02:04:01 +0100 Subject: [PATCH 084/481] Revert "Turned public+unstable+hidden functions into private functions" See https://github.com/rust-lang/rust/pull/118159#discussion_r1491842170 for context. This reverts commit 62078dffcc1aefd4d678df94bca06e7b864065bd. --- core/src/fmt/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 4fda439881173..e2f0597b74d92 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -459,8 +459,10 @@ impl FormattingOptions { Formatter { options: self, buf: write } } + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - fn flags(&mut self, flags: u32) { + pub fn flags(&mut self, flags: u32) { self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { Some(Sign::Plus) } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { @@ -478,8 +480,10 @@ impl FormattingOptions { None }; } + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting - fn get_flags(&self) -> u32 { + pub fn get_flags(&self) -> u32 { >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 | >::into(self.get_sign() == Some(Sign::Minus)) << rt::Flag::SignMinus as u32 From 543b98fd0d57e313597e330a693f60a13ec33742 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 03:42:03 +0100 Subject: [PATCH 085/481] Refactored FormattingOptions to use a bitmask for storing flags --- core/src/fmt/mod.rs | 90 ++++++++++++++++++++++--------------------- core/tests/fmt/mod.rs | 16 +++----- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index e2f0597b74d92..9598dd33e9364 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -288,14 +288,11 @@ pub enum DebugAsHex { #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { - sign: Option, - sign_aware_zero_pad: bool, - alternate: bool, + flags: u32, fill: char, align: Option, width: Option, precision: Option, - debug_as_hex: Option, } impl FormattingOptions { @@ -312,14 +309,11 @@ impl FormattingOptions { #[unstable(feature = "formatting_options", issue = "118117")] pub const fn new() -> Self { Self { - sign: None, - sign_aware_zero_pad: false, - alternate: false, + flags: 0, fill: ' ', align: None, width: None, precision: None, - debug_as_hex: None, } } @@ -333,7 +327,12 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub const fn sign(&mut self, sign: Option) -> &mut Self { - self.sign = sign; + self.flags = self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); + match sign { + None => {}, + Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, + Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, + } self } /// Sets or unsets the `0` flag. @@ -341,7 +340,11 @@ impl FormattingOptions { /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { - self.sign_aware_zero_pad = sign_aware_zero_pad; + if sign_aware_zero_pad { + self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 + } else { + self.flags &= !(1 << rt::Flag::SignAwareZeroPad as u32) + } self } /// Sets or unsets the `#` flag. @@ -354,7 +357,11 @@ impl FormattingOptions { /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] pub const fn alternate(&mut self, alternate: bool) -> &mut Self { - self.alternate = alternate; + if alternate { + self.flags |= 1 << rt::Flag::Alternate as u32 + } else { + self.flags &= !(1 << rt::Flag::Alternate as u32) + } self } /// Sets the fill character. @@ -406,24 +413,36 @@ impl FormattingOptions { /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { - self.debug_as_hex = debug_as_hex; + self.flags = self.flags & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); + match debug_as_hex { + None => {}, + Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, + Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, + } self } /// Returns the current sign (the `+` or the `-` flag). #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign(&self) -> Option { - self.sign + const SIGN_PLUS_BITFIELD: u32 = 1 << rt::Flag::SignPlus as u32; + const SIGN_MINUS_BITFIELD: u32 = 1 << rt::Flag::SignMinus as u32; + match self.flags & ((1 << rt::Flag::SignPlus as u32) | (1 << rt::Flag::SignMinus as u32)) { + SIGN_PLUS_BITFIELD => Some(Sign::Plus), + SIGN_MINUS_BITFIELD => Some(Sign::Minus), + 0 => None, + _ => panic!("Invalid sign bits set in flags"), + } } /// Returns the current `0` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_sign_aware_zero_pad(&self) -> bool { - self.sign_aware_zero_pad + self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 } /// Returns the current `#` flag. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_alternate(&self) -> bool { - self.alternate + self.flags & (1 << rt::Flag::Alternate as u32) != 0 } /// Returns the current fill character. #[unstable(feature = "formatting_options", issue = "118117")] @@ -448,7 +467,14 @@ impl FormattingOptions { /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn get_debug_as_hex(&self) -> Option { - self.debug_as_hex + const DEBUG_UPPER_BITFIELD: u32 = 1 << rt::Flag::DebugUpperHex as u32; + const DEBUG_LOWER_BITFIELD: u32 = 1 << rt::Flag::DebugLowerHex as u32; + match self.flags & ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) { + DEBUG_UPPER_BITFIELD => Some(DebugAsHex::Upper), + DEBUG_LOWER_BITFIELD => Some(DebugAsHex::Lower), + 0 => None, + _ => panic!("Invalid hex debug bits set in flags"), + } } /// Creates a [`Formatter`] that writes its output to the given [`Write`] trait. @@ -463,37 +489,13 @@ impl FormattingOptions { #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting pub fn flags(&mut self, flags: u32) { - self.sign = if flags & (1 << rt::Flag::SignPlus as u32) != 0 { - Some(Sign::Plus) - } else if flags & (1 << rt::Flag::SignMinus as u32) != 0 { - Some(Sign::Minus) - } else { - None - }; - self.alternate = (flags & (1 << rt::Flag::Alternate as u32)) != 0; - self.sign_aware_zero_pad = (flags & (1 << rt::Flag::SignAwareZeroPad as u32)) != 0; - self.debug_as_hex = if flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 { - Some(DebugAsHex::Lower) - } else if flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 { - Some(DebugAsHex::Upper) - } else { - None - }; + self.flags = flags } #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] /// Flags for formatting pub fn get_flags(&self) -> u32 { - >::into(self.get_sign() == Some(Sign::Plus)) << rt::Flag::SignPlus as u32 - | >::into(self.get_sign() == Some(Sign::Minus)) - << rt::Flag::SignMinus as u32 - | >::into(self.get_alternate()) << rt::Flag::Alternate as u32 - | >::into(self.get_sign_aware_zero_pad()) - << rt::Flag::SignAwareZeroPad as u32 - | >::into(self.debug_as_hex == Some(DebugAsHex::Lower)) - << rt::Flag::DebugLowerHex as u32 - | >::into(self.debug_as_hex == Some(DebugAsHex::Upper)) - << rt::Flag::DebugUpperHex as u32 + self.flags } } @@ -2161,11 +2163,11 @@ impl<'a> Formatter<'a> { // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.options.debug_as_hex == Some(DebugAsHex::Lower) + self.options.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 } fn debug_upper_hex(&self) -> bool { - self.options.debug_as_hex == Some(DebugAsHex::Upper) + self.options.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of diff --git a/core/tests/fmt/mod.rs b/core/tests/fmt/mod.rs index 9aedfdefa688d..2c93a9bc80db9 100644 --- a/core/tests/fmt/mod.rs +++ b/core/tests/fmt/mod.rs @@ -58,21 +58,17 @@ fn formatting_options_flags() { for alternate in [true, false] { for sign_aware_zero_pad in [true, false] { for debug_as_hex in [None, Some(DebugAsHex::Lower), Some(DebugAsHex::Upper)] { - let mut original_formatting_options = FormattingOptions::new(); - original_formatting_options + let mut formatting_options = FormattingOptions::new(); + formatting_options .sign(sign) .sign_aware_zero_pad(sign_aware_zero_pad) .alternate(alternate) .debug_as_hex(debug_as_hex); - let mut formatting_options_with_flags_set_to_self = original_formatting_options; - formatting_options_with_flags_set_to_self - .flags(formatting_options_with_flags_set_to_self.get_flags()); - - assert_eq!( - original_formatting_options, formatting_options_with_flags_set_to_self, - "Reading and setting flags changes FormattingOptions; Sign({sign:?}), Alternate({alternate:?}). DebugAsHex({debug_as_hex:?})" - ) + assert_eq!(formatting_options.get_sign(), sign); + assert_eq!(formatting_options.get_alternate(), alternate); + assert_eq!(formatting_options.get_sign_aware_zero_pad(), sign_aware_zero_pad); + assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex); } } } From 7d738cddd23ec985ab93b9c9f6c1959241e2aef3 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 04:10:58 +0100 Subject: [PATCH 086/481] Formatted --- core/src/fmt/mod.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 9598dd33e9364..ccad3748bbd12 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -308,13 +308,7 @@ impl FormattingOptions { /// - no [`DebugAsHex`] output mode. #[unstable(feature = "formatting_options", issue = "118117")] pub const fn new() -> Self { - Self { - flags: 0, - fill: ' ', - align: None, - width: None, - precision: None, - } + Self { flags: 0, fill: ' ', align: None, width: None, precision: None } } /// Sets or removes the sign (the `+` or the `-` flag). @@ -327,9 +321,10 @@ impl FormattingOptions { /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] pub const fn sign(&mut self, sign: Option) -> &mut Self { - self.flags = self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); + self.flags = + self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); match sign { - None => {}, + None => {} Some(Sign::Plus) => self.flags |= 1 << rt::Flag::SignPlus as u32, Some(Sign::Minus) => self.flags |= 1 << rt::Flag::SignMinus as u32, } @@ -413,9 +408,10 @@ impl FormattingOptions { /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { - self.flags = self.flags & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); + self.flags = self.flags + & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); match debug_as_hex { - None => {}, + None => {} Some(DebugAsHex::Upper) => self.flags |= 1 << rt::Flag::DebugUpperHex as u32, Some(DebugAsHex::Lower) => self.flags |= 1 << rt::Flag::DebugLowerHex as u32, } @@ -469,7 +465,9 @@ impl FormattingOptions { pub const fn get_debug_as_hex(&self) -> Option { const DEBUG_UPPER_BITFIELD: u32 = 1 << rt::Flag::DebugUpperHex as u32; const DEBUG_LOWER_BITFIELD: u32 = 1 << rt::Flag::DebugLowerHex as u32; - match self.flags & ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) { + match self.flags + & ((1 << rt::Flag::DebugUpperHex as u32) | (1 << rt::Flag::DebugLowerHex as u32)) + { DEBUG_UPPER_BITFIELD => Some(DebugAsHex::Upper), DEBUG_LOWER_BITFIELD => Some(DebugAsHex::Lower), 0 => None, From a9d5f739e86ddae374511abe376f866f3ecfb94a Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 3 Mar 2024 03:36:37 +0100 Subject: [PATCH 087/481] Added better reason for exposing `flags` and `get_flags` as unstable --- core/src/fmt/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index ccad3748bbd12..422d9b25183d9 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -484,13 +484,21 @@ impl FormattingOptions { } #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + #[unstable( + feature = "fmt_internals", + reason = "internal routines only exposed for testing", + issue = "none" + )] /// Flags for formatting pub fn flags(&mut self, flags: u32) { self.flags = flags } #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + #[unstable( + feature = "fmt_internals", + reason = "internal routines only exposed for testing", + issue = "none" + )] /// Flags for formatting pub fn get_flags(&self) -> u32 { self.flags From 9be73d6ae194ef7c30a3ecd324d9b83a16110391 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 3 Mar 2024 03:53:11 +0100 Subject: [PATCH 088/481] Removed constness for methods receiving a `&mut` parameter See https://github.com/rust-lang/rust/pull/118159#discussion_r1495760867 for context. --- core/src/fmt/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 422d9b25183d9..da89acdcd1ef4 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -320,7 +320,7 @@ impl FormattingOptions { /// always be printed. /// - `-`: Currently not used #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn sign(&mut self, sign: Option) -> &mut Self { + pub fn sign(&mut self, sign: Option) -> &mut Self { self.flags = self.flags & !(1 << rt::Flag::SignMinus as u32 | 1 << rt::Flag::SignPlus as u32); match sign { @@ -334,7 +334,7 @@ impl FormattingOptions { /// /// This is used to indicate for integer formats that the padding to width should both be done with a 0 character as well as be sign-aware #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { + pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self { if sign_aware_zero_pad { self.flags |= 1 << rt::Flag::SignAwareZeroPad as u32 } else { @@ -351,7 +351,7 @@ impl FormattingOptions { /// - [`Octal`] - precedes the argument with a `0b` /// - [`Binary`] - precedes the argument with a `0o` #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn alternate(&mut self, alternate: bool) -> &mut Self { + pub fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { self.flags |= 1 << rt::Flag::Alternate as u32 } else { @@ -366,7 +366,7 @@ impl FormattingOptions { /// being formatted is smaller than width some extra characters will be /// printed around it. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn fill(&mut self, fill: char) -> &mut Self { + pub fn fill(&mut self, fill: char) -> &mut Self { self.fill = fill; self } @@ -375,7 +375,7 @@ impl FormattingOptions { /// The alignment specifies how the value being formatted should be /// positioned if it is smaller than the width of the formatter. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn align(&mut self, align: Option) -> &mut Self { + pub fn align(&mut self, align: Option) -> &mut Self { self.align = align; self } @@ -386,7 +386,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn width(&mut self, width: Option) -> &mut Self { + pub fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -400,14 +400,14 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn precision(&mut self, precision: Option) -> &mut Self { + pub fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; self } /// Specifies whether the [`Debug`] trait should use lower-/upper-case /// hexadecimal or normal integers #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { + pub fn debug_as_hex(&mut self, debug_as_hex: Option) -> &mut Self { self.flags = self.flags & !(1 << rt::Flag::DebugUpperHex as u32 | 1 << rt::Flag::DebugLowerHex as u32); match debug_as_hex { @@ -479,7 +479,7 @@ impl FormattingOptions { /// /// You may alternatively use [`Formatter::new()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { options: self, buf: write } } @@ -532,13 +532,13 @@ impl<'a> Formatter<'a> { /// /// You may alternatively use [`FormattingOptions::create_formatter()`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { + pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self { Formatter { options, buf: write } } /// Creates a new formatter based on this one with given [`FormattingOptions`]. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { + pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b> { Formatter { options, buf: self.buf } } } From 5a9824820782cdca1d47a0db38379fc0907915e1 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 3 Mar 2024 05:17:55 +0100 Subject: [PATCH 089/481] Access members of `FormattingOptions` directly instead of via getters/setters --- core/src/fmt/float.rs | 6 ++-- core/src/fmt/mod.rs | 74 +++++++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/core/src/fmt/float.rs b/core/src/fmt/float.rs index ee7a8f08f1986..3f10158193d76 100644 --- a/core/src/fmt/float.rs +++ b/core/src/fmt/float.rs @@ -86,7 +86,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.precision() { + if let Some(precision) = fmt.options.precision { float_to_decimal_common_exact(fmt, num, sign, precision) } else { let min_precision = 0; @@ -162,7 +162,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.precision() { + if let Some(precision) = fmt.options.precision { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { @@ -180,7 +180,7 @@ where true => flt2dec::Sign::MinusPlus, }; - if let Some(precision) = fmt.precision() { + if let Some(precision) = fmt.options.precision { // this behavior of {:.PREC?} predates exponential formatting for {:?} float_to_decimal_common_exact(fmt, num, sign, precision) } else { diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index da89acdcd1ef4..14c7006510162 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -1466,14 +1466,14 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { } unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { - fmt.options.fill(arg.fill); - fmt.options.align(arg.align.into()); - fmt.options.flags(arg.flags); + fmt.options.fill = arg.fill; + fmt.options.align = arg.align.into(); + fmt.options.flags = arg.flags; // SAFETY: arg and args come from the same Arguments, // which guarantees the indexes are always within bounds. unsafe { - fmt.options.width(getcount(args, &arg.width)); - fmt.options.precision(getcount(args, &arg.precision)); + fmt.options.width = getcount(args, &arg.width); + fmt.options.precision = getcount(args, &arg.precision); } // Extract the correct argument @@ -1613,7 +1613,7 @@ impl<'a> Formatter<'a> { } // The `width` field is more of a `min-width` parameter at this point. - match self.width() { + match self.options.width { // If there's no minimum length requirements then we can just // write the bytes. None => { @@ -1682,12 +1682,12 @@ impl<'a> Formatter<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front - if self.width().is_none() && self.precision().is_none() { + if self.options.width.is_none() && self.options.precision.is_none() { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the // string being formatted. - let s = if let Some(max) = self.precision() { + let s = if let Some(max) = self.options.precision { // If our string is longer that the precision, then we must have // truncation. However other flags like `fill`, `width` and `align` // must act as always. @@ -1704,7 +1704,7 @@ impl<'a> Formatter<'a> { &s }; // The `width` field is more of a `min-width` parameter at this point. - match self.width() { + match self.options.width { // If we're under the maximum length, and there's no minimum length // requirements, then we can just emit the string None => self.buf.write_str(s), @@ -1745,10 +1745,10 @@ impl<'a> Formatter<'a> { }; for _ in 0..pre_pad { - self.buf.write_char(self.fill())?; + self.buf.write_char(self.options.fill)?; } - Ok(PostPadding::new(self.fill(), post_pad)) + Ok(PostPadding::new(self.options.fill, post_pad)) } /// Takes the formatted parts and applies the padding. @@ -1760,12 +1760,12 @@ impl<'a> Formatter<'a> { /// /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - if let Some(mut width) = self.width() { + if let Some(mut width) = self.options.width { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. let mut formatted = formatted.clone(); - let old_fill = self.fill(); - let old_align = self.align(); + let old_fill = self.options.fill; + let old_align = self.options.align; if self.sign_aware_zero_pad() { // a sign always goes first let sign = formatted.sign; @@ -1774,8 +1774,8 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; width = width.saturating_sub(sign.len()); - self.options.fill('0'); - self.options.align(Some(Alignment::Right)); + self.options.fill = '0'; + self.options.align = Some(Alignment::Right); } // remaining parts go through the ordinary padding process. @@ -1792,8 +1792,8 @@ impl<'a> Formatter<'a> { } post_padding.write(self) }; - self.options.fill(old_fill); - self.options.align(old_align); + self.options.fill = old_fill; + self.options.align = old_align; ret } else { // this is the common case and we take a shortcut @@ -1919,7 +1919,7 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead" )] pub fn flags(&self) -> u32 { - self.options.get_flags() + self.options.flags } /// Returns the character used as 'fill' whenever there is alignment. @@ -1952,7 +1952,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { - self.options.get_fill() + self.options.fill } /// Returns a flag indicating what form of alignment was requested. @@ -1987,7 +1987,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub fn align(&self) -> Option { - self.options.get_align() + self.options.align } /// Returns the optionally specified integer width that the output should be. @@ -2017,7 +2017,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.get_width() + self.options.width } /// Returns the optionally specified precision for numeric types. @@ -2048,7 +2048,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.get_precision() + self.options.precision } /// Determines if the `+` flag was specified. @@ -2080,7 +2080,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.options.get_sign() == Some(Sign::Plus) + self.options.flags & (1 << rt::Flag::SignPlus as u32) != 0 } /// Determines if the `-` flag was specified. @@ -2109,7 +2109,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.options.get_sign() == Some(Sign::Minus) + self.options.flags & (1 << rt::Flag::SignMinus as u32) != 0 } /// Determines if the `#` flag was specified. @@ -2137,7 +2137,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.options.get_alternate() + self.options.flags & (1 << rt::Flag::Alternate as u32) != 0 } /// Determines if the `0` flag was specified. @@ -2163,7 +2163,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.options.get_sign_aware_zero_pad() + self.options.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 } // FIXME: Decide what public API we want for these two flags. @@ -2753,7 +2753,7 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - if f.width().is_none() && f.precision().is_none() { + if f.options.width.is_none() && f.options.precision.is_none() { f.write_char(*self) } else { f.pad(self.encode_utf8(&mut [0; 4])) @@ -2777,28 +2777,26 @@ impl Pointer for *const T { /// /// [problematic]: https://github.com/rust-lang/rust/issues/95489 pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result { - let old_width = f.width(); - let old_alternate = f.alternate(); - let old_zero_pad = f.sign_aware_zero_pad(); + let old_width = f.options.width; + let old_flags = f.options.flags; // The alternate flag is already treated by LowerHex as being special- // it denotes whether to prefix with 0x. We use it to work out whether // or not to zero extend, and then unconditionally set it to get the // prefix. if f.alternate() { - f.options.sign_aware_zero_pad(true); + f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); - if f.width().is_none() { - f.options.width(Some((usize::BITS / 4) as usize + 2)); + if f.options.width.is_none() { + f.options.width = Some((usize::BITS / 4) as usize + 2); } } - f.options.alternate(true); + f.options.flags |= 1 << (rt::Flag::Alternate as u32); let ret = LowerHex::fmt(&ptr_addr, f); - f.options.width(old_width); - f.options.alternate(old_alternate); - f.options.sign_aware_zero_pad(old_zero_pad); + f.options.width = old_width; + f.options.flags = old_flags; ret } From 194dac0c6159ecb26db65420cf1c45486b161875 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 11 Sep 2024 01:26:55 +0300 Subject: [PATCH 090/481] Stabilize `std::io::ErrorKind::CrossesDevices` --- std/src/io/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/io/error.rs b/std/src/io/error.rs index 03f38e220a581..7322cbe79bc23 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -364,7 +364,7 @@ pub enum ErrorKind { #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] Deadlock, /// Cross-device or cross-filesystem (hard) link or rename. - #[unstable(feature = "io_error_more", issue = "86442")] + #[stable(feature = "io_error_crosses_devices", since = "CURRENT_RUSTC_VERSION")] CrossesDevices, /// Too many (hard) links to the same filesystem object. /// From c1cc5b73041a89720cdf52af8f90baeb05ef0dca Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 12 Sep 2024 02:53:12 +0300 Subject: [PATCH 091/481] Stabilize `std::io::ErrorKind::QuotaExceeded` Also drop "Filesystem" from its name --- std/src/io/error.rs | 8 ++++---- std/src/io/error/repr_bitpacked.rs | 2 +- std/src/sys/pal/teeos/mod.rs | 2 +- std/src/sys/pal/unix/mod.rs | 2 +- std/src/sys/pal/windows/mod.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/std/src/io/error.rs b/std/src/io/error.rs index 7322cbe79bc23..7532ec995a307 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -338,9 +338,9 @@ pub enum ErrorKind { /// example, on Unix, a named pipe opened with `File::open`. #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] NotSeekable, - /// Filesystem quota was exceeded. - #[unstable(feature = "io_error_more", issue = "86442")] - FilesystemQuotaExceeded, + /// Filesystem quota or some other kind of quota was exceeded. + #[stable(feature = "io_error_quota_exceeded", since = "CURRENT_RUSTC_VERSION")] + QuotaExceeded, /// File larger than allowed or supported. /// /// This might arise from a hard limit of the underlying filesystem or file access API, or from @@ -462,7 +462,7 @@ impl ErrorKind { ExecutableFileBusy => "executable file busy", FileTooLarge => "file too large", FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", - FilesystemQuotaExceeded => "filesystem quota exceeded", + QuotaExceeded => "quota exceeded", HostUnreachable => "host unreachable", Interrupted => "operation interrupted", InProgress => "in progress", diff --git a/std/src/io/error/repr_bitpacked.rs b/std/src/io/error/repr_bitpacked.rs index a839a2fbac117..f958a93864603 100644 --- a/std/src/io/error/repr_bitpacked.rs +++ b/std/src/io/error/repr_bitpacked.rs @@ -335,7 +335,7 @@ fn kind_from_prim(ek: u32) -> Option { WriteZero, StorageFull, NotSeekable, - FilesystemQuotaExceeded, + QuotaExceeded, FileTooLarge, ResourceBusy, ExecutableFileBusy, diff --git a/std/src/sys/pal/teeos/mod.rs b/std/src/sys/pal/teeos/mod.rs index 2bf2e2ceb314d..a9900f55b1926 100644 --- a/std/src/sys/pal/teeos/mod.rs +++ b/std/src/sys/pal/teeos/mod.rs @@ -71,7 +71,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ECONNREFUSED => ConnectionRefused, libc::ECONNRESET => ConnectionReset, libc::EDEADLK => Deadlock, - libc::EDQUOT => FilesystemQuotaExceeded, + libc::EDQUOT => QuotaExceeded, libc::EEXIST => AlreadyExists, libc::EFBIG => FileTooLarge, libc::EHOSTUNREACH => HostUnreachable, diff --git a/std/src/sys/pal/unix/mod.rs b/std/src/sys/pal/unix/mod.rs index 8eaa50d7f81d2..3cc1cae8d000e 100644 --- a/std/src/sys/pal/unix/mod.rs +++ b/std/src/sys/pal/unix/mod.rs @@ -254,7 +254,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ECONNREFUSED => ConnectionRefused, libc::ECONNRESET => ConnectionReset, libc::EDEADLK => Deadlock, - libc::EDQUOT => FilesystemQuotaExceeded, + libc::EDQUOT => QuotaExceeded, libc::EEXIST => AlreadyExists, libc::EFBIG => FileTooLarge, libc::EHOSTUNREACH => HostUnreachable, diff --git a/std/src/sys/pal/windows/mod.rs b/std/src/sys/pal/windows/mod.rs index d66ff15e10bf6..88e6def7a7577 100644 --- a/std/src/sys/pal/windows/mod.rs +++ b/std/src/sys/pal/windows/mod.rs @@ -113,7 +113,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem, c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull, c::ERROR_SEEK_ON_DEVICE => return NotSeekable, - c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded, + c::ERROR_DISK_QUOTA_EXCEEDED => return QuotaExceeded, c::ERROR_FILE_TOO_LARGE => return FileTooLarge, c::ERROR_BUSY => return ResourceBusy, c::ERROR_POSSIBLE_DEADLOCK => return Deadlock, @@ -138,7 +138,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::WSAEHOSTUNREACH => HostUnreachable, c::WSAENETDOWN => NetworkDown, c::WSAENETUNREACH => NetworkUnreachable, - c::WSAEDQUOT => FilesystemQuotaExceeded, + c::WSAEDQUOT => QuotaExceeded, _ => Uncategorized, } From 7416d80745bfc7fe4cde071ea3305b33f5d35519 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 12 Sep 2024 02:58:27 +0300 Subject: [PATCH 092/481] Unbreak tidy --- std/src/io/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/std/src/io/error.rs b/std/src/io/error.rs index 7532ec995a307..476c403c21f33 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -446,8 +446,8 @@ pub enum ErrorKind { impl ErrorKind { pub(crate) fn as_str(&self) -> &'static str { use ErrorKind::*; - // tidy-alphabetical-start match *self { + // tidy-alphabetical-start AddrInUse => "address in use", AddrNotAvailable => "address not available", AlreadyExists => "entity already exists", @@ -460,12 +460,11 @@ impl ErrorKind { Deadlock => "deadlock", DirectoryNotEmpty => "directory not empty", ExecutableFileBusy => "executable file busy", - FileTooLarge => "file too large", FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", - QuotaExceeded => "quota exceeded", + FileTooLarge => "file too large", HostUnreachable => "host unreachable", - Interrupted => "operation interrupted", InProgress => "in progress", + Interrupted => "operation interrupted", InvalidData => "invalid data", InvalidFilename => "invalid filename", InvalidInput => "invalid input parameter", @@ -479,6 +478,7 @@ impl ErrorKind { Other => "other error", OutOfMemory => "out of memory", PermissionDenied => "permission denied", + QuotaExceeded => "quota exceeded", ReadOnlyFilesystem => "read-only filesystem or storage medium", ResourceBusy => "resource busy", StaleNetworkFileHandle => "stale network file handle", @@ -490,8 +490,8 @@ impl ErrorKind { Unsupported => "unsupported", WouldBlock => "operation would block", WriteZero => "write zero", + // tidy-alphabetical-end } - // tidy-alphabetical-end } } From d37ea9f332769ca8f0527ff09779c1abdd510899 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Sat, 26 Oct 2024 17:25:10 +0200 Subject: [PATCH 093/481] Add Extend impls for tuples of arity 1 through 12 --- core/src/iter/traits/collect.rs | 248 ++++++++++++++++++-------------- 1 file changed, 138 insertions(+), 110 deletions(-) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index 2cf2ea58fd4ee..16211610f0551 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -492,131 +492,159 @@ impl Extend<()> for () { fn extend_one(&mut self, _item: ()) {} } -#[stable(feature = "extend_for_tuple", since = "1.56.0")] -impl Extend<(A, B)> for (ExtendA, ExtendB) -where - ExtendA: Extend, - ExtendB: Extend, -{ - /// Allows to `extend` a tuple of collections that also implement `Extend`. - /// - /// See also: [`Iterator::unzip`] - /// - /// # Examples - /// ``` - /// let mut tuple = (vec![0], vec![1]); - /// tuple.extend([(2, 3), (4, 5), (6, 7)]); - /// assert_eq!(tuple.0, [0, 2, 4, 6]); - /// assert_eq!(tuple.1, [1, 3, 5, 7]); - /// - /// // also allows for arbitrarily nested tuples as elements - /// let mut nested_tuple = (vec![1], (vec![2], vec![3])); - /// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]); - /// - /// let (a, (b, c)) = nested_tuple; - /// assert_eq!(a, [1, 4, 7]); - /// assert_eq!(b, [2, 5, 8]); - /// assert_eq!(c, [3, 6, 9]); - /// ``` - fn extend>(&mut self, into_iter: T) { - let (a, b) = self; - let iter = into_iter.into_iter(); - SpecTupleExtend::extend(iter, a, b); - } +macro_rules! spec_tuple_impl { + ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => { + spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_more_tuples", since = "CURRENT_RUSTC_VERSION")] #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] => ($ty_name, $var_name, $extend_ty_name, $cnt),); + }; + // Special case (A, B) as this was stabilized earlier + ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), + ($ty_names:ident, $var_names:ident, $extend_ty_names: ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),) => { - fn extend_one(&mut self, item: (A, B)) { - self.0.extend_one(item.0); - self.1.extend_one(item.1); - } + spec_tuple_impl!(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),); + spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_tuple", since = "1.56.0")] => ($ty_name, $var_name, $extend_ty_name, $cnt), ($ty_names, $var_names, $extend_ty_names, $cnts),); + }; + ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),)*) => { - fn extend_reserve(&mut self, additional: usize) { - self.0.extend_reserve(additional); - self.1.extend_reserve(additional); - } + spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*); + spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_more_tuples", since = "CURRENT_RUSTC_VERSION")] #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*); + }; + ($trait_name:ident, $default_fn_name:ident, #[$stable:meta] $(#[$meta:meta] $(#[$doctext:meta])?)? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => { + $(#[$meta] + $(#[$doctext])? + )? + #[$stable] + impl<$($ty_names,)* $($extend_ty_names,)*> Extend<($($ty_names,)*)> for ($($extend_ty_names,)*) + where + $($extend_ty_names: Extend<$ty_names>,)* + { + /// Allows to `extend` a tuple of collections that also implement `Extend`. + /// + /// See also: [`Iterator::unzip`] + /// + /// # Examples + /// ``` + /// // Example given for a 2-tuple, but 1- through 12-tuples are supported + /// let mut tuple = (vec![0], vec![1]); + /// tuple.extend([(2, 3), (4, 5), (6, 7)]); + /// assert_eq!(tuple.0, [0, 2, 4, 6]); + /// assert_eq!(tuple.1, [1, 3, 5, 7]); + /// + /// // also allows for arbitrarily nested tuples as elements + /// let mut nested_tuple = (vec![1], (vec![2], vec![3])); + /// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]); + /// + /// let (a, (b, c)) = nested_tuple; + /// assert_eq!(a, [1, 4, 7]); + /// assert_eq!(b, [2, 5, 8]); + /// assert_eq!(c, [3, 6, 9]); + /// ``` + fn extend>(&mut self, into_iter: T) { + let ($($var_names,)*) = self; + let iter = into_iter.into_iter(); + $trait_name::extend(iter, $($var_names,)*); + } - unsafe fn extend_one_unchecked(&mut self, item: (A, B)) { - // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`. - unsafe { - self.0.extend_one_unchecked(item.0); - self.1.extend_one_unchecked(item.1); - } - } -} + fn extend_one(&mut self, item: ($($ty_names,)*)) { + $(self.$cnts.extend_one(item.$cnts);)* + } -fn default_extend_tuple( - iter: impl Iterator, - a: &mut ExtendA, - b: &mut ExtendB, -) where - ExtendA: Extend, - ExtendB: Extend, -{ - fn extend<'a, A, B>( - a: &'a mut impl Extend, - b: &'a mut impl Extend, - ) -> impl FnMut((), (A, B)) + 'a { - move |(), (t, u)| { - a.extend_one(t); - b.extend_one(u); + fn extend_reserve(&mut self, additional: usize) { + $(self.$cnts.extend_reserve(additional);)* + } + + unsafe fn extend_one_unchecked(&mut self, item: ($($ty_names,)*)) { + // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`. + unsafe { + $(self.$cnts.extend_one_unchecked(item.$cnts);)* + } + } } - } - let (lower_bound, _) = iter.size_hint(); - if lower_bound > 0 { - a.extend_reserve(lower_bound); - b.extend_reserve(lower_bound); - } + trait $trait_name<$($ty_names),*> { + fn extend(self, $($var_names: &mut $ty_names,)*); + } - iter.fold((), extend(a, b)); -} + fn $default_fn_name<$($ty_names,)* $($extend_ty_names,)*>( + iter: impl Iterator, + $($var_names: &mut $extend_ty_names,)* + ) where + $($extend_ty_names: Extend<$ty_names>,)* + { + fn extend<'a, $($ty_names,)*>( + $($var_names: &'a mut impl Extend<$ty_names>,)* + ) -> impl FnMut((), ($($ty_names,)*)) + 'a { + #[allow(non_snake_case)] + move |(), ($($extend_ty_names,)*)| { + $($var_names.extend_one($extend_ty_names);)* + } + } -trait SpecTupleExtend { - fn extend(self, a: &mut A, b: &mut B); -} + let (lower_bound, _) = iter.size_hint(); + if lower_bound > 0 { + $($var_names.extend_reserve(lower_bound);)* + } -impl SpecTupleExtend for Iter -where - ExtendA: Extend, - ExtendB: Extend, - Iter: Iterator, -{ - default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { - default_extend_tuple(self, a, b); - } -} + iter.fold((), extend($($var_names,)*)); + } -impl SpecTupleExtend for Iter -where - ExtendA: Extend, - ExtendB: Extend, - Iter: TrustedLen, -{ - fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { - fn extend<'a, A, B>( - a: &'a mut impl Extend, - b: &'a mut impl Extend, - ) -> impl FnMut((), (A, B)) + 'a { - // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen` - // so its `size_hint` is exact. - move |(), (t, u)| unsafe { - a.extend_one_unchecked(t); - b.extend_one_unchecked(u); + impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter + where + $($extend_ty_names: Extend<$ty_names>,)* + Iter: Iterator, + { + default fn extend(self, $($var_names: &mut $extend_ty_names),*) { + $default_fn_name(self, $($var_names),*); } } - let (lower_bound, upper_bound) = self.size_hint(); + impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter + where + $($extend_ty_names: Extend<$ty_names>,)* + Iter: TrustedLen, + { + fn extend(self, $($var_names: &mut $extend_ty_names,)*) { + fn extend<'a, $($ty_names,)*>( + $($var_names: &'a mut impl Extend<$ty_names>,)* + ) -> impl FnMut((), ($($ty_names,)*)) + 'a { + #[allow(non_snake_case)] + // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen` + // so its `size_hint` is exact. + move |(), ($($extend_ty_names,)*)| unsafe { + $($var_names.extend_one_unchecked($extend_ty_names);)* + } + } - if upper_bound.is_none() { - // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. - default_extend_tuple(self, a, b); - return; - } + let (lower_bound, upper_bound) = self.size_hint(); - if lower_bound > 0 { - a.extend_reserve(lower_bound); - b.extend_reserve(lower_bound); - } + if upper_bound.is_none() { + // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. + $default_fn_name(self, $($var_names,)*); + return; + } - self.fold((), extend(a, b)); + if lower_bound > 0 { + $($var_names.extend_reserve(lower_bound);)* + } + + self.fold((), extend($($var_names,)*)); + } } + + }; } + +spec_tuple_impl!( + (M, m, EM, TraitM, default_extend_tuple_m, 12), + (L, l, EL, TraitL, default_extend_tuple_l, 11), + (K, k, EK, TraitK, default_extend_tuple_k, 10), + (J, j, EJ, TraitJ, default_extend_tuple_j, 9), + (I, i, EI, TraitI, default_extend_tuple_i, 8), + (H, h, EH, TraitH, default_extend_tuple_h, 7), + (G, g, EG, TraitG, default_extend_tuple_g, 6), + (F, f, EF, TraitF, default_extend_tuple_f, 5), + (E, e, EE, TraitE, default_extend_tuple_e, 4), + (D, d, ED, TraitD, default_extend_tuple_d, 3), + (C, c, EC, TraitC, default_extend_tuple_c, 2), + (B, b, EB, TraitB, default_extend_tuple_b, 1), + (A, a, EA, TraitA, default_extend_tuple_a, 0), +); From be2a0b1c394ded4357bc9d9d5b8ac8c07af946b9 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Sat, 26 Oct 2024 18:58:05 +0200 Subject: [PATCH 094/481] Simplify documentation for Extend impl for tuples --- core/src/iter/traits/collect.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index 16211610f0551..8e2d7b9b4a6eb 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -494,25 +494,17 @@ impl Extend<()> for () { macro_rules! spec_tuple_impl { ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => { - spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_more_tuples", since = "CURRENT_RUSTC_VERSION")] #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] => ($ty_name, $var_name, $extend_ty_name, $cnt),); - }; - // Special case (A, B) as this was stabilized earlier - ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), - ($ty_names:ident, $var_names:ident, $extend_ty_names: ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),) => { - - spec_tuple_impl!(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),); - spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_tuple", since = "1.56.0")] => ($ty_name, $var_name, $extend_ty_name, $cnt), ($ty_names, $var_names, $extend_ty_names, $cnts),); + spec_tuple_impl!($trait_name, $default_fn_name, #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in RUSTC_CURRENT_VERSION."] => ($ty_name, $var_name, $extend_ty_name, $cnt),); }; ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),)*) => { spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*); - spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_more_tuples", since = "CURRENT_RUSTC_VERSION")] #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*); + spec_tuple_impl!($trait_name, $default_fn_name, #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*); }; - ($trait_name:ident, $default_fn_name:ident, #[$stable:meta] $(#[$meta:meta] $(#[$doctext:meta])?)? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => { - $(#[$meta] - $(#[$doctext])? - )? - #[$stable] + ($trait_name:ident, $default_fn_name:ident, #[$meta:meta] $(#[$doctext:meta])? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => { + #[$meta] + $(#[$doctext])? + #[stable(feature = "extend_for_tuple", since = "1.56.0")] impl<$($ty_names,)* $($extend_ty_names,)*> Extend<($($ty_names,)*)> for ($($extend_ty_names,)*) where $($extend_ty_names: Extend<$ty_names>,)* From 79a56bdf77e79701694c1655011aca380c1d384b Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Thu, 31 Oct 2024 01:23:46 +0100 Subject: [PATCH 095/481] Don't impl Extend for 13-tuples --- core/src/iter/traits/collect.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index 8e2d7b9b4a6eb..c3c7288e38990 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -626,7 +626,6 @@ macro_rules! spec_tuple_impl { } spec_tuple_impl!( - (M, m, EM, TraitM, default_extend_tuple_m, 12), (L, l, EL, TraitL, default_extend_tuple_l, 11), (K, k, EK, TraitK, default_extend_tuple_k, 10), (J, j, EJ, TraitJ, default_extend_tuple_j, 9), From 06f0c374f810340454ebe0d275a84ed1f7fcdaa0 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Thu, 31 Oct 2024 01:48:37 +0100 Subject: [PATCH 096/481] Add a `collect_into` tuple test case --- core/tests/iter/traits/iterator.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/tests/iter/traits/iterator.rs b/core/tests/iter/traits/iterator.rs index 93ef9c0812b16..76f1e3319d42e 100644 --- a/core/tests/iter/traits/iterator.rs +++ b/core/tests/iter/traits/iterator.rs @@ -617,6 +617,19 @@ fn test_next_chunk() { assert_eq!(it.next_chunk::<0>().unwrap(), []); } +#[test] +fn test_collect_into_tuples() { + let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; + let b = vec![1, 4, 7]; + let c = vec![2, 5, 8]; + let d = vec![3, 6, 9]; + let mut e = (Vec::new(), Vec::new(), Vec::new()); + a.iter().cloned().collect_into(&mut e); + assert!(e.0 == b); + assert!(e.1 == c); + assert!(e.2 == d); +} + // just tests by whether or not this compiles fn _empty_impl_all_auto_traits() { use std::panic::{RefUnwindSafe, UnwindSafe}; From 6601cb92081adec174f3c4930488932ff1d6bbd7 Mon Sep 17 00:00:00 2001 From: Will-Low <26700668+Will-Low@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:33:05 -0800 Subject: [PATCH 097/481] Define acronym for thread local storage There are multiple references in this module's documentation to the acronym "TLS", without defining it. This is confusing for the reader. I propose that this acronym be defined during the first use of the term. --- std/src/thread/local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/thread/local.rs b/std/src/thread/local.rs index 56cf438bd9bbe..2313f4b5beb11 100644 --- a/std/src/thread/local.rs +++ b/std/src/thread/local.rs @@ -12,7 +12,7 @@ use crate::cell::{Cell, RefCell}; use crate::error::Error; use crate::fmt; -/// A thread local storage key which owns its contents. +/// A thread local storage (TLS) key which owns its contents. /// /// This key uses the fastest possible implementation available to it for the /// target platform. It is instantiated with the [`thread_local!`] macro and the From 3eec6b04315cc7be18373b763c74bbec21368a4e Mon Sep 17 00:00:00 2001 From: "aaishwarymishra@gmail.com" Date: Sun, 8 Dec 2024 03:12:48 +0530 Subject: [PATCH 098/481] Adds new intrinsic declaration changes old intrinsic to new declaration --- core/src/intrinsics/mod.rs | 66 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 802b571c51067..3e53c0497cc78 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3577,34 +3577,44 @@ pub const fn discriminant_value(_v: &T) -> ::Discrimin unimplemented!() } -extern "rust-intrinsic" { - /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the - /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. - /// - /// `catch_fn` must not unwind. - /// - /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign - /// unwinds). This function takes the data pointer and a pointer to the target- and - /// runtime-specific exception object that was caught. - /// - /// Note that in the case of a foreign unwinding operation, the exception object data may not be - /// safely usable from Rust, and should not be directly exposed via the standard library. To - /// prevent unsafe access, the library implementation may either abort the process or present an - /// opaque error type to the user. - /// - /// For more information, see the compiler's source, as well as the documentation for the stable - /// version of this intrinsic, `std::panic::catch_unwind`. - #[rustc_nounwind] - pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; - - /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held - /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`. - /// - /// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT` - /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered - /// in ways that are not allowed for regular writes). - #[rustc_nounwind] - pub fn nontemporal_store(ptr: *mut T, val: T); +/// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the +/// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. +/// +/// `catch_fn` must not unwind. +/// +/// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign +/// unwinds). This function takes the data pointer and a pointer to the target- and +/// runtime-specific exception object that was caught. +/// +/// Note that in the case of a foreign unwinding operation, the exception object data may not be +/// safely usable from Rust, and should not be directly exposed via the standard library. To +/// prevent unsafe access, the library implementation may either abort the process or present an +/// opaque error type to the user. +/// +/// For more information, see the compiler's source, as well as the documentation for the stable +/// version of this intrinsic, `std::panic::catch_unwind`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn catch_unwind( + _try_fn: fn(*mut u8), + _data: *mut u8, + _catch_fn: fn(*mut u8, *mut u8), +) -> i32 { + unreachable!() +} + +/// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held +/// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`. +/// +/// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT` +/// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered +/// in ways that are not allowed for regular writes). +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn nontemporal_store(_ptr: *mut T, _val: T) { + unreachable!() } /// See documentation of `<*const T>::offset_from` for details. From 9e8cf079bdef11ae4b757df0bc054a555273dc30 Mon Sep 17 00:00:00 2001 From: Ross MacArthur Date: Tue, 3 Dec 2024 09:20:34 +0200 Subject: [PATCH 099/481] Add doc alias 'then_with' for `then` method on `bool` --- core/src/bool.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/bool.rs b/core/src/bool.rs index 58a870d2e0725..1590b9f29fcae 100644 --- a/core/src/bool.rs +++ b/core/src/bool.rs @@ -54,6 +54,7 @@ impl bool { /// // `then`. /// assert_eq!(a, 1); /// ``` + #[doc(alias = "then_with")] #[stable(feature = "lazy_bool_to_option", since = "1.50.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "bool_then")] #[inline] From ccde43b2726065a9e395f6c34db281d505339e27 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 5 Dec 2024 00:26:13 +0000 Subject: [PATCH 100/481] Expand home_dir docs --- std/src/env.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/std/src/env.rs b/std/src/env.rs index 043747d0bc5e3..535236ff89a37 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -597,6 +597,13 @@ impl Error for JoinPathsError { /// Returns the path of the current user's home directory if known. /// +/// This may return `None` if getting the directory fails or if the platform does not have user home directories. +/// +/// For storing user data and configuration it is often preferable to use more specific directories. +/// For example, [XDG Base Directories] on Unix or the `LOCALAPPDATA` and `APPDATA` environment variables on Windows. +/// +/// [XDG Base Directories]: https://specifications.freedesktop.org/basedir-spec/latest/ +/// /// # Unix /// /// - Returns the value of the 'HOME' environment variable if it is set From ab4bfc9ff0a840c0697d5caa6e43dd4765d7fd0f Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Sun, 8 Dec 2024 18:21:15 +0530 Subject: [PATCH 101/481] docs: better examples for `std::ops::ControlFlow` Signed-off-by: Prajwal S N --- core/src/ops/control_flow.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/ops/control_flow.rs b/core/src/ops/control_flow.rs index c4429b3cd7d45..c8fcee5c140f5 100644 --- a/core/src/ops/control_flow.rs +++ b/core/src/ops/control_flow.rs @@ -141,8 +141,8 @@ impl ControlFlow { /// ``` /// use std::ops::ControlFlow; /// - /// assert!(ControlFlow::::Break(3).is_break()); - /// assert!(!ControlFlow::::Continue(3).is_break()); + /// assert!(ControlFlow::<&str, i32>::Break("Stop right there!").is_break()); + /// assert!(!ControlFlow::<&str, i32>::Continue(3).is_break()); /// ``` #[inline] #[stable(feature = "control_flow_enum_is", since = "1.59.0")] @@ -157,8 +157,8 @@ impl ControlFlow { /// ``` /// use std::ops::ControlFlow; /// - /// assert!(!ControlFlow::::Break(3).is_continue()); - /// assert!(ControlFlow::::Continue(3).is_continue()); + /// assert!(!ControlFlow::<&str, i32>::Break("Stop right there!").is_continue()); + /// assert!(ControlFlow::<&str, i32>::Continue(3).is_continue()); /// ``` #[inline] #[stable(feature = "control_flow_enum_is", since = "1.59.0")] @@ -174,8 +174,8 @@ impl ControlFlow { /// ``` /// use std::ops::ControlFlow; /// - /// assert_eq!(ControlFlow::::Break(3).break_value(), Some(3)); - /// assert_eq!(ControlFlow::::Continue(3).break_value(), None); + /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").break_value(), Some("Stop right there!")); + /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).break_value(), None); /// ``` #[inline] #[stable(feature = "control_flow_enum", since = "1.83.0")] @@ -205,8 +205,8 @@ impl ControlFlow { /// ``` /// use std::ops::ControlFlow; /// - /// assert_eq!(ControlFlow::::Break(3).continue_value(), None); - /// assert_eq!(ControlFlow::::Continue(3).continue_value(), Some(3)); + /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").continue_value(), None); + /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).continue_value(), Some(3)); /// ``` #[inline] #[stable(feature = "control_flow_enum", since = "1.83.0")] From f73a48de9914813c3fb2d0696bde3ed49dfe63a1 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 18 Nov 2024 18:58:56 +0100 Subject: [PATCH 102/481] wasi/fs: Improve stopping condition for ::next When upgrading [Zed](https://github.com/zed-industries/zed/pull/19349) to Rust 1.82 I've encountered a test failure in our test suite. Specifically, one of our extension tests started hanging. I've tracked it down to a call to std::fs::remove_dir_all not returning when an extension is compiled with Rust 1.82 Our extension system uses WASM components, thus I've looked at the diff between 1.81 and 1.82 with respect to WASI and found a87feee4ca9a673bf6aad673fcb09a2ec9f805dc As it turned out, calling remove_dir_all from extension returned io::ErrorKind::NotFound in 1.81; the underlying issue is that the ReadDir iterator never actually terminates iteration, however since it loops around, with 1.81 we'd come across an entry second time and fail to remove it, since it would've been removed previously. With 1.82 and a87feee4ca9a673bf6aad673fcb09a2ec9f805dc it is no longer the case, thus we're seeing the hang. This commit makes ReadDir::next adhere to readdir contract, namely it will no longer call readdir once the returned # of bytes is smaller than the size of a passed-in buffer. Previously we'd only terminate the loop if readdir returned 0. --- std/src/sys/pal/wasi/fs.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/std/src/sys/pal/wasi/fs.rs b/std/src/sys/pal/wasi/fs.rs index 0667eb9010100..f5a4b932d8c65 100644 --- a/std/src/sys/pal/wasi/fs.rs +++ b/std/src/sys/pal/wasi/fs.rs @@ -172,20 +172,22 @@ impl Iterator for ReadDir { let offset = if self.offset == self.cap { let cookie = self.cookie.take()?; match self.inner.dir.fd.readdir(&mut self.buf, cookie) { - Ok(bytes) => self.cap = bytes, + Ok(bytes) => { + // No more entries if we read less than buffer size + if bytes < self.buf.len() { + self.cookie = None; + if bytes == 0 { + return None; + } + } else { + self.cookie = Some(cookie); + } + self.cap = self.buf.len(); + self.offset = 0; + 0 + } Err(e) => return Some(Err(e)), } - self.offset = 0; - self.cookie = Some(cookie); - - // If we didn't actually read anything, this is in theory the - // end of the directory. - if self.cap == 0 { - self.cookie = None; - return None; - } - - 0 } else { self.offset }; @@ -197,7 +199,6 @@ impl Iterator for ReadDir { // where we last left off. let dirent_size = mem::size_of::(); if data.len() < dirent_size { - assert!(self.cookie.is_some()); assert!(self.buf.len() >= dirent_size); self.offset = self.cap; continue; @@ -218,7 +219,9 @@ impl Iterator for ReadDir { self.offset = self.cap; continue; } - self.cookie = Some(dirent.d_next); + self.cookie.as_mut().map(|cookie| { + *cookie = dirent.d_next; + }); self.offset = offset + dirent_size + dirent.d_namlen as usize; let name = &data[..(dirent.d_namlen as usize)]; From ca091dace5866de27ca19ab9aabd8ac28c6c7653 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:45:17 +0100 Subject: [PATCH 103/481] Refactor ReadDir into a state machine --- std/src/sys/pal/wasi/fs.rs | 171 ++++++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 70 deletions(-) diff --git a/std/src/sys/pal/wasi/fs.rs b/std/src/sys/pal/wasi/fs.rs index f5a4b932d8c65..a35ced861ac3d 100644 --- a/std/src/sys/pal/wasi/fs.rs +++ b/std/src/sys/pal/wasi/fs.rs @@ -27,10 +27,26 @@ pub struct FileAttr { pub struct ReadDir { inner: Arc, - cookie: Option, - buf: Vec, - offset: usize, - cap: usize, + state: ReadDirState, +} + +enum ReadDirState { + /// Next DirEntry should be read from contents of buf at `offset` + FillBuffer { + next_read_offset: wasi::Dircookie, + buf: Vec, + }, + ProcessEntry { + buf: Vec, + next_read_offset: Option, + offset: usize, + }, + /// Do not fetch any more entries, process all entries + RunUntilExhaustion { + buf: Vec, + offset: usize, + }, + Done, } struct ReadDirInner { @@ -147,11 +163,8 @@ impl FileType { impl ReadDir { fn new(dir: File, root: PathBuf) -> ReadDir { ReadDir { - cookie: Some(0), - buf: vec![0; 128], - offset: 0, - cap: 0, inner: Arc::new(ReadDirInner { dir, root }), + state: ReadDirState::FillBuffer { next_read_offset: 0, buf: vec![0; 128] }, } } } @@ -162,81 +175,99 @@ impl fmt::Debug for ReadDir { } } +impl core::iter::FusedIterator for ReadDir {} + impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - loop { - // If we've reached the capacity of our buffer then we need to read - // some more from the OS, otherwise we pick up at our old offset. - let offset = if self.offset == self.cap { - let cookie = self.cookie.take()?; - match self.inner.dir.fd.readdir(&mut self.buf, cookie) { - Ok(bytes) => { - // No more entries if we read less than buffer size - if bytes < self.buf.len() { - self.cookie = None; - if bytes == 0 { - return None; - } + match &mut self.state { + ReadDirState::FillBuffer { next_read_offset, ref mut buf } => { + let result = self.inner.dir.fd.readdir(buf, *next_read_offset); + match result { + Ok(read_bytes) => { + if read_bytes < buf.len() { + buf.truncate(read_bytes); + self.state = + ReadDirState::RunUntilExhaustion { buf: mem::take(buf), offset: 0 }; } else { - self.cookie = Some(cookie); + debug_assert_eq!(read_bytes, buf.len()); + self.state = ReadDirState::ProcessEntry { + buf: mem::take(buf), + offset: 0, + next_read_offset: Some(*next_read_offset), + }; } - self.cap = self.buf.len(); - self.offset = 0; - 0 + self.next() + } + Err(e) => { + self.state = ReadDirState::Done; + return Some(Err(e)); } - Err(e) => return Some(Err(e)), - } - } else { - self.offset - }; - let data = &self.buf[offset..self.cap]; - - // If we're not able to read a directory entry then that means it - // must have been truncated at the end of the buffer, so reset our - // offset so we can go back and reread into the buffer, picking up - // where we last left off. - let dirent_size = mem::size_of::(); - if data.len() < dirent_size { - assert!(self.buf.len() >= dirent_size); - self.offset = self.cap; - continue; - } - let (dirent, data) = data.split_at(dirent_size); - let dirent = unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; - - // If the file name was truncated, then we need to reinvoke - // `readdir` so we truncate our buffer to start over and reread this - // descriptor. Note that if our offset is 0 that means the file name - // is massive and we need a bigger buffer. - if data.len() < dirent.d_namlen as usize { - if offset == 0 { - let amt_to_add = self.buf.capacity(); - self.buf.extend(iter::repeat(0).take(amt_to_add)); } - assert!(self.cookie.is_some()); - self.offset = self.cap; - continue; } - self.cookie.as_mut().map(|cookie| { - *cookie = dirent.d_next; - }); - self.offset = offset + dirent_size + dirent.d_namlen as usize; + ReadDirState::ProcessEntry { ref mut buf, next_read_offset, offset } => { + let contents = &buf[*offset..]; + const DIRENT_SIZE: usize = crate::mem::size_of::(); + if contents.len() >= DIRENT_SIZE { + let (dirent, data) = contents.split_at(DIRENT_SIZE); + let dirent = + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; + // If the file name was truncated, then we need to reinvoke + // `readdir` so we truncate our buffer to start over and reread this + // descriptor. + if data.len() < dirent.d_namlen as usize { + if buf.len() < dirent.d_namlen as usize + DIRENT_SIZE { + buf.resize(dirent.d_namlen as usize + DIRENT_SIZE, 0); + } + if let Some(next_read_offset) = *next_read_offset { + self.state = + ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; + } else { + self.state = ReadDirState::Done; + } + + return self.next(); + } + next_read_offset.as_mut().map(|cookie| { + *cookie = dirent.d_next; + }); + *offset = *offset + DIRENT_SIZE + dirent.d_namlen as usize; + + let name = &data[..(dirent.d_namlen as usize)]; - let name = &data[..(dirent.d_namlen as usize)]; + // These names are skipped on all other platforms, so let's skip + // them here too + if name == b"." || name == b".." { + return self.next(); + } - // These names are skipped on all other platforms, so let's skip - // them here too - if name == b"." || name == b".." { - continue; + return Some(Ok(DirEntry { + meta: dirent, + name: name.to_vec(), + inner: self.inner.clone(), + })); + } else if let Some(next_read_offset) = *next_read_offset { + self.state = ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; + } else { + self.state = ReadDirState::Done; + } + self.next() } + ReadDirState::RunUntilExhaustion { buf, offset } => { + if *offset >= buf.len() { + self.state = ReadDirState::Done; + } else { + self.state = ReadDirState::ProcessEntry { + buf: mem::take(buf), + offset: *offset, + next_read_offset: None, + }; + } - return Some(Ok(DirEntry { - meta: dirent, - name: name.to_vec(), - inner: self.inner.clone(), - })); + self.next() + } + ReadDirState::Done => None, } } } From 4baf329c8d8292ae711d112c4ad16a093f23b90c Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:46:12 +0100 Subject: [PATCH 104/481] chore: Improve doc comments --- std/src/sys/pal/wasi/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/src/sys/pal/wasi/fs.rs b/std/src/sys/pal/wasi/fs.rs index a35ced861ac3d..7779d2b97d7f9 100644 --- a/std/src/sys/pal/wasi/fs.rs +++ b/std/src/sys/pal/wasi/fs.rs @@ -31,7 +31,7 @@ pub struct ReadDir { } enum ReadDirState { - /// Next DirEntry should be read from contents of buf at `offset` + /// Fill `buf` with `buf.len()` bytes starting from `next_read_offset`. FillBuffer { next_read_offset: wasi::Dircookie, buf: Vec, @@ -41,7 +41,8 @@ enum ReadDirState { next_read_offset: Option, offset: usize, }, - /// Do not fetch any more entries, process all entries + /// There is no more data to get in [`Self::FillBuffer`]; keep returning + /// entries via ProcessEntry until `buf` is exhausted. RunUntilExhaustion { buf: Vec, offset: usize, From 5e9b5e6931ce10e0b9acf96357067126ba7fa67a Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 25 Nov 2024 15:06:43 +0000 Subject: [PATCH 105/481] Run `cargo update` and update licenses --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9b0af2c6e84c..490c989300f58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,15 +36,15 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987" +checksum = "e2c6cb20f236dae10c69b0b45d82ef50af8b7e45c10e429e7901d26b49b4dbf3" dependencies = [ "compiler_builtins", "gimli 0.31.1", From efe11200361da9f2445fd364e6ce161dee3189bf Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 8 Dec 2024 18:18:03 +0000 Subject: [PATCH 106/481] Downgrade cc --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 490c989300f58..03c2356e542a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,9 +42,9 @@ checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "cc" -version = "1.2.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" dependencies = [ "shlex", ] From 7f4574c159f821b81d07ee6d514d2a4c5a82062f Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Sat, 23 Nov 2024 21:28:09 +0100 Subject: [PATCH 107/481] Run TLS destructors for wasm32-wasip1-threads The target has support for pthreads and allows registration of TLS destructors. --- std/src/sys/thread_local/guard/wasi.rs | 71 ++++++++++++++++++++++++++ std/src/sys/thread_local/mod.rs | 3 ++ 2 files changed, 74 insertions(+) create mode 100644 std/src/sys/thread_local/guard/wasi.rs diff --git a/std/src/sys/thread_local/guard/wasi.rs b/std/src/sys/thread_local/guard/wasi.rs new file mode 100644 index 0000000000000..dfd1f126aa0f1 --- /dev/null +++ b/std/src/sys/thread_local/guard/wasi.rs @@ -0,0 +1,71 @@ +//! wasm32-wasip1 has pthreads support. + +use crate::cell::Cell; +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sys::thread_local::destructors; +use crate::{ffi, ptr}; + +// Add a few symbols not in upstream `libc` just yet. +mod libc { + pub use libc::*; + + use crate::ffi; + + #[allow(non_camel_case_types)] + pub type pthread_key_t = ffi::c_uint; + + extern "C" { + pub fn pthread_key_create( + key: *mut pthread_key_t, + destructor: unsafe extern "C" fn(*mut ffi::c_void), + ) -> ffi::c_int; + + pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; + } +} + +pub fn enable() { + enable_main(); + enable_thread(); +} + +fn enable_main() { + static REGISTERED: AtomicBool = AtomicBool::new(false); + + if !REGISTERED.swap(true, Ordering::AcqRel) { + unsafe { + assert_eq!(libc::atexit(run_main_dtors), 0); + } + } + + extern "C" fn run_main_dtors() { + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } + } +} + +fn enable_thread() { + #[thread_local] + static REGISTERED: Cell = Cell::new(false); + + if !REGISTERED.replace(true) { + unsafe { + let mut key: libc::pthread_key_t = 0; + assert_eq!(libc::pthread_key_create(&mut key, run_thread_dtors), 0); + + // We must set the value to a non-NULL pointer value so that + // the destructor is run on thread exit. The pointer is only + // passed to run_dtors and never dereferenced. + assert_eq!(libc::pthread_setspecific(key, ptr::without_provenance(1)), 0); + } + } + + extern "C" fn run_thread_dtors(_: *mut ffi::c_void) { + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } + } +} diff --git a/std/src/sys/thread_local/mod.rs b/std/src/sys/thread_local/mod.rs index 31d3b43906004..042f0f76c9a4d 100644 --- a/std/src/sys/thread_local/mod.rs +++ b/std/src/sys/thread_local/mod.rs @@ -85,6 +85,9 @@ pub(crate) mod guard { } else if #[cfg(target_os = "windows")] { mod windows; pub(crate) use windows::enable; + } else if #[cfg(all(target_os = "wasi"))] { + mod wasi; + pub(crate) use wasi::enable; } else if #[cfg(any( target_family = "wasm", target_os = "uefi", From 3e567f7d631746d6f4b0bb648755f798bf066480 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Tue, 3 Dec 2024 16:16:08 +0100 Subject: [PATCH 108/481] Use UNIX thread_local implementation for WASI. --- std/src/sys/thread_local/guard/wasi.rs | 71 -------------------------- std/src/sys/thread_local/key/unix.rs | 20 ++++++++ std/src/sys/thread_local/mod.rs | 6 +-- 3 files changed, 22 insertions(+), 75 deletions(-) delete mode 100644 std/src/sys/thread_local/guard/wasi.rs diff --git a/std/src/sys/thread_local/guard/wasi.rs b/std/src/sys/thread_local/guard/wasi.rs deleted file mode 100644 index dfd1f126aa0f1..0000000000000 --- a/std/src/sys/thread_local/guard/wasi.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! wasm32-wasip1 has pthreads support. - -use crate::cell::Cell; -use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sys::thread_local::destructors; -use crate::{ffi, ptr}; - -// Add a few symbols not in upstream `libc` just yet. -mod libc { - pub use libc::*; - - use crate::ffi; - - #[allow(non_camel_case_types)] - pub type pthread_key_t = ffi::c_uint; - - extern "C" { - pub fn pthread_key_create( - key: *mut pthread_key_t, - destructor: unsafe extern "C" fn(*mut ffi::c_void), - ) -> ffi::c_int; - - pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; - } -} - -pub fn enable() { - enable_main(); - enable_thread(); -} - -fn enable_main() { - static REGISTERED: AtomicBool = AtomicBool::new(false); - - if !REGISTERED.swap(true, Ordering::AcqRel) { - unsafe { - assert_eq!(libc::atexit(run_main_dtors), 0); - } - } - - extern "C" fn run_main_dtors() { - unsafe { - destructors::run(); - crate::rt::thread_cleanup(); - } - } -} - -fn enable_thread() { - #[thread_local] - static REGISTERED: Cell = Cell::new(false); - - if !REGISTERED.replace(true) { - unsafe { - let mut key: libc::pthread_key_t = 0; - assert_eq!(libc::pthread_key_create(&mut key, run_thread_dtors), 0); - - // We must set the value to a non-NULL pointer value so that - // the destructor is run on thread exit. The pointer is only - // passed to run_dtors and never dereferenced. - assert_eq!(libc::pthread_setspecific(key, ptr::without_provenance(1)), 0); - } - } - - extern "C" fn run_thread_dtors(_: *mut ffi::c_void) { - unsafe { - destructors::run(); - crate::rt::thread_cleanup(); - } - } -} diff --git a/std/src/sys/thread_local/key/unix.rs b/std/src/sys/thread_local/key/unix.rs index 28e48a750b9bf..6661e378dbf44 100644 --- a/std/src/sys/thread_local/key/unix.rs +++ b/std/src/sys/thread_local/key/unix.rs @@ -1,5 +1,25 @@ use crate::mem; +// For WASI add a few symbols not in upstream `libc` just yet. +#[cfg(target_os = "wasi")] +mod libc { + use crate::ffi; + + #[allow(non_camel_case_types)] + pub type pthread_key_t = ffi::c_uint; + + extern "C" { + pub fn pthread_key_create( + key: *mut pthread_key_t, + destructor: unsafe extern "C" fn(*mut ffi::c_void), + ) -> ffi::c_int; + #[allow(dead_code)] + pub fn pthread_getspecific(key: pthread_key_t) -> *mut ffi::c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> ffi::c_int; + } +} + pub type Key = libc::pthread_key_t; #[inline] diff --git a/std/src/sys/thread_local/mod.rs b/std/src/sys/thread_local/mod.rs index 042f0f76c9a4d..82e1aeabf5ba1 100644 --- a/std/src/sys/thread_local/mod.rs +++ b/std/src/sys/thread_local/mod.rs @@ -85,11 +85,8 @@ pub(crate) mod guard { } else if #[cfg(target_os = "windows")] { mod windows; pub(crate) use windows::enable; - } else if #[cfg(all(target_os = "wasi"))] { - mod wasi; - pub(crate) use wasi::enable; } else if #[cfg(any( - target_family = "wasm", + all(target_family = "wasm", not(target_os="wasi")), target_os = "uefi", target_os = "zkvm", ))] { @@ -138,6 +135,7 @@ pub(crate) mod key { target_family = "unix", ), target_os = "teeos", + target_os = "wasi", ))] { mod racy; mod unix; From e65c781f194308e68293c15569368fb7a0ffd2c9 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Thu, 5 Dec 2024 12:18:14 +0100 Subject: [PATCH 109/481] Fix compilation for wasm32-wasip1 (without threads). --- std/src/sys/thread_local/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/std/src/sys/thread_local/mod.rs b/std/src/sys/thread_local/mod.rs index 82e1aeabf5ba1..f0a13323ec93f 100644 --- a/std/src/sys/thread_local/mod.rs +++ b/std/src/sys/thread_local/mod.rs @@ -86,7 +86,9 @@ pub(crate) mod guard { mod windows; pub(crate) use windows::enable; } else if #[cfg(any( - all(target_family = "wasm", not(target_os="wasi")), + all(target_family = "wasm", not( + all(target_os = "wasi", target_env = "p1", target_feature = "atomics") + )), target_os = "uefi", target_os = "zkvm", ))] { @@ -135,7 +137,7 @@ pub(crate) mod key { target_family = "unix", ), target_os = "teeos", - target_os = "wasi", + all(target_os = "wasi", target_env = "p1", target_feature = "atomics"), ))] { mod racy; mod unix; From bf51d378f9f8a90e05134be35749f180f9336a55 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Thu, 5 Dec 2024 12:24:19 +0100 Subject: [PATCH 110/481] Add libc funcitons only for wasm32-wasip1-threads. --- std/src/sys/thread_local/key/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sys/thread_local/key/unix.rs b/std/src/sys/thread_local/key/unix.rs index 6661e378dbf44..b4b58b3470631 100644 --- a/std/src/sys/thread_local/key/unix.rs +++ b/std/src/sys/thread_local/key/unix.rs @@ -1,7 +1,7 @@ use crate::mem; // For WASI add a few symbols not in upstream `libc` just yet. -#[cfg(target_os = "wasi")] +#[cfg(all(target_os = "wasi", target_env = "p1", target_feature = "atomics"))] mod libc { use crate::ffi; From 2f96c6adf11f6312e049b128dc2df69fa85e0518 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 9 Dec 2024 15:08:30 -0800 Subject: [PATCH 111/481] Remove rustc_const_stable attribute on const NOOP This was accidentally reintroduced while editing #133089. --- core/src/task/wake.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index 6762ed54e5c9b..bfffcc24a46a2 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -61,7 +61,6 @@ impl RawWaker { } #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] const NOOP: RawWaker = { const VTABLE: RawWakerVTable = RawWakerVTable::new( // Cloning just returns a new no-op raw waker From ffb5026f5fcfce26a103d4656a0a75c5c93d0c82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Dec 2024 11:29:01 +0100 Subject: [PATCH 112/481] stabilize const_nonnull_new --- core/src/ptr/non_null.rs | 2 +- core/src/ptr/unique.rs | 2 -- core/tests/lib.rs | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 0ad1cad6914ad..6b601405e1c2a 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -217,7 +217,7 @@ impl NonNull { /// } /// ``` #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")] + #[rustc_const_stable(feature = "const_nonnull_new", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn new(ptr: *mut T) -> Option { if !ptr.is_null() { diff --git a/core/src/ptr/unique.rs b/core/src/ptr/unique.rs index ebdc918a729c7..4810ebe01f9bb 100644 --- a/core/src/ptr/unique.rs +++ b/core/src/ptr/unique.rs @@ -92,8 +92,6 @@ impl Unique { /// Creates a new `Unique` if `ptr` is non-null. #[inline] - // rustc_const_unstable attribute can be removed when `const_nonnull_new` is stable - #[rustc_const_unstable(feature = "ptr_internals", issue = "none")] pub const fn new(ptr: *mut T) -> Option { if let Some(pointer) = NonNull::new(ptr) { Some(Unique { pointer, _marker: PhantomData }) diff --git a/core/tests/lib.rs b/core/tests/lib.rs index a4a794691fe38..89b65eefd027e 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(clone_to_uninit)] #![feature(const_black_box)] #![feature(const_eval_select)] -#![feature(const_nonnull_new)] #![feature(const_swap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] From 2cb1a6e6e789786e6bf0b026d6b523f7001b09a5 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 9 Dec 2024 14:48:13 +0100 Subject: [PATCH 113/481] Add a note saying that `{u8,i8}::from_{be,le,ne}_bytes` is meaningless --- core/src/num/mod.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index e36f20fd576ff..357a85ae843cd 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -77,6 +77,31 @@ pub use saturating::Saturating; #[stable(feature = "rust1", since = "1.0.0")] pub use wrapping::Wrapping; +macro_rules! u8_xe_bytes_doc { + () => { + " + +**Note**: This function is meaningless on `u8`. Byte order does not exist as a +concept for byte-sized integers. This function is only provided in symmetry +with larger integer types. + +" + }; +} + +macro_rules! i8_xe_bytes_doc { + () => { + " + +**Note**: This function is meaningless on `i8`. Byte order does not exist as a +concept for byte-sized integers. This function is only provided in symmetry +with larger integer types. You can cast from and to `u8` using `as i8` and `as +u8`. + +" + }; +} + macro_rules! usize_isize_to_xe_bytes_doc { () => { " @@ -348,8 +373,8 @@ impl i8 { reversed = "0x48", le_bytes = "[0x12]", be_bytes = "[0x12]", - to_xe_bytes_doc = "", - from_xe_bytes_doc = "", + to_xe_bytes_doc = i8_xe_bytes_doc!(), + from_xe_bytes_doc = i8_xe_bytes_doc!(), bound_condition = "", } midpoint_impl! { i8, i16, signed } @@ -547,8 +572,8 @@ impl u8 { reversed = "0x48", le_bytes = "[0x12]", be_bytes = "[0x12]", - to_xe_bytes_doc = "", - from_xe_bytes_doc = "", + to_xe_bytes_doc = u8_xe_bytes_doc!(), + from_xe_bytes_doc = u8_xe_bytes_doc!(), bound_condition = "", } widening_impl! { u8, u16, 8, unsigned } From d03ec88d27427ed08024fd4a567657e8e00e5986 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 12 Nov 2024 17:27:52 -0800 Subject: [PATCH 114/481] De-duplicate and improve definition of core::ffi::c_char Instead of having a list of unsigned char targets for each OS, follow the logic Clang uses and instead set the value based on architecture with a special case for Darwin and Windows operating systems. This makes it easier to support new operating systems targeting Arm/AArch64 without having to modify this config statement for each new OS. The new list does not quite match Clang since I noticed a few bugs in the Clang implementation (https://github.com/llvm/llvm-project/issues/115957). Fixes: https://github.com/rust-lang/rust/issues/129945 --- core/src/ffi/mod.rs | 77 ++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index dc107c5d22cdd..a9be4ebea4e19 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -91,59 +91,30 @@ pub type c_ssize_t = isize; mod c_char_definition { cfg_if! { - // These are the targets on which c_char is unsigned. - if #[cfg(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32", - target_arch = "csky" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - any(target_os = "freebsd", target_os = "openbsd", target_os = "rtems"), - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "riscv64" - ) - ), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all( - target_os = "fuchsia", - any(target_arch = "aarch64", target_arch = "riscv64") - ), - all(target_os = "nto", target_arch = "aarch64"), - target_os = "horizon", - target_os = "aix", + // These are the targets on which c_char is unsigned. Usually the + // signedness is the same for all target_os values on a given + // architecture but there are some exceptions (see isSignedCharDefault() + // in clang/lib/Driver/ToolChains/Clang.cpp): + // - PowerPC uses unsigned char for all targets except Darwin + // - Arm/AArch64 uses unsigned char except for Darwin and Windows + // - L4RE builds with -funsigned-char on all targets + if #[cfg(all( + not(windows), + not(target_vendor = "apple"), + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "csky", + target_arch = "hexagon", + target_arch = "msp430", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "riscv32", + target_arch = "s390x", + target_arch = "xtensa", + target_os = "l4re", + ) ))] { pub type c_char = u8; } else { From 352f63547e030591fbb09716f69d8dcce876e9ec Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Wed, 4 Dec 2024 09:41:51 -0800 Subject: [PATCH 115/481] Remove l4re from the unsigned char operating system list As noted in https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240, the default for userland apps is to follow the architecture defaults, the -funsigned-char flag only applies to kernel builds. --- core/src/ffi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index a9be4ebea4e19..827c8ca15d4ed 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -97,7 +97,8 @@ mod c_char_definition { // in clang/lib/Driver/ToolChains/Clang.cpp): // - PowerPC uses unsigned char for all targets except Darwin // - Arm/AArch64 uses unsigned char except for Darwin and Windows - // - L4RE builds with -funsigned-char on all targets + // Note: the L4RE kernel builds with -funsigned-char on all targets, but + // we only have a target for userspace apps so it follows the architectures. if #[cfg(all( not(windows), not(target_vendor = "apple"), @@ -113,7 +114,6 @@ mod c_char_definition { target_arch = "riscv32", target_arch = "s390x", target_arch = "xtensa", - target_os = "l4re", ) ))] { pub type c_char = u8; From e82cda443c00e32aca58cfa6e062ea57f8c21f9c Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 10 Dec 2024 08:33:17 -0800 Subject: [PATCH 116/481] Add references to the specific ABI documents Expcept for L4RE and Xtensa these were obtained from #131319 I could not find an open link to the Xtensa documentation, but the signedness was confirmed by on of the Xtensa developers in https://github.com/llvm/llvm-project/pull/115967#issuecomment-2506292323 Co-authored-by: Taiki Endo --- core/src/ffi/mod.rs | 70 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 827c8ca15d4ed..7a161f595f41b 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -92,13 +92,69 @@ pub type c_ssize_t = isize; mod c_char_definition { cfg_if! { // These are the targets on which c_char is unsigned. Usually the - // signedness is the same for all target_os values on a given - // architecture but there are some exceptions (see isSignedCharDefault() - // in clang/lib/Driver/ToolChains/Clang.cpp): - // - PowerPC uses unsigned char for all targets except Darwin - // - Arm/AArch64 uses unsigned char except for Darwin and Windows - // Note: the L4RE kernel builds with -funsigned-char on all targets, but - // we only have a target for userspace apps so it follows the architectures. + // signedness is the same for all target_os values on a given architecture + // but there are some exceptions (see isSignedCharDefault() in clang). + // + // aarch64: + // Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the Arm® + // 64-bit Architecture (AArch64) says C/C++ char is unsigned byte. + // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs64/aapcs64.rst#arm-c-and-c-language-mappings + // arm: + // Section 8 "Arm C and C++ Language Mappings" in Procedure Call Standard for the Arm® + // Architecture says C/C++ char is unsigned byte. + // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs32/aapcs32.rst#arm-c-and-c-language-mappings + // csky: + // Section 2.1.2 "Primary Data Type" in C-SKY V2 CPU Applications Binary Interface + // Standards Manual says ANSI C char is unsigned byte. + // https://github.com/c-sky/csky-doc/blob/9f7121f7d40970ba5cc0f15716da033db2bb9d07/C-SKY_V2_CPU_Applications_Binary_Interface_Standards_Manual.pdf + // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). + // hexagon: + // Section 3.1 "Basic data type" in Qualcomm Hexagon™ Application + // Binary Interface User Guide says "By default, the `char` data type is unsigned." + // https://docs.qualcomm.com/bundle/publicresource/80-N2040-23_REV_K_Qualcomm_Hexagon_Application_Binary_Interface_User_Guide.pdf + // msp430: + // Section 2.1 "Basic Types" in MSP430 Embedded Application Binary + // Interface says "The char type is unsigned by default". + // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf + // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). + // powerpc/powerpc64: + // - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC + // Processor Supplement says ANSI C char is unsigned byte + // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf + // - PPC64 ELFv1: Section 3.1.4 "Fundamental Types" in 64-bit PowerPC ELF Application + // Binary Interface Supplement 1.9 says ANSI C is unsigned byte + // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUND-TYPE + // - PPC64 ELFv2: Section 2.1.2.2 "Fundamental Types" in 64-Bit ELF V2 ABI Specification + // says char is unsigned byte + // https://openpowerfoundation.org/specifications/64bitelfabi/ + // - AIX: XL C for AIX Language Reference says "By default, char behaves like an unsigned char." + // https://www.ibm.com/docs/en/xl-c-aix/13.1.3?topic=specifiers-character-types + // riscv32/riscv64: + // C/C++ type representations section in RISC-V Calling Conventions + // page in RISC-V ELF psABI Document says "char is unsigned." + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/draft-20240829-13bfa9f54634cb60d86b9b333e109f077805b4b3/riscv-cc.adoc#cc-type-representations + // s390x: + // - ELF: "Table 1.1.: Scalar types" in ELF Application Binary Interface s390x Supplement + // Version 1.6.1 categorize ISO C char in unsigned integer + // https://github.com/IBM/s390x-abi/releases/tag/v1.6.1 + // - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char." + // https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types + // Xtensa: + // - "The char type is unsigned by default for Xtensa processors." + // + // On the following operating systems, c_char is signed by default, regardless of architecture. + // Darwin (macOS, iOS, etc.): + // Apple targets' c_char is signed by default even on arm + // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Handle-data-types-and-data-alignment-properly + // Windows: + // Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char + // are promoted to int as if from type signed char by default, unless the /J compilation + // option is used." + // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types) + // L4RE: + // The kernel builds with -funsigned-char on all targets (but useserspace follows the + // architecture defaults). As we only have a target for userspace apps so there are no + // special cases for L4RE below. if #[cfg(all( not(windows), not(target_vendor = "apple"), From b1e5646b9b7261060be5410a33f718af8091036f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Nov 2024 23:34:47 +0200 Subject: [PATCH 117/481] Change `GetManyMutError` to match T-libs-api decision That is, differentiate between out-of-bounds and overlapping indices, and remove the generic parameter `N`. I also exported `GetManyMutError` from `alloc` (and `std`), which was apparently forgotten. Changing the error to carry additional details means LLVM no longer generates separate short-circuiting branches for the checks, instead it generates one branch at the end. I therefore changed the code to use early returns to make LLVM generate jumps. Benchmark results between the approaches are somewhat mixed, but I chose this approach because it is significantly faster with ranges and also faster with `unwrap()`. --- alloc/src/slice.rs | 2 ++ core/src/error.rs | 2 +- core/src/slice/mod.rs | 58 +++++++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/alloc/src/slice.rs b/alloc/src/slice.rs index e3c7835f1d10b..edc8d99f2f990 100644 --- a/alloc/src/slice.rs +++ b/alloc/src/slice.rs @@ -27,6 +27,8 @@ pub use core::slice::ArrayChunksMut; pub use core::slice::ArrayWindows; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; +#[unstable(feature = "get_many_mut", issue = "104642")] +pub use core::slice::GetManyMutError; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[cfg(not(no_global_oom_handling))] diff --git a/core/src/error.rs b/core/src/error.rs index 95a39cc3aed38..91549f49f9f9d 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -1076,4 +1076,4 @@ impl Error for crate::time::TryFromFloatSecsError {} impl Error for crate::ffi::FromBytesUntilNulError {} #[unstable(feature = "get_many_mut", issue = "104642")] -impl Error for crate::slice::GetManyMutError {} +impl Error for crate::slice::GetManyMutError {} diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 191eaccff9899..97a7338b0bfe8 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -4629,13 +4629,11 @@ impl [T] { pub fn get_many_mut( &mut self, indices: [I; N], - ) -> Result<[&mut I::Output; N], GetManyMutError> + ) -> Result<[&mut I::Output; N], GetManyMutError> where I: GetManyMutIndex + SliceIndex, { - if !get_many_check_valid(&indices, self.len()) { - return Err(GetManyMutError { _private: () }); - } + get_many_check_valid(&indices, self.len())?; // SAFETY: The `get_many_check_valid()` call checked that all indices // are disjunct and in bounds. unsafe { Ok(self.get_many_unchecked_mut(indices)) } @@ -4978,53 +4976,59 @@ impl SlicePattern for [T; N] { /// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` /// comparison operations. #[inline] -fn get_many_check_valid(indices: &[I; N], len: usize) -> bool { +fn get_many_check_valid( + indices: &[I; N], + len: usize, +) -> Result<(), GetManyMutError> { // NB: The optimizer should inline the loops into a sequence // of instructions without additional branching. - let mut valid = true; for (i, idx) in indices.iter().enumerate() { - valid &= idx.is_in_bounds(len); + if !idx.is_in_bounds(len) { + return Err(GetManyMutError::IndexOutOfBounds); + } for idx2 in &indices[..i] { - valid &= !idx.is_overlapping(idx2); + if idx.is_overlapping(idx2) { + return Err(GetManyMutError::OverlappingIndices); + } } } - valid + Ok(()) } -/// The error type returned by [`get_many_mut`][`slice::get_many_mut`]. +/// The error type returned by [`get_many_mut`][`slice::get_many_mut`]. /// /// It indicates one of two possible errors: /// - An index is out-of-bounds. -/// - The same index appeared multiple times in the array. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). /// /// # Examples /// /// ``` /// #![feature(get_many_mut)] +/// use std::slice::GetManyMutError; /// /// let v = &mut [1, 2, 3]; -/// assert!(v.get_many_mut([0, 999]).is_err()); -/// assert!(v.get_many_mut([1, 1]).is_err()); +/// assert_eq!(v.get_many_mut([0, 999]), Err(GetManyMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_many_mut([1, 1]), Err(GetManyMutError::OverlappingIndices)); /// ``` #[unstable(feature = "get_many_mut", issue = "104642")] -// NB: The N here is there to be forward-compatible with adding more details -// to the error type at a later point -#[derive(Clone, PartialEq, Eq)] -pub struct GetManyMutError { - _private: (), +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetManyMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, } #[unstable(feature = "get_many_mut", issue = "104642")] -impl fmt::Debug for GetManyMutError { +impl fmt::Display for GetManyMutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GetManyMutError").finish_non_exhaustive() - } -} - -#[unstable(feature = "get_many_mut", issue = "104642")] -impl fmt::Display for GetManyMutError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f) + let msg = match self { + GetManyMutError::IndexOutOfBounds => "an index is out of bounds", + GetManyMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) } } From 3e598f613031c3120af0f8bda6016c6080515b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sat, 28 Sep 2024 11:05:03 +0200 Subject: [PATCH 118/481] control libunwind linkage mode via `crt-static` on gnullvm targets Co-authored-by: Kleis Auke Wolthuizen --- unwind/src/lib.rs | 5 +++++ unwind/src/libunwind.rs | 9 +++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/unwind/src/lib.rs b/unwind/src/lib.rs index 79baa5b0b83ec..40d409310ffab 100644 --- a/unwind/src/lib.rs +++ b/unwind/src/lib.rs @@ -178,3 +178,8 @@ cfg_if::cfg_if! { #[cfg(target_os = "hurd")] #[link(name = "gcc_s")] extern "C" {} + +#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))] +#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "unwind", cfg(not(target_feature = "crt-static")))] +extern "C" {} diff --git a/unwind/src/libunwind.rs b/unwind/src/libunwind.rs index 715f8b57876ae..1fa9e480166b7 100644 --- a/unwind/src/libunwind.rs +++ b/unwind/src/libunwind.rs @@ -102,12 +102,9 @@ pub type _Unwind_Exception_Cleanup_Fn = // rustc_codegen_ssa::src::back::symbol_export, rustc_middle::middle::exported_symbols // and RFC 2841 #[cfg_attr( - any( - all( - feature = "llvm-libunwind", - any(target_os = "fuchsia", target_os = "linux", target_os = "xous") - ), - all(target_os = "windows", target_env = "gnu", target_abi = "llvm") + all( + feature = "llvm-libunwind", + any(target_os = "fuchsia", target_os = "linux", target_os = "xous") ), link(name = "unwind", kind = "static", modifiers = "-bundle") )] From 59d4c0569d4d4a106bc8f57d098663b947e94cb8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:26:18 +0000 Subject: [PATCH 119/481] Move some alloc tests to the alloctests crate Unit tests directly inside of standard library crates require a very fragile way of building that is hard to reproduce outside of bootstrap. --- alloc/src/alloc.rs | 3 - alloc/src/collections/binary_heap/mod.rs | 3 - alloc/src/ffi/c_str.rs | 3 - alloc/src/lib.rs | 2 - alloc/src/sync.rs | 3 - alloc/{src/alloc/tests.rs => tests/alloc.rs} | 5 +- .../ffi/c_str/tests.rs => tests/c_str2.rs} | 7 +- .../collections/binary_heap.rs} | 8 +- alloc/tests/collections/mod.rs | 1 + alloc/tests/lib.rs | 24 ++++++ alloc/{src/tests.rs => tests/misc_tests.rs} | 0 alloc/{src/sync/tests.rs => tests/sync.rs} | 10 ++- alloc/tests/testing/crash_test.rs | 80 +++++++++++++++++++ alloc/tests/testing/mod.rs | 1 + 14 files changed, 123 insertions(+), 27 deletions(-) rename alloc/{src/alloc/tests.rs => tests/alloc.rs} (93%) rename alloc/{src/ffi/c_str/tests.rs => tests/c_str2.rs} (98%) rename alloc/{src/collections/binary_heap/tests.rs => tests/collections/binary_heap.rs} (99%) create mode 100644 alloc/tests/collections/mod.rs rename alloc/{src/tests.rs => tests/misc_tests.rs} (100%) rename alloc/{src/sync/tests.rs => tests/sync.rs} (98%) create mode 100644 alloc/tests/testing/crash_test.rs create mode 100644 alloc/tests/testing/mod.rs diff --git a/alloc/src/alloc.rs b/alloc/src/alloc.rs index 04b7315e650a2..ae34fc653260e 100644 --- a/alloc/src/alloc.rs +++ b/alloc/src/alloc.rs @@ -10,9 +10,6 @@ use core::hint; #[cfg(not(test))] use core::ptr::{self, NonNull}; -#[cfg(test)] -mod tests; - extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 5d3997e14e3e9..116e0e73e9659 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -155,9 +155,6 @@ use crate::collections::TryReserveError; use crate::slice; use crate::vec::{self, AsVecIntoIter, Vec}; -#[cfg(test)] -mod tests; - /// A priority queue implemented with a binary heap. /// /// This will be a max-heap. diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index 9c074383a5ecb..c7d6d8a55c2e3 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -1,8 +1,5 @@ //! [`CString`] and its related types. -#[cfg(test)] -mod tests; - use core::borrow::Borrow; use core::ffi::{CStr, c_char}; use core::num::NonZero; diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 927c3aa23b9f7..78cdeeb2866ef 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -239,8 +239,6 @@ pub mod string; pub mod sync; #[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))] pub mod task; -#[cfg(test)] -mod tests; pub mod vec; #[doc(hidden)] diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index b8bdd298c27ab..6cf41a3fa4e16 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -39,9 +39,6 @@ use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; -#[cfg(test)] -mod tests; - /// A soft limit on the amount of references that may be made to an `Arc`. /// /// Going above this limit will abort your program (although not diff --git a/alloc/src/alloc/tests.rs b/alloc/tests/alloc.rs similarity index 93% rename from alloc/src/alloc/tests.rs rename to alloc/tests/alloc.rs index 5d6077f057a2c..1e722d667955c 100644 --- a/alloc/src/alloc/tests.rs +++ b/alloc/tests/alloc.rs @@ -1,10 +1,9 @@ -use super::*; +use alloc::alloc::*; +use alloc::boxed::Box; extern crate test; use test::Bencher; -use crate::boxed::Box; - #[test] fn allocate_zeroed() { unsafe { diff --git a/alloc/src/ffi/c_str/tests.rs b/alloc/tests/c_str2.rs similarity index 98% rename from alloc/src/ffi/c_str/tests.rs rename to alloc/tests/c_str2.rs index d6b797347c2ec..0f4c27fa12322 100644 --- a/alloc/src/ffi/c_str/tests.rs +++ b/alloc/tests/c_str2.rs @@ -1,11 +1,12 @@ +use alloc::ffi::CString; +use alloc::rc::Rc; +use alloc::sync::Arc; use core::assert_matches::assert_matches; -use core::ffi::FromBytesUntilNulError; +use core::ffi::{CStr, FromBytesUntilNulError, c_char}; #[allow(deprecated)] use core::hash::SipHasher13 as DefaultHasher; use core::hash::{Hash, Hasher}; -use super::*; - #[test] fn c_to_rust() { let data = b"123\0"; diff --git a/alloc/src/collections/binary_heap/tests.rs b/alloc/tests/collections/binary_heap.rs similarity index 99% rename from alloc/src/collections/binary_heap/tests.rs rename to alloc/tests/collections/binary_heap.rs index ad0a020a1a961..55405ffe8c4f6 100644 --- a/alloc/src/collections/binary_heap/tests.rs +++ b/alloc/tests/collections/binary_heap.rs @@ -1,7 +1,9 @@ +use alloc::boxed::Box; +use alloc::collections::binary_heap::*; +use std::iter::TrustedLen; +use std::mem; use std::panic::{AssertUnwindSafe, catch_unwind}; -use super::*; -use crate::boxed::Box; use crate::testing::crash_test::{CrashTestDummy, Panic}; #[test] @@ -531,7 +533,7 @@ fn panic_safe() { self.0.partial_cmp(&other.0) } } - let mut rng = crate::test_helpers::test_rng(); + let mut rng = crate::test_rng(); const DATASZ: usize = 32; // Miri is too slow let ntest = if cfg!(miri) { 1 } else { 10 }; diff --git a/alloc/tests/collections/mod.rs b/alloc/tests/collections/mod.rs new file mode 100644 index 0000000000000..e73f3aaef8c83 --- /dev/null +++ b/alloc/tests/collections/mod.rs @@ -0,0 +1 @@ +mod binary_heap; diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs index bcab17e7b2ddc..393bdfe48b741 100644 --- a/alloc/tests/lib.rs +++ b/alloc/tests/lib.rs @@ -5,8 +5,10 @@ #![feature(btree_extract_if)] #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] +#![feature(downcast_unchecked)] #![feature(extract_if)] #![feature(exact_size_is_empty)] +#![feature(hashmap_internals)] #![feature(linked_list_cursors)] #![feature(map_try_insert)] #![feature(pattern)] @@ -29,9 +31,11 @@ #![feature(const_str_from_utf8)] #![feature(panic_update_hook)] #![feature(pointer_is_aligned_to)] +#![feature(test)] #![feature(thin_box)] #![feature(drain_keep_rest)] #![feature(local_waker)] +#![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(vec_pop_if)] #![feature(unique_rc_arc)] @@ -40,25 +44,33 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +extern crate test; + use std::hash::{DefaultHasher, Hash, Hasher}; +mod alloc; mod arc; mod autotraits; mod borrow; mod boxed; mod btree_set_hash; mod c_str; +mod c_str2; +mod collections; mod const_fns; mod cow_str; mod fmt; mod heap; mod linked_list; +mod misc_tests; mod rc; mod slice; mod sort; mod str; mod string; +mod sync; mod task; +mod testing; mod thin_box; mod vec; mod vec_deque; @@ -69,6 +81,18 @@ fn hash(t: &T) -> u64 { s.finish() } +/// Copied from `std::test_helpers::test_rng`, since these tests rely on the +/// seed not being the same for every RNG invocation too. +fn test_rng() -> rand_xorshift::XorShiftRng { + use std::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + std::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) +} + // FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten. // See https://github.com/kripken/emscripten-fastcomp/issues/169 #[cfg(not(target_os = "emscripten"))] diff --git a/alloc/src/tests.rs b/alloc/tests/misc_tests.rs similarity index 100% rename from alloc/src/tests.rs rename to alloc/tests/misc_tests.rs diff --git a/alloc/src/sync/tests.rs b/alloc/tests/sync.rs similarity index 98% rename from alloc/src/sync/tests.rs rename to alloc/tests/sync.rs index de5816fda974a..7a9a4abfdc672 100644 --- a/alloc/src/sync/tests.rs +++ b/alloc/tests/sync.rs @@ -1,14 +1,16 @@ +use alloc::sync::*; +use std::alloc::{AllocError, Allocator, Layout}; +use std::any::Any; use std::clone::Clone; use std::mem::MaybeUninit; use std::option::Option::None; +use std::ptr::NonNull; use std::sync::Mutex; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{self, AtomicUsize}; use std::sync::mpsc::channel; use std::thread; -use super::*; - struct Canary(*mut AtomicUsize); impl Drop for Canary { diff --git a/alloc/tests/testing/crash_test.rs b/alloc/tests/testing/crash_test.rs new file mode 100644 index 0000000000000..502fe6c10c6fd --- /dev/null +++ b/alloc/tests/testing/crash_test.rs @@ -0,0 +1,80 @@ +use std::cmp::Ordering; +use std::fmt::Debug; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +/// A blueprint for crash test dummy instances that monitor drops. +/// Some instances may be configured to panic at some point. +/// +/// Crash test dummies are identified and ordered by an id, so they can be used +/// as keys in a BTreeMap. +#[derive(Debug)] +pub struct CrashTestDummy { + pub id: usize, + dropped: AtomicUsize, +} + +impl CrashTestDummy { + /// Creates a crash test dummy design. The `id` determines order and equality of instances. + pub fn new(id: usize) -> CrashTestDummy { + CrashTestDummy { id, dropped: AtomicUsize::new(0) } + } + + /// Creates an instance of a crash test dummy that records what events it experiences + /// and optionally panics. + pub fn spawn(&self, panic: Panic) -> Instance<'_> { + Instance { origin: self, panic } + } + + /// Returns how many times instances of the dummy have been dropped. + pub fn dropped(&self) -> usize { + self.dropped.load(SeqCst) + } +} + +#[derive(Debug)] +pub struct Instance<'a> { + origin: &'a CrashTestDummy, + panic: Panic, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Panic { + Never, + InDrop, +} + +impl Instance<'_> { + pub fn id(&self) -> usize { + self.origin.id + } +} + +impl Drop for Instance<'_> { + fn drop(&mut self) { + self.origin.dropped.fetch_add(1, SeqCst); + if self.panic == Panic::InDrop { + panic!("panic in `drop`"); + } + } +} + +impl PartialOrd for Instance<'_> { + fn partial_cmp(&self, other: &Self) -> Option { + self.id().partial_cmp(&other.id()) + } +} + +impl Ord for Instance<'_> { + fn cmp(&self, other: &Self) -> Ordering { + self.id().cmp(&other.id()) + } +} + +impl PartialEq for Instance<'_> { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for Instance<'_> {} diff --git a/alloc/tests/testing/mod.rs b/alloc/tests/testing/mod.rs new file mode 100644 index 0000000000000..0a3dd191dc891 --- /dev/null +++ b/alloc/tests/testing/mod.rs @@ -0,0 +1 @@ +pub mod crash_test; From b32e1d981e8329aba3a9e7ec4cd894bdf809d128 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Wed, 11 Dec 2024 00:56:58 +0100 Subject: [PATCH 120/481] Forbid unsafe_op_in_unsafe_fn in hurd-specific os and sys files Adding it did not cause any error. Most of this falls back on Unix already. See #127747 --- std/src/os/hurd/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/os/hurd/mod.rs b/std/src/os/hurd/mod.rs index aee86c7f61655..6cd50aeada1da 100644 --- a/std/src/os/hurd/mod.rs +++ b/std/src/os/hurd/mod.rs @@ -1,6 +1,7 @@ //! Hurd-specific definitions #![stable(feature = "raw_ext", since = "1.1.0")] +#![forbid(unsafe_op_in_unsafe_fn)] pub mod fs; pub mod raw; From b80e47fc1eb23ca4955b50c75a11a1a4b2a3e16e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Dec 2024 10:59:35 -0800 Subject: [PATCH 121/481] Stabilize the Rust 2024 prelude --- core/src/prelude/mod.rs | 4 ++-- std/src/lib.rs | 1 - std/src/prelude/mod.rs | 16 +++++++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/core/src/prelude/mod.rs b/core/src/prelude/mod.rs index 496b78439ea6c..9b23874bcf7ba 100644 --- a/core/src/prelude/mod.rs +++ b/core/src/prelude/mod.rs @@ -71,7 +71,7 @@ pub mod rust_2021 { /// The 2024 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2024", issue = "121042")] +#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] pub mod rust_2024 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; @@ -84,7 +84,7 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::convert::{TryFrom, TryInto}; - #[unstable(feature = "prelude_2024", issue = "121042")] + #[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] #[doc(no_inline)] pub use crate::future::{Future, IntoFuture}; } diff --git a/std/src/lib.rs b/std/src/lib.rs index 49a0322003905..047f5b0c4c584 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -348,7 +348,6 @@ #![feature(pin_coerce_unsized_trait)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] -#![feature(prelude_2024)] #![feature(ptr_as_uninit)] #![feature(ptr_mask)] #![feature(random)] diff --git a/std/src/prelude/mod.rs b/std/src/prelude/mod.rs index 0c610ba67e65c..fffc1e9264e7c 100644 --- a/std/src/prelude/mod.rs +++ b/std/src/prelude/mod.rs @@ -25,6 +25,7 @@ //! //! # Prelude contents //! +//! The items included in the prelude depend on the edition of the crate. //! The first version of the prelude is used in Rust 2015 and Rust 2018, //! and lives in [`std::prelude::v1`]. //! [`std::prelude::rust_2015`] and [`std::prelude::rust_2018`] re-export this prelude. @@ -67,15 +68,21 @@ //! The prelude used in Rust 2021, [`std::prelude::rust_2021`], includes all of the above, //! and in addition re-exports: //! -//! * [std::convert]::{[TryFrom], [TryInto]}, +//! * [std::convert]::{[TryFrom], [TryInto]}. //! * [std::iter]::[FromIterator]. //! +//! The prelude used in Rust 2024, [`std::prelude::rust_2024`], includes all of the above, +//! and in addition re-exports: +//! +//! * [std::future]::{[Future], [IntoFuture]}. +//! //! [std::borrow]: crate::borrow //! [std::boxed]: crate::boxed //! [std::clone]: crate::clone //! [std::cmp]: crate::cmp //! [std::convert]: crate::convert //! [std::default]: crate::default +//! [std::future]: crate::future //! [std::iter]: crate::iter //! [std::marker]: crate::marker //! [std::mem]: crate::mem @@ -85,6 +92,7 @@ //! [`std::prelude::rust_2015`]: rust_2015 //! [`std::prelude::rust_2018`]: rust_2018 //! [`std::prelude::rust_2021`]: rust_2021 +//! [`std::prelude::rust_2024`]: rust_2024 //! [std::result]: crate::result //! [std::slice]: crate::slice //! [std::string]: crate::string @@ -94,6 +102,8 @@ //! [book-dtor]: ../../book/ch15-03-drop.html //! [book-enums]: ../../book/ch06-01-defining-an-enum.html //! [book-iter]: ../../book/ch13-02-iterators.html +//! [Future]: crate::future::Future +//! [IntoFuture]: crate::future::IntoFuture // No formatting: this file is nothing but re-exports, and their order is worth preserving. #![cfg_attr(rustfmt, rustfmt::skip)] @@ -158,12 +168,12 @@ pub mod rust_2021 { /// The 2024 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2024", issue = "121042")] +#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] pub mod rust_2024 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - #[unstable(feature = "prelude_2024", issue = "121042")] + #[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] #[doc(no_inline)] pub use core::prelude::rust_2024::*; } From a7aae9e06e58ad1fbc8c03e68caca6a9b8a5e77e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 11 Dec 2024 12:56:12 -0600 Subject: [PATCH 122/481] Remove consteval note from <*mut T>::align_offset docs. --- core/src/ptr/mut_ptr.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 6d0361b8c63f4..3639feaacf3ab 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -1587,15 +1587,6 @@ impl *mut T { /// beyond the allocation that the pointer points into. It is up to the caller to ensure that /// the returned offset is correct in all terms other than alignment. /// - /// When this is called during compile-time evaluation (which is unstable), the implementation - /// may return `usize::MAX` in cases where that can never happen at runtime. This is because the - /// actual alignment of pointers is not known yet during compile-time, so an offset with - /// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8; - /// N]` might be allocated at an odd or an even address, but at compile-time this is not yet - /// known, so the execution has to be correct for either choice. It is therefore impossible to - /// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual - /// for unstable APIs.) - /// /// # Panics /// /// The function panics if `align` is not a power-of-two. From fb95d2be63d555a86546b065456724022f6cd3da Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Nov 2024 17:53:59 +0000 Subject: [PATCH 123/481] Stabilize async closures --- alloc/src/boxed.rs | 9 ++++++--- alloc/src/lib.rs | 2 +- core/src/ops/async_function.rs | 24 ++++++++++++++++-------- std/src/prelude/common.rs | 3 ++- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index e0f94428cfa65..23b85fbd4ebc3 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -1985,7 +1985,8 @@ impl + ?Sized, A: Allocator> Fn for Box { } } -#[unstable(feature = "async_fn_traits", issue = "none")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl + ?Sized, A: Allocator> AsyncFnOnce for Box { type Output = F::Output; type CallOnceFuture = F::CallOnceFuture; @@ -1995,7 +1996,8 @@ impl + ?Sized, A: Allocator> AsyncFnOnce } } -#[unstable(feature = "async_fn_traits", issue = "none")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl + ?Sized, A: Allocator> AsyncFnMut for Box { type CallRefFuture<'a> = F::CallRefFuture<'a> @@ -2007,7 +2009,8 @@ impl + ?Sized, A: Allocator> AsyncFnMut f } } -#[unstable(feature = "async_fn_traits", issue = "none")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl + ?Sized, A: Allocator> AsyncFn for Box { extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 78cdeeb2866ef..40759cb0ba83c 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -91,6 +91,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(async_closure))] #![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] @@ -99,7 +100,6 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] -#![feature(async_closure)] #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(box_uninit_write)] diff --git a/core/src/ops/async_function.rs b/core/src/ops/async_function.rs index 4b230b15a1e6f..0073afd496070 100644 --- a/core/src/ops/async_function.rs +++ b/core/src/ops/async_function.rs @@ -4,7 +4,8 @@ use crate::marker::Tuple; /// An async-aware version of the [`Fn`](crate::ops::Fn) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[unstable(feature = "async_closure", issue = "62290")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -18,7 +19,8 @@ pub trait AsyncFn: AsyncFnMut { /// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[unstable(feature = "async_closure", issue = "62290")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -39,7 +41,8 @@ pub trait AsyncFnMut: AsyncFnOnce { /// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[unstable(feature = "async_closure", issue = "62290")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -64,7 +67,8 @@ mod impls { use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; use crate::marker::Tuple; - #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl AsyncFn for &F where F: AsyncFn, @@ -74,7 +78,8 @@ mod impls { } } - #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl AsyncFnMut for &F where F: AsyncFn, @@ -89,7 +94,8 @@ mod impls { } } - #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F where F: AsyncFn, @@ -102,7 +108,8 @@ mod impls { } } - #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl AsyncFnMut for &mut F where F: AsyncFnMut, @@ -117,7 +124,8 @@ mod impls { } } - #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F where F: AsyncFnMut, diff --git a/std/src/prelude/common.rs b/std/src/prelude/common.rs index e4731280ffe35..22a364074c52d 100644 --- a/std/src/prelude/common.rs +++ b/std/src/prelude/common.rs @@ -12,7 +12,8 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; -#[unstable(feature = "async_closure", issue = "62290")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] #[doc(no_inline)] pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; From 05e7d867a7675906aef74e30e1f25a2e620ff4aa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 12 Dec 2024 23:22:02 +0000 Subject: [PATCH 124/481] Reword prelude for AsyncFn stabilization --- std/src/prelude/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/src/prelude/mod.rs b/std/src/prelude/mod.rs index fffc1e9264e7c..64349987fcfb8 100644 --- a/std/src/prelude/mod.rs +++ b/std/src/prelude/mod.rs @@ -33,8 +33,9 @@ //! //! * [std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}, //! marker traits that indicate fundamental properties of types. -//! * [std::ops]::{[Drop], [Fn], [FnMut], [FnOnce]}, various -//! operations for both destructors and overloading `()`. +//! * [std::ops]::{[Fn], [FnMut], [FnOnce]}, and their analogous +//! async traits, [std::ops]::{[AsyncFn], [AsyncFnMut], [AsyncFnOnce]}. +//! * [std::ops]::[Drop], for implementing destructors. //! * [std::mem]::[drop], a convenience function for explicitly //! dropping a value. //! * [std::mem]::{[size_of], [size_of_val]}, to get the size of From e1431bc16f8b692d0ba8ff333d3138ad4b8291c3 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 8 Dec 2024 15:40:56 -0500 Subject: [PATCH 125/481] Switch inline(always) in core/src/fmt/rt.rs to plain inline --- core/src/fmt/rt.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/core/src/fmt/rt.rs b/core/src/fmt/rt.rs index af6f0da88de67..94341a4da66cd 100644 --- a/core/src/fmt/rt.rs +++ b/core/src/fmt/rt.rs @@ -19,7 +19,7 @@ pub struct Placeholder { } impl Placeholder { - #[inline(always)] + #[inline] pub const fn new( position: usize, fill: char, @@ -95,7 +95,7 @@ pub struct Argument<'a> { #[rustc_diagnostic_item = "ArgumentMethods"] impl Argument<'_> { - #[inline(always)] + #[inline] fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { Argument { // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and @@ -109,47 +109,47 @@ impl Argument<'_> { } } - #[inline(always)] + #[inline] pub fn new_display(x: &T) -> Argument<'_> { Self::new(x, Display::fmt) } - #[inline(always)] + #[inline] pub fn new_debug(x: &T) -> Argument<'_> { Self::new(x, Debug::fmt) } - #[inline(always)] + #[inline] pub fn new_debug_noop(x: &T) -> Argument<'_> { Self::new(x, |_, _| Ok(())) } - #[inline(always)] + #[inline] pub fn new_octal(x: &T) -> Argument<'_> { Self::new(x, Octal::fmt) } - #[inline(always)] + #[inline] pub fn new_lower_hex(x: &T) -> Argument<'_> { Self::new(x, LowerHex::fmt) } - #[inline(always)] + #[inline] pub fn new_upper_hex(x: &T) -> Argument<'_> { Self::new(x, UpperHex::fmt) } - #[inline(always)] + #[inline] pub fn new_pointer(x: &T) -> Argument<'_> { Self::new(x, Pointer::fmt) } - #[inline(always)] + #[inline] pub fn new_binary(x: &T) -> Argument<'_> { Self::new(x, Binary::fmt) } - #[inline(always)] + #[inline] pub fn new_lower_exp(x: &T) -> Argument<'_> { Self::new(x, LowerExp::fmt) } - #[inline(always)] + #[inline] pub fn new_upper_exp(x: &T) -> Argument<'_> { Self::new(x, UpperExp::fmt) } - #[inline(always)] + #[inline] pub fn from_usize(x: &usize) -> Argument<'_> { Argument { ty: ArgumentType::Count(*x) } } @@ -164,7 +164,7 @@ impl Argument<'_> { // it here is an explicit CFI violation. #[allow(inline_no_sanitize)] #[no_sanitize(cfi, kcfi)] - #[inline(always)] + #[inline] pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.ty { // SAFETY: @@ -180,7 +180,7 @@ impl Argument<'_> { } } - #[inline(always)] + #[inline] pub(super) fn as_usize(&self) -> Option { match self.ty { ArgumentType::Count(count) => Some(count), @@ -198,7 +198,7 @@ impl Argument<'_> { /// let f = format_args!("{}", "a"); /// println!("{f}"); /// ``` - #[inline(always)] + #[inline] pub fn none() -> [Self; 0] { [] } @@ -215,7 +215,7 @@ pub struct UnsafeArg { impl UnsafeArg { /// See documentation where `UnsafeArg` is required to know when it is safe to /// create and use `UnsafeArg`. - #[inline(always)] + #[inline] pub unsafe fn new() -> Self { Self { _private: () } } From a9a748a54f513dd44210c030edd64c96c81b4456 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 13 Sep 2024 14:00:10 -0400 Subject: [PATCH 126/481] Add unwrap_unsafe_binder and wrap_unsafe_binder macro operators --- core/src/lib.rs | 2 ++ core/src/unsafe_binder.rs | 25 +++++++++++++++++++++++++ std/src/lib.rs | 2 ++ 3 files changed, 29 insertions(+) create mode 100644 core/src/unsafe_binder.rs diff --git a/core/src/lib.rs b/core/src/lib.rs index fde6887c5abae..d45cb01910f66 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -354,6 +354,8 @@ pub mod random; pub mod range; pub mod result; pub mod sync; +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub mod unsafe_binder; pub mod fmt; pub mod hash; diff --git a/core/src/unsafe_binder.rs b/core/src/unsafe_binder.rs new file mode 100644 index 0000000000000..98f53e07d9d8d --- /dev/null +++ b/core/src/unsafe_binder.rs @@ -0,0 +1,25 @@ +//! Operators used to turn types into unsafe binders and back. + +/// Unwrap an unsafe binder into its underlying type. +#[allow_internal_unstable(builtin_syntax)] +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub macro unwrap_binder { + ($expr:expr) => { + builtin # unwrap_binder ( $expr ) + }, + ($expr:expr ; $ty:ty) => { + builtin # unwrap_binder ( $expr, $ty ) + }, +} + +/// Wrap a type into an unsafe binder. +#[allow_internal_unstable(builtin_syntax)] +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub macro wrap_binder { + ($expr:expr) => { + builtin # wrap_binder ( $expr ) + }, + ($expr:expr ; $ty:ty) => { + builtin # wrap_binder ( $expr, $ty ) + }, +} diff --git a/std/src/lib.rs b/std/src/lib.rs index 047f5b0c4c584..1cbf51463ea80 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -544,6 +544,8 @@ pub use core::u64; #[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u128; +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub use core::unsafe_binder; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::usize; From 8f732168f8274d9a43ed27a9d0c1bbff432b11b2 Mon Sep 17 00:00:00 2001 From: Alisa Sireneva Date: Thu, 12 Dec 2024 22:48:50 +0300 Subject: [PATCH 127/481] Fix typos in docs on provenance --- core/src/ptr/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index bc4c4e168a369..51ab2054b3beb 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -200,7 +200,7 @@ //! //! But it *is* still sound to: //! -//! * Create a pointer without provenance from just an address (see [`ptr::dangling`]). Such a +//! * Create a pointer without provenance from just an address (see [`without_provenance`]). Such a //! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be //! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be //! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for @@ -314,8 +314,8 @@ //! } //! ``` //! -//! (Yes, if you've been using AtomicUsize for pointers in concurrent datastructures, you should -//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers, +//! (Yes, if you've been using [`AtomicUsize`] for pointers in concurrent datastructures, you should +//! be using [`AtomicPtr`] instead. If that messes up the way you atomically manipulate pointers, //! we would like to know why, and what needs to be done to fix it.) //! //! Situations where a valid pointer *must* be created from just an address, such as baremetal code @@ -381,7 +381,8 @@ //! [`with_addr`]: pointer::with_addr //! [`map_addr`]: pointer::map_addr //! [`addr`]: pointer::addr -//! [`ptr::dangling`]: core::ptr::dangling +//! [`AtomicUsize`]: crate::sync::atomic::AtomicUsize +//! [`AtomicPtr`]: crate::sync::atomic::AtomicPtr //! [`expose_provenance`]: pointer::expose_provenance //! [`with_exposed_provenance`]: with_exposed_provenance //! [Miri]: https://github.com/rust-lang/miri From 394763a629e4dbd509d564bfd1668a7c9e0913d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Fri, 13 Dec 2024 11:50:40 +0100 Subject: [PATCH 128/481] Fix `Path::is_absolute` on Hermit --- std/src/path.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/std/src/path.rs b/std/src/path.rs index 5b277a982eeb8..35e920ab34476 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -2327,7 +2327,9 @@ impl Path { // FIXME: Allow Redox prefixes self.has_root() || has_redox_scheme(self.as_u8_slice()) } else { - self.has_root() && (cfg!(any(unix, target_os = "wasi")) || self.prefix().is_some()) + self.has_root() + && (cfg!(any(unix, target_os = "hermit", target_os = "wasi")) + || self.prefix().is_some()) } } From 307dd9fa4db55fdff18fa6ca54597f3ba96bca2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Fri, 13 Dec 2024 12:17:46 +0100 Subject: [PATCH 129/481] Fix building `std` for Hermit after `c_char` change --- std/src/sys/pal/hermit/fs.rs | 6 +++--- std/src/sys/pal/hermit/mod.rs | 2 +- std/src/sys/pal/hermit/os.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/std/src/sys/pal/hermit/fs.rs b/std/src/sys/pal/hermit/fs.rs index 11862a076082d..88fc40687195d 100644 --- a/std/src/sys/pal/hermit/fs.rs +++ b/std/src/sys/pal/hermit/fs.rs @@ -3,7 +3,7 @@ use super::hermit_abi::{ self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct, }; -use crate::ffi::{CStr, OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString, c_char}; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; @@ -204,7 +204,7 @@ impl Iterator for ReadDir { // the size of dirent64. The file name is always a C string and terminated by `\0`. // Consequently, we are able to ignore the last byte. let name_bytes = - unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const i8).to_bytes() }; + unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const c_char).to_bytes() }; let entry = DirEntry { root: self.inner.root.clone(), ino: dir.d_ino, @@ -445,7 +445,7 @@ impl DirBuilder { pub fn mkdir(&self, path: &Path) -> io::Result<()> { run_path_with_cstr(path, &|path| { - cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode.into()) }).map(|_| ()) + cvt(unsafe { hermit_abi::mkdir(path.as_ptr().cast(), self.mode.into()) }).map(|_| ()) }) } diff --git a/std/src/sys/pal/hermit/mod.rs b/std/src/sys/pal/hermit/mod.rs index f03fca603441d..d833c9d632c6d 100644 --- a/std/src/sys/pal/hermit/mod.rs +++ b/std/src/sys/pal/hermit/mod.rs @@ -85,7 +85,7 @@ pub unsafe extern "C" fn runtime_entry( } // initialize environment - os::init_environment(env as *const *const i8); + os::init_environment(env); let result = unsafe { main(argc as isize, argv) }; diff --git a/std/src/sys/pal/hermit/os.rs b/std/src/sys/pal/hermit/os.rs index f8ea80afa43f1..791cdb1e57e7d 100644 --- a/std/src/sys/pal/hermit/os.rs +++ b/std/src/sys/pal/hermit/os.rs @@ -3,7 +3,7 @@ use core::slice::memchr; use super::hermit_abi; use crate::collections::HashMap; use crate::error::Error as StdError; -use crate::ffi::{CStr, OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString, c_char}; use crate::marker::PhantomData; use crate::os::hermit::ffi::OsStringExt; use crate::path::{self, PathBuf}; @@ -70,7 +70,7 @@ pub fn current_exe() -> io::Result { static ENV: Mutex>> = Mutex::new(None); -pub fn init_environment(env: *const *const i8) { +pub fn init_environment(env: *const *const c_char) { let mut guard = ENV.lock().unwrap(); let map = guard.insert(HashMap::new()); From 4fc7cbcb24fcdb9f34956701b9f77d231fcb3169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Fri, 13 Dec 2024 12:20:40 +0100 Subject: [PATCH 130/481] Update includes in '/library/core/src/error.rs'; --- core/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/error.rs b/core/src/error.rs index 91549f49f9f9d..9dbea57fa1f86 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -2,7 +2,7 @@ #![stable(feature = "error_in_core", since = "1.81.0")] use crate::any::TypeId; -use crate::fmt::{Debug, Display, Formatter, Result}; +use crate::fmt::{self, Debug, Display, Formatter}; /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. @@ -857,7 +857,7 @@ impl<'a> Request<'a> { #[unstable(feature = "error_generic_member_access", issue = "99301")] impl<'a> Debug for Request<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Request").finish_non_exhaustive() } } From 369cb38ba97a9348f88f536aace033a598b25561 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:47:41 -0500 Subject: [PATCH 131/481] feat: clarify how to use `black_box()` Co-authored-by: Ben Kimock --- core/src/hint.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/core/src/hint.rs b/core/src/hint.rs index c59e4414d3726..9c054b99a27ac 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -310,6 +310,8 @@ pub fn spin_loop() { /// behavior in the calling code. This property makes `black_box` useful for writing code in which /// certain optimizations are not desired, such as benchmarks. /// +///
+/// /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The /// extent to which it can block optimisations may vary depending upon the platform and code-gen /// backend used. Programs cannot rely on `black_box` for *correctness*, beyond it behaving as the @@ -317,6 +319,8 @@ pub fn spin_loop() { /// This also means that this function does not offer any guarantees for cryptographic or security /// purposes. /// +///
+/// /// [`std::convert::identity`]: crate::convert::identity /// /// # When is this useful? @@ -357,7 +361,7 @@ pub fn spin_loop() { /// ``` /// use std::hint::black_box; /// -/// // Same `contains` function +/// // Same `contains` function. /// fn contains(haystack: &[&str], needle: &str) -> bool { /// haystack.iter().any(|x| x == &needle) /// } @@ -366,8 +370,13 @@ pub fn spin_loop() { /// let haystack = vec!["abc", "def", "ghi", "jkl", "mno"]; /// let needle = "ghi"; /// for _ in 0..10 { -/// // Adjust our benchmark loop contents -/// black_box(contains(black_box(&haystack), black_box(needle))); +/// // Force the compiler to run `contains`, even though it is a pure function whose +/// // results are unused. +/// black_box(contains( +/// // Prevent the compiler from making assumptions about the input. +/// black_box(&haystack), +/// black_box(needle), +/// )); /// } /// } /// ``` @@ -382,6 +391,83 @@ pub fn spin_loop() { /// /// This makes our benchmark much more realistic to how the function would actually be used, where /// arguments are usually not known at compile time and the result is used in some way. +/// +/// # How to use this +/// +/// In practice, `black_box` serves two purposes: +/// +/// 1. It prevents the compiler from making optimizations related to the value returned by `black_box` +/// 2. It forces the value passed to `black_box` to be calculated, even if the return value of `black_box` is unused +/// +/// ``` +/// use std::hint::black_box; +/// +/// let zero = 0; +/// let five = 5; +/// +/// // The compiler will see this and remove the `* five` call, because it knows that multiplying +/// // any integer by 0 will result in 0. +/// let c = zero * five; +/// +/// // Adding `black_box` here disables the compiler's ability to reason about the first operand in the multiplication. +/// // It is forced to assume that it can be any possible number, so it cannot remove the `* five` +/// // operation. +/// let c = black_box(zero) * five; +/// ``` +/// +/// While most cases will not be as clear-cut as the above example, it still illustrates how +/// `black_box` can be used. When benchmarking a function, you usually want to wrap its inputs in +/// `black_box` so the compiler cannot make optimizations that would be unrealistic in real-life +/// use. +/// +/// ``` +/// use std::hint::black_box; +/// +/// // This is a simple function that increments its input by 1. Note that it is pure, meaning it +/// // has no side-effects. This function has no effect if its result is unused. (An example of a +/// // function *with* side-effects is `println!()`.) +/// fn increment(x: u8) -> u8 { +/// x + 1 +/// } +/// +/// // Here, we call `increment` but discard its result. The compiler, seeing this and knowing that +/// // `increment` is pure, will eliminate this function call entirely. This may not be desired, +/// // though, especially if we're trying to track how much time `increment` takes to execute. +/// let _ = increment(black_box(5)); +/// +/// // Here, we force `increment` to be executed. This is because the compiler treats `black_box` +/// // as if it has side-effects, and thus must compute its input. +/// let _ = black_box(increment(black_box(5))); +/// ``` +/// +/// There may be additional situations where you want to wrap the result of a function in +/// `black_box` to force its execution. This is situational though, and may not have any effect +/// (such as when the function returns a zero-sized type such as [`()` unit][unit]). +/// +/// Note that `black_box` has no effect on how its input is treated, only its output. As such, +/// expressions passed to `black_box` may still be optimized: +/// +/// ``` +/// use std::hint::black_box; +/// +/// // The compiler sees this... +/// let y = black_box(5 * 10); +/// +/// // ...as this. As such, it will likely simplify `5 * 10` to just `50`. +/// let _0 = 5 * 10; +/// let y = black_box(_0); +/// ``` +/// +/// In the above example, the `5 * 10` expression is considered distinct from the `black_box` call, +/// and thus is still optimized by the compiler. You can prevent this by moving the multiplication +/// operation outside of `black_box`: +/// +/// ``` +/// use std::hint::black_box; +/// +/// // No assumptions can be made about either operand, so the multiplication is not optimized out. +/// let y = black_box(5) * black_box(10); +/// ``` #[inline] #[stable(feature = "bench_black_box", since = "1.66.0")] #[rustc_const_unstable(feature = "const_black_box", issue = "none")] From 0b581cf6315144d92b8530e28e6399a73d24e742 Mon Sep 17 00:00:00 2001 From: Andrew Bond Date: Fri, 6 Dec 2024 11:09:11 -0700 Subject: [PATCH 132/481] Add documentation for anonymous pipe module --- std/src/pipe.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 5 deletions(-) diff --git a/std/src/pipe.rs b/std/src/pipe.rs index 891032e94a669..06f3fd9fdffe8 100644 --- a/std/src/pipe.rs +++ b/std/src/pipe.rs @@ -1,20 +1,66 @@ -//! Module for anonymous pipe +//! A cross-platform anonymous pipe. //! -//! ``` -//! #![feature(anonymous_pipe)] +//! This module provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on +//! Windows. +//! +//! # Behavior +//! +//! A pipe is a synchronous, unidirectional data channel between two or more processes, like an +//! interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular: +//! +//! * A read on a [`PipeReader`] blocks until the pipe is non-empty. +//! * A write on a [`PipeWriter`] blocks when the pipe is full. +//! * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] +//! returns EOF. +//! * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. +//! +//! # Capacity +//! +//! Pipe capacity is platform dependent. To quote the Linux [man page]: +//! +//! > Different implementations have different limits for the pipe capacity. Applications should +//! > not rely on a particular capacity: an application should be designed so that a reading process +//! > consumes data as soon as it is available, so that a writing process does not remain blocked. //! +//! # Examples +//! +//! ```no_run +//! #![feature(anonymous_pipe)] //! # #[cfg(miri)] fn main() {} //! # #[cfg(not(miri))] //! # fn main() -> std::io::Result<()> { -//! let (reader, writer) = std::pipe::pipe()?; +//! # use std::process::Command; +//! # use std::io::{Read, Write}; +//! let (ping_rx, mut ping_tx) = std::pipe::pipe()?; +//! let (mut pong_rx, pong_tx) = std::pipe::pipe()?; +//! +//! // Spawn a process that echoes its input. +//! let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; +//! +//! ping_tx.write_all(b"hello")?; +//! // Close to unblock echo_server's reader. +//! drop(ping_tx); +//! +//! let mut buf = String::new(); +//! // Block until echo_server's writer is closed. +//! pong_rx.read_to_string(&mut buf)?; +//! assert_eq!(&buf, "hello"); +//! +//! echo_server.wait()?; //! # Ok(()) //! # } //! ``` - +//! [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html +//! [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe +//! [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html use crate::io; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// Create anonymous pipe that is close-on-exec and blocking. +/// +/// # Examples +/// +/// See the [module-level](crate::pipe) documentation for examples. #[unstable(feature = "anonymous_pipe", issue = "127154")] #[inline] pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { @@ -33,6 +79,58 @@ pub struct PipeWriter(pub(crate) AnonPipe); impl PipeReader { /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::fs; + /// # use std::io::Write; + /// # use std::process::Command; + /// const NUM_SLOT: u8 = 2; + /// const NUM_PROC: u8 = 5; + /// const OUTPUT: &str = "work.txt"; + /// + /// let mut jobs = vec![]; + /// let (reader, mut writer) = std::pipe::pipe()?; + /// + /// // Write NUM_SLOT characters the the pipe. + /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; + /// + /// // Spawn several processes that read a character from the pipe, do some work, then + /// // write back to the pipe. When the pipe is empty, the processes block, so only + /// // NUM_SLOT processes can be working at any given time. + /// for _ in 0..NUM_PROC { + /// jobs.push( + /// Command::new("bash") + /// .args(["-c", + /// &format!( + /// "read -n 1\n\ + /// echo -n 'x' >> '{OUTPUT}'\n\ + /// echo -n '|'", + /// ), + /// ]) + /// .stdin(reader.try_clone()?) + /// .stdout(writer.try_clone()?) + /// .spawn()?, + /// ); + /// } + /// + /// // Wait for all jobs to finish. + /// for mut job in jobs { + /// job.wait()?; + /// } + /// + /// // Check our work and clean up. + /// let xs = fs::read_to_string(OUTPUT)?; + /// fs::remove_file(OUTPUT)?; + /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); + /// # Ok(()) + /// # } + /// ``` #[unstable(feature = "anonymous_pipe", issue = "127154")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) @@ -41,6 +139,38 @@ impl PipeReader { impl PipeWriter { /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::process::Command; + /// # use std::io::Read; + /// let (mut reader, writer) = std::pipe::pipe()?; + /// + /// // Spawn a process that writes to stdout and stderr. + /// let mut peer = Command::new("bash") + /// .args([ + /// "-c", + /// "echo -n foo\n\ + /// echo -n bar >&2" + /// ]) + /// .stdout(writer.try_clone()?) + /// .stderr(writer) + /// .spawn()?; + /// + /// // Read and check the result. + /// let mut msg = String::new(); + /// reader.read_to_string(&mut msg)?; + /// assert_eq!(&msg, "foobar"); + /// + /// peer.wait()?; + /// # Ok(()) + /// # } + /// ``` #[unstable(feature = "anonymous_pipe", issue = "127154")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) From d87869863c7ad9d024b617a987d3754f2cbed707 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Sun, 8 Dec 2024 08:14:05 +0100 Subject: [PATCH 133/481] Correct spelling of CURRENT_RUSTC_VERSION I mixed it up with RUSTC_CURRENT_VERSION unfortunately. Also improve the formatting of the macro invocation slightly. --- core/src/iter/traits/collect.rs | 63 +++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index c3c7288e38990..8ab1c26f95e32 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -493,15 +493,64 @@ impl Extend<()> for () { } macro_rules! spec_tuple_impl { - ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => { - spec_tuple_impl!($trait_name, $default_fn_name, #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in RUSTC_CURRENT_VERSION."] => ($ty_name, $var_name, $extend_ty_name, $cnt),); + ( + ( + $ty_name:ident, $var_name:ident, $extend_ty_name: ident, + $trait_name:ident, $default_fn_name:ident, $cnt:tt + ), + ) => { + spec_tuple_impl!( + $trait_name, + $default_fn_name, + #[doc(fake_variadic)] + #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for \ + 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in \ + CURRENT_RUSTC_VERSION."] + => ($ty_name, $var_name, $extend_ty_name, $cnt), + ); }; - ( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),)*) => { - - spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*); - spec_tuple_impl!($trait_name, $default_fn_name, #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*); + ( + ( + $ty_name:ident, $var_name:ident, $extend_ty_name: ident, + $trait_name:ident, $default_fn_name:ident, $cnt:tt + ), + $( + ( + $ty_names:ident, $var_names:ident, $extend_ty_names:ident, + $trait_names:ident, $default_fn_names:ident, $cnts:tt + ), + )* + ) => { + spec_tuple_impl!( + $( + ( + $ty_names, $var_names, $extend_ty_names, + $trait_names, $default_fn_names, $cnts + ), + )* + ); + spec_tuple_impl!( + $trait_name, + $default_fn_name, + #[doc(hidden)] + => ( + $ty_name, $var_name, $extend_ty_name, $cnt + ), + $( + ( + $ty_names, $var_names, $extend_ty_names, $cnts + ), + )* + ); }; - ($trait_name:ident, $default_fn_name:ident, #[$meta:meta] $(#[$doctext:meta])? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => { + ( + $trait_name:ident, $default_fn_name:ident, #[$meta:meta] + $(#[$doctext:meta])? => $( + ( + $ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt + ), + )* + ) => { #[$meta] $(#[$doctext])? #[stable(feature = "extend_for_tuple", since = "1.56.0")] From e7961b47f4119710bf7e5e6b09e47efc88dc65ce Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 31 Dec 2023 18:35:49 +0000 Subject: [PATCH 134/481] Remove support for specializing ToString outside the standard library This is the only trait specializable outside of the standard library. Before stabilizing specialization we will probably want to remove support for this. It was originally made specializable to allow a more efficient ToString in libproc_macro back when this way the only way to get any data out of a TokenStream. We now support getting individual tokens, so proc macros no longer need to call it as often. --- alloc/src/string.rs | 69 ++++++++++++++--------------- proc_macro/src/bridge/symbol.rs | 6 --- proc_macro/src/lib.rs | 77 +++++---------------------------- 3 files changed, 43 insertions(+), 109 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index c5378d78d591b..23d060d2158cd 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -2675,12 +2675,25 @@ pub trait ToString { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl ToString for T { + #[inline] + fn to_string(&self) -> String { + ::spec_to_string(self) + } +} + +#[cfg(not(no_global_oom_handling))] +trait SpecToString { + fn spec_to_string(&self) -> String; +} + +#[cfg(not(no_global_oom_handling))] +impl SpecToString for T { // A common guideline is to not inline generic functions. However, // removing `#[inline]` from this method causes non-negligible regressions. // See , the last attempt // to try to remove it. #[inline] - default fn to_string(&self) -> String { + default fn spec_to_string(&self) -> String { let mut buf = String::new(); let mut formatter = core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new()); @@ -2691,42 +2704,34 @@ impl ToString for T { } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[unstable(feature = "ascii_char", issue = "110998")] -impl ToString for core::ascii::Char { +impl SpecToString for core::ascii::Char { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { self.as_str().to_owned() } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "char_to_string_specialization", since = "1.46.0")] -impl ToString for char { +impl SpecToString for char { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { String::from(self.encode_utf8(&mut [0; 4])) } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "bool_to_string_specialization", since = "1.68.0")] -impl ToString for bool { +impl SpecToString for bool { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { String::from(if *self { "true" } else { "false" }) } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "u8_to_string_specialization", since = "1.54.0")] -impl ToString for u8 { +impl SpecToString for u8 { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { let mut buf = String::with_capacity(3); let mut n = *self; if n >= 10 { @@ -2742,12 +2747,10 @@ impl ToString for u8 { } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "i8_to_string_specialization", since = "1.54.0")] -impl ToString for i8 { +impl SpecToString for i8 { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { let mut buf = String::with_capacity(4); if self.is_negative() { buf.push('-'); @@ -2788,11 +2791,9 @@ macro_rules! to_string_expr_wrap_in_deref { macro_rules! to_string_str { {$($($x:ident)*),+} => { $( - #[doc(hidden)] - #[stable(feature = "str_to_string_specialization", since = "1.9.0")] - impl ToString for to_string_str_wrap_in_ref!($($x)*) { + impl SpecToString for to_string_str_wrap_in_ref!($($x)*) { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { String::from(to_string_expr_wrap_in_deref!(self ; $($x)*)) } } @@ -2816,32 +2817,26 @@ to_string_str! { x, } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")] -impl ToString for Cow<'_, str> { +impl SpecToString for Cow<'_, str> { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { self[..].to_owned() } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "string_to_string_specialization", since = "1.17.0")] -impl ToString for String { +impl SpecToString for String { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { self.to_owned() } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "fmt_arguments_to_string_specialization", since = "1.71.0")] -impl ToString for fmt::Arguments<'_> { +impl SpecToString for fmt::Arguments<'_> { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { crate::fmt::format(*self) } } diff --git a/proc_macro/src/bridge/symbol.rs b/proc_macro/src/bridge/symbol.rs index edad6e7ac393f..6a1cecd69fb5f 100644 --- a/proc_macro/src/bridge/symbol.rs +++ b/proc_macro/src/bridge/symbol.rs @@ -91,12 +91,6 @@ impl fmt::Debug for Symbol { } } -impl ToString for Symbol { - fn to_string(&self) -> String { - self.with(|s| s.to_owned()) - } -} - impl fmt::Display for Symbol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.with(|s| fmt::Display::fmt(s, f)) diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index 4aa47ce4e4f51..26a09f0daca02 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -19,9 +19,6 @@ )] #![doc(rust_logo)] #![feature(rustdoc_internals)] -// This library is copied into rust-analyzer to allow loading rustc compiled proc macros. -// Please avoid unstable features where possible to minimize the amount of changes necessary -// to make it compile with rust-analyzer on stable. #![feature(staged_api)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] @@ -30,7 +27,6 @@ #![feature(panic_can_unwind)] #![feature(restricted_std)] #![feature(rustc_attrs)] -#![feature(min_specialization)] #![feature(extend_one)] #![recursion_limit = "256"] #![allow(internal_features)] @@ -185,16 +181,6 @@ impl FromStr for TokenStream { } } -// N.B., the bridge only provides `to_string`, implement `fmt::Display` -// based on it (the reverse of the usual relationship between the two). -#[doc(hidden)] -#[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl ToString for TokenStream { - fn to_string(&self) -> String { - self.0.as_ref().map(|t| t.to_string()).unwrap_or_default() - } -} - /// Prints the token stream as a string that is supposed to be losslessly convertible back /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. @@ -210,7 +196,10 @@ impl ToString for TokenStream { impl fmt::Display for TokenStream { #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + match &self.0 { + Some(ts) => write!(f, "{}", ts.to_string()), + None => Ok(()), + } } } @@ -756,21 +745,6 @@ impl From for TokenTree { } } -// N.B., the bridge only provides `to_string`, implement `fmt::Display` -// based on it (the reverse of the usual relationship between the two). -#[doc(hidden)] -#[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl ToString for TokenTree { - fn to_string(&self) -> String { - match *self { - TokenTree::Group(ref t) => t.to_string(), - TokenTree::Ident(ref t) => t.to_string(), - TokenTree::Punct(ref t) => t.to_string(), - TokenTree::Literal(ref t) => t.to_string(), - } - } -} - /// Prints the token tree as a string that is supposed to be losslessly convertible back /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. @@ -786,7 +760,12 @@ impl ToString for TokenTree { impl fmt::Display for TokenTree { #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + match self { + TokenTree::Group(t) => write!(f, "{t}"), + TokenTree::Ident(t) => write!(f, "{t}"), + TokenTree::Punct(t) => write!(f, "{t}"), + TokenTree::Literal(t) => write!(f, "{t}"), + } } } @@ -912,16 +891,6 @@ impl Group { } } -// N.B., the bridge only provides `to_string`, implement `fmt::Display` -// based on it (the reverse of the usual relationship between the two). -#[doc(hidden)] -#[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl ToString for Group { - fn to_string(&self) -> String { - TokenStream::from(TokenTree::from(self.clone())).to_string() - } -} - /// Prints the group as a string that should be losslessly convertible back /// into the same group (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters. @@ -929,7 +898,7 @@ impl ToString for Group { impl fmt::Display for Group { #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + write!(f, "{}", TokenStream::from(TokenTree::from(self.clone()))) } } @@ -1035,14 +1004,6 @@ impl Punct { } } -#[doc(hidden)] -#[stable(feature = "proc_macro_lib2", since = "1.29.0")] -impl ToString for Punct { - fn to_string(&self) -> String { - self.as_char().to_string() - } -} - /// Prints the punctuation character as a string that should be losslessly convertible /// back into the same character. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] @@ -1138,14 +1099,6 @@ impl Ident { } } -#[doc(hidden)] -#[stable(feature = "proc_macro_lib2", since = "1.29.0")] -impl ToString for Ident { - fn to_string(&self) -> String { - self.0.sym.with(|sym| if self.0.is_raw { ["r#", sym].concat() } else { sym.to_owned() }) - } -} - /// Prints the identifier as a string that should be losslessly convertible back /// into the same identifier. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] @@ -1520,14 +1473,6 @@ impl FromStr for Literal { } } -#[doc(hidden)] -#[stable(feature = "proc_macro_lib2", since = "1.29.0")] -impl ToString for Literal { - fn to_string(&self) -> String { - self.with_stringify_parts(|parts| parts.concat()) - } -} - /// Prints the literal as a string that should be losslessly convertible /// back into the same literal (except for possible rounding for floating point literals). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] From 70b85a3461b25b99257b1f55ee955917f149fae4 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 18 Nov 2024 19:52:58 -0600 Subject: [PATCH 135/481] UniqueRc: Add more trait impls. * Support the same formatting as Rc * Add explicit !Send and !Sync impls, to mirror Rc * DispatchFromDyn * borrowing traits and Unpin --- alloc/src/rc.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 7aa1457b1df54..f2d8419338e98 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -3684,7 +3684,6 @@ fn data_offset_align(align: usize) -> usize { /// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, /// including fallible or async constructors. #[unstable(feature = "unique_rc_arc", issue = "112566")] -#[derive(Debug)] pub struct UniqueRc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -3694,12 +3693,80 @@ pub struct UniqueRc< alloc: A, } +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl !Send for UniqueRc {} + +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl !Sync for UniqueRc {} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl, U: ?Sized, A: Allocator> CoerceUnsized> for UniqueRc { } +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Display for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Debug for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Pointer for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::Borrow for UniqueRc { + fn borrow(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::BorrowMut for UniqueRc { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsRef for UniqueRc { + fn as_ref(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsMut for UniqueRc { + fn as_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Unpin for UniqueRc {} + // Depends on A = Global impl UniqueRc { /// Creates a new `UniqueRc`. From b0ac778b099b8f309be72b6b690a7fc515753816 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 19 Nov 2024 13:50:33 -0600 Subject: [PATCH 136/481] UniqueRc: comparisons and Hash --- alloc/src/rc.rs | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index f2d8419338e98..be558dc80704a 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -3767,6 +3767,179 @@ impl AsMut for UniqueRc { #[unstable(feature = "unique_rc_arc", issue = "112566")] impl Unpin for UniqueRc {} +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialEq for UniqueRc { + /// Equality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five == UniqueRc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&**self, &**other) + } + + /// Inequality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are not equal if their inner values are not equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five != UniqueRc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Self) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialOrd for UniqueRc { + /// Partial comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueRc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &UniqueRc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five < UniqueRc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &UniqueRc) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five <= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &UniqueRc) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five > UniqueRc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &UniqueRc) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five >= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &UniqueRc) -> bool { + **self >= **other + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Ord for UniqueRc { + /// Comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&UniqueRc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &UniqueRc) -> Ordering { + (**self).cmp(&**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Eq for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Hash for UniqueRc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + // Depends on A = Global impl UniqueRc { /// Creates a new `UniqueRc`. From 1eec6cd3c6be78011c3c4206cfd65443316dd974 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 19 Nov 2024 13:50:04 -0600 Subject: [PATCH 137/481] UniqueRc: PinCoerceUnsized and DerefPure --- alloc/src/rc.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index be558dc80704a..bb27fe3c62dcd 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -2232,12 +2232,20 @@ impl Deref for Rc { #[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] unsafe impl PinCoerceUnsized for Rc {} +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UniqueRc {} + #[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] unsafe impl PinCoerceUnsized for Weak {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Rc {} +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for UniqueRc {} + #[unstable(feature = "legacy_receiver_trait", issue = "none")] impl LegacyReceiver for Rc {} @@ -4031,9 +4039,6 @@ impl Deref for UniqueRc { } } -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for UniqueRc {} - #[unstable(feature = "unique_rc_arc", issue = "112566")] impl DerefMut for UniqueRc { fn deref_mut(&mut self) -> &mut T { From 4cd84db6dea4c1bb1b22274bea30ae137587f119 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 19 Nov 2024 13:38:49 -0600 Subject: [PATCH 138/481] UniqueRc: platform-specific AsFd/Handle/etc impls to mirror Rc --- std/src/lib.rs | 1 + std/src/os/fd/owned.rs | 8 ++++++++ std/src/os/fd/raw.rs | 8 ++++++++ std/src/os/windows/io/handle.rs | 8 ++++++++ std/src/os/windows/io/socket.rs | 8 ++++++++ 5 files changed, 33 insertions(+) diff --git a/std/src/lib.rs b/std/src/lib.rs index 1cbf51463ea80..2b97f73f79aa9 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -373,6 +373,7 @@ #![feature(thin_box)] #![feature(try_reserve_kind)] #![feature(try_with_capacity)] +#![feature(unique_rc_arc)] #![feature(vec_into_raw_parts)] // tidy-alphabetical-end // diff --git a/std/src/os/fd/owned.rs b/std/src/os/fd/owned.rs index 388b8a88a1a48..abb13b75f5087 100644 --- a/std/src/os/fd/owned.rs +++ b/std/src/os/fd/owned.rs @@ -428,6 +428,14 @@ impl AsFd for crate::rc::Rc { } } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsFd for crate::rc::UniqueRc { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + (**self).as_fd() + } +} + #[stable(feature = "asfd_ptrs", since = "1.64.0")] impl AsFd for Box { #[inline] diff --git a/std/src/os/fd/raw.rs b/std/src/os/fd/raw.rs index 0d99d5492a268..22f5528248a32 100644 --- a/std/src/os/fd/raw.rs +++ b/std/src/os/fd/raw.rs @@ -266,6 +266,14 @@ impl AsRawFd for crate::rc::Rc { } } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsRawFd for crate::rc::UniqueRc { + #[inline] + fn as_raw_fd(&self) -> RawFd { + (**self).as_raw_fd() + } +} + #[stable(feature = "asrawfd_ptrs", since = "1.63.0")] impl AsRawFd for Box { #[inline] diff --git a/std/src/os/windows/io/handle.rs b/std/src/os/windows/io/handle.rs index a4fa94e2b96a4..76f5f549dd244 100644 --- a/std/src/os/windows/io/handle.rs +++ b/std/src/os/windows/io/handle.rs @@ -485,6 +485,14 @@ impl AsHandle for crate::rc::Rc { } } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsHandle for crate::rc::UniqueRc { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + (**self).as_handle() + } +} + #[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsHandle for Box { #[inline] diff --git a/std/src/os/windows/io/socket.rs b/std/src/os/windows/io/socket.rs index 272641ea6c7a8..c6d7bad944093 100644 --- a/std/src/os/windows/io/socket.rs +++ b/std/src/os/windows/io/socket.rs @@ -279,6 +279,14 @@ impl AsSocket for crate::rc::Rc { } } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsSocket for crate::rc::UniqueRc { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + (**self).as_socket() + } +} + #[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsSocket for Box { #[inline] From 680064765ce6dadb20456101b1c40417c77e46cc Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 14 Sep 2024 18:46:06 +0100 Subject: [PATCH 139/481] std::net: Solaris supports `SOCK_CLOEXEC` as well since 11.4. --- std/src/sys/pal/unix/net.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/sys/pal/unix/net.rs b/std/src/sys/pal/unix/net.rs index d140607869c14..d73b9fd5eb882 100644 --- a/std/src/sys/pal/unix/net.rs +++ b/std/src/sys/pal/unix/net.rs @@ -81,6 +81,7 @@ impl Socket { target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_os = "solaris", ))] { // On platforms that support it we pass the SOCK_CLOEXEC // flag to atomically create the socket and set it as From 0299a19bd56ad855fc43d8bb3f7f0c2cb3f12c10 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sat, 30 Nov 2024 19:33:06 +0800 Subject: [PATCH 140/481] Add value accessor methods to `Mutex` and `RwLock` --- std/src/sync/mutex.rs | 110 +++++++++++++++++++++-- std/src/sync/mutex/tests.rs | 161 ++++++++++++++++++++++++++++----- std/src/sync/poison.rs | 35 ++++---- std/src/sync/rwlock.rs | 128 +++++++++++++++++++++++--- std/src/sync/rwlock/tests.rs | 169 +++++++++++++++++++++++++++++------ 5 files changed, 517 insertions(+), 86 deletions(-) diff --git a/std/src/sync/mutex.rs b/std/src/sync/mutex.rs index fe2aca031a248..e28c2090afed7 100644 --- a/std/src/sync/mutex.rs +++ b/std/src/sync/mutex.rs @@ -4,10 +4,10 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; -use crate::mem::ManuallyDrop; +use crate::mem::{self, ManuallyDrop}; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; -use crate::sync::{LockResult, TryLockError, TryLockResult, poison}; +use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison}; use crate::sys::sync as sys; /// A mutual exclusion primitive useful for protecting shared data @@ -273,6 +273,100 @@ impl Mutex { pub const fn new(t: T) -> Mutex { Mutex { inner: sys::Mutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) } } + + /// Returns the contained value by cloning it. + /// + /// # Errors + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error instead. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::Mutex; + /// + /// let mut mutex = Mutex::new(7); + /// + /// assert_eq!(mutex.get_cloned().unwrap(), 7); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + pub fn get_cloned(&self) -> Result> + where + T: Clone, + { + match self.lock() { + Ok(guard) => Ok((*guard).clone()), + Err(_) => Err(PoisonError::new(())), + } + } + + /// Sets the contained value. + /// + /// # Errors + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error containing the provided `value` instead. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::Mutex; + /// + /// let mut mutex = Mutex::new(7); + /// + /// assert_eq!(mutex.get_cloned().unwrap(), 7); + /// mutex.set(11).unwrap(); + /// assert_eq!(mutex.get_cloned().unwrap(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + pub fn set(&self, value: T) -> Result<(), PoisonError> { + if mem::needs_drop::() { + // If the contained value has non-trivial destructor, we + // call that destructor after the lock being released. + self.replace(value).map(drop) + } else { + match self.lock() { + Ok(mut guard) => { + *guard = value; + + Ok(()) + } + Err(_) => Err(PoisonError::new(value)), + } + } + } + + /// Replaces the contained value with `value`, and returns the old contained value. + /// + /// # Errors + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error containing the provided `value` instead. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::Mutex; + /// + /// let mut mutex = Mutex::new(7); + /// + /// assert_eq!(mutex.replace(11).unwrap(), 7); + /// assert_eq!(mutex.get_cloned().unwrap(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + pub fn replace(&self, value: T) -> LockResult { + match self.lock() { + Ok(mut guard) => Ok(mem::replace(&mut *guard, value)), + Err(_) => Err(PoisonError::new(value)), + } + } } impl Mutex { @@ -290,7 +384,8 @@ impl Mutex { /// # Errors /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error once the mutex is acquired. + /// this call will return an error once the mutex is acquired. The acquired + /// mutex guard will be contained in the returned error. /// /// # Panics /// @@ -331,7 +426,8 @@ impl Mutex { /// /// If another user of this mutex panicked while holding the mutex, then /// this call will return the [`Poisoned`] error if the mutex would - /// otherwise be acquired. + /// otherwise be acquired. An acquired lock guard will be contained + /// in the returned error. /// /// If the mutex could not be acquired because it is already locked, then /// this call will return the [`WouldBlock`] error. @@ -438,7 +534,8 @@ impl Mutex { /// # Errors /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error instead. + /// this call will return an error containing the the underlying data + /// instead. /// /// # Examples /// @@ -465,7 +562,8 @@ impl Mutex { /// # Errors /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error instead. + /// this call will return an error containing a mutable reference to the + /// underlying data instead. /// /// # Examples /// diff --git a/std/src/sync/mutex/tests.rs b/std/src/sync/mutex/tests.rs index 19ec096c59334..395c8aada089a 100644 --- a/std/src/sync/mutex/tests.rs +++ b/std/src/sync/mutex/tests.rs @@ -1,13 +1,34 @@ +use crate::fmt::Debug; +use crate::ops::FnMut; +use crate::panic::{self, AssertUnwindSafe}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::mpsc::channel; use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError}; -use crate::thread; +use crate::{hint, mem, thread}; struct Packet(Arc<(Mutex, Condvar)>); #[derive(Eq, PartialEq, Debug)] struct NonCopy(i32); +#[derive(Eq, PartialEq, Debug)] +struct NonCopyNeedsDrop(i32); + +impl Drop for NonCopyNeedsDrop { + fn drop(&mut self) { + hint::black_box(()); + } +} + +#[test] +fn test_needs_drop() { + assert!(!mem::needs_drop::()); + assert!(mem::needs_drop::()); +} + +#[derive(Clone, Eq, PartialEq, Debug)] +struct Cloneable(i32); + #[test] fn smoke() { let m = Mutex::new(()); @@ -57,6 +78,21 @@ fn try_lock() { *m.try_lock().unwrap() = (); } +fn new_poisoned_mutex(value: T) -> Mutex { + let mutex = Mutex::new(value); + + let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| { + let _guard = mutex.lock().unwrap(); + + panic!("test panic to poison mutex"); + })); + + assert!(catch_unwind_result.is_err()); + assert!(mutex.is_poisoned()); + + mutex +} + #[test] fn test_into_inner() { let m = Mutex::new(NonCopy(10)); @@ -83,21 +119,31 @@ fn test_into_inner_drop() { #[test] fn test_into_inner_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }) - .join(); + let m = new_poisoned_mutex(NonCopy(10)); - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { + match m.into_inner() { Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"), } } +#[test] +fn test_get_cloned() { + let m = Mutex::new(Cloneable(10)); + + assert_eq!(m.get_cloned().unwrap(), Cloneable(10)); +} + +#[test] +fn test_get_cloned_poison() { + let m = new_poisoned_mutex(Cloneable(10)); + + match m.get_cloned() { + Err(e) => assert_eq!(e.into_inner(), ()), + Ok(x) => panic!("get of poisoned Mutex is Ok: {x:?}"), + } +} + #[test] fn test_get_mut() { let mut m = Mutex::new(NonCopy(10)); @@ -107,21 +153,90 @@ fn test_get_mut() { #[test] fn test_get_mut_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }) - .join(); + let mut m = new_poisoned_mutex(NonCopy(10)); - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { + match m.get_mut() { Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"), } } +#[test] +fn test_set() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = Mutex::new(init()); + + assert_eq!(*m.lock().unwrap(), init()); + m.set(value()).unwrap(); + assert_eq!(*m.lock().unwrap(), value()); + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + +#[test] +fn test_set_poison() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = new_poisoned_mutex(init()); + + match m.set(value()) { + Err(e) => { + assert_eq!(e.into_inner(), value()); + assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); + } + Ok(x) => panic!("set of poisoned Mutex is Ok: {x:?}"), + } + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + +#[test] +fn test_replace() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = Mutex::new(init()); + + assert_eq!(*m.lock().unwrap(), init()); + assert_eq!(m.replace(value()).unwrap(), init()); + assert_eq!(*m.lock().unwrap(), value()); + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + +#[test] +fn test_replace_poison() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = new_poisoned_mutex(init()); + + match m.replace(value()) { + Err(e) => { + assert_eq!(e.into_inner(), value()); + assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); + } + Ok(x) => panic!("replace of poisoned Mutex is Ok: {x:?}"), + } + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + #[test] fn test_mutex_arc_condvar() { let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); @@ -269,7 +384,7 @@ fn test_mapping_mapped_guard() { fn panic_while_mapping_unlocked_poison() { let lock = Mutex::new(()); - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); let _guard = MutexGuard::map::<(), _>(guard, |_| panic!()); }); @@ -282,7 +397,7 @@ fn panic_while_mapping_unlocked_poison() { Err(TryLockError::Poisoned(_)) => {} } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!()); }); @@ -295,7 +410,7 @@ fn panic_while_mapping_unlocked_poison() { Err(TryLockError::Poisoned(_)) => {} } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); let guard = MutexGuard::map::<(), _>(guard, |val| val); let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!()); @@ -309,7 +424,7 @@ fn panic_while_mapping_unlocked_poison() { Err(TryLockError::Poisoned(_)) => {} } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); let guard = MutexGuard::map::<(), _>(guard, |val| val); let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!()); diff --git a/std/src/sync/poison.rs b/std/src/sync/poison.rs index da66a088e51b1..9eb900c210350 100644 --- a/std/src/sync/poison.rs +++ b/std/src/sync/poison.rs @@ -87,8 +87,8 @@ pub struct Guard { /// /// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock /// is held. The precise semantics for when a lock is poisoned is documented on -/// each lock, but once a lock is poisoned then all future acquisitions will -/// return this error. +/// each lock. For a lock in the poisoned state, unless the state is cleared manually, +/// all future acquisitions will return this error. /// /// # Examples /// @@ -118,7 +118,7 @@ pub struct Guard { /// [`RwLock`]: crate::sync::RwLock #[stable(feature = "rust1", since = "1.0.0")] pub struct PoisonError { - guard: T, + data: T, #[cfg(not(panic = "unwind"))] _never: !, } @@ -147,14 +147,15 @@ pub enum TryLockError { /// A type alias for the result of a lock method which can be poisoned. /// /// The [`Ok`] variant of this result indicates that the primitive was not -/// poisoned, and the `Guard` is contained within. The [`Err`] variant indicates +/// poisoned, and the operation result is contained within. The [`Err`] variant indicates /// that the primitive was poisoned. Note that the [`Err`] variant *also* carries -/// the associated guard, and it can be acquired through the [`into_inner`] -/// method. +/// an associated value assigned by the lock method, and it can be acquired through the +/// [`into_inner`] method. The semantics of the associated value depends on the corresponding +/// lock method. /// /// [`into_inner`]: PoisonError::into_inner #[stable(feature = "rust1", since = "1.0.0")] -pub type LockResult = Result>; +pub type LockResult = Result>; /// A type alias for the result of a nonblocking locking method. /// @@ -195,8 +196,8 @@ impl PoisonError { /// This method may panic if std was built with `panic="abort"`. #[cfg(panic = "unwind")] #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn new(guard: T) -> PoisonError { - PoisonError { guard } + pub fn new(data: T) -> PoisonError { + PoisonError { data } } /// Creates a `PoisonError`. @@ -208,12 +209,12 @@ impl PoisonError { #[cfg(not(panic = "unwind"))] #[stable(feature = "sync_poison", since = "1.2.0")] #[track_caller] - pub fn new(_guard: T) -> PoisonError { + pub fn new(_data: T) -> PoisonError { panic!("PoisonError created in a libstd built with panic=\"abort\"") } /// Consumes this error indicating that a lock is poisoned, returning the - /// underlying guard to allow access regardless. + /// associated data. /// /// # Examples /// @@ -238,21 +239,21 @@ impl PoisonError { /// ``` #[stable(feature = "sync_poison", since = "1.2.0")] pub fn into_inner(self) -> T { - self.guard + self.data } /// Reaches into this error indicating that a lock is poisoned, returning a - /// reference to the underlying guard to allow access regardless. + /// reference to the associated data. #[stable(feature = "sync_poison", since = "1.2.0")] pub fn get_ref(&self) -> &T { - &self.guard + &self.data } /// Reaches into this error indicating that a lock is poisoned, returning a - /// mutable reference to the underlying guard to allow access regardless. + /// mutable reference to the associated data. #[stable(feature = "sync_poison", since = "1.2.0")] pub fn get_mut(&mut self) -> &mut T { - &mut self.guard + &mut self.data } } @@ -322,6 +323,6 @@ where match result { Ok(t) => Ok(f(t)), #[cfg(panic = "unwind")] - Err(PoisonError { guard }) => Err(PoisonError::new(f(guard))), + Err(PoisonError { data }) => Err(PoisonError::new(f(data))), } } diff --git a/std/src/sync/rwlock.rs b/std/src/sync/rwlock.rs index d55d1c80dcae0..1519baf99a8fd 100644 --- a/std/src/sync/rwlock.rs +++ b/std/src/sync/rwlock.rs @@ -4,7 +4,7 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; -use crate::mem::{ManuallyDrop, forget}; +use crate::mem::{self, ManuallyDrop, forget}; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison}; @@ -224,6 +224,103 @@ impl RwLock { pub const fn new(t: T) -> RwLock { RwLock { inner: sys::RwLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) } } + + /// Returns the contained value by cloning it. + /// + /// # Errors + /// + /// This function will return an error if the `RwLock` is poisoned. An + /// `RwLock` is poisoned whenever a writer panics while holding an exclusive + /// lock. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.get_cloned().unwrap(), 7); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + pub fn get_cloned(&self) -> Result> + where + T: Clone, + { + match self.read() { + Ok(guard) => Ok((*guard).clone()), + Err(_) => Err(PoisonError::new(())), + } + } + + /// Sets the contained value. + /// + /// # Errors + /// + /// This function will return an error containing the provided `value` if + /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer + /// panics while holding an exclusive lock. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.get_cloned().unwrap(), 7); + /// lock.set(11).unwrap(); + /// assert_eq!(lock.get_cloned().unwrap(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + pub fn set(&self, value: T) -> Result<(), PoisonError> { + if mem::needs_drop::() { + // If the contained value has non-trivial destructor, we + // call that destructor after the lock being released. + self.replace(value).map(drop) + } else { + match self.write() { + Ok(mut guard) => { + *guard = value; + + Ok(()) + } + Err(_) => Err(PoisonError::new(value)), + } + } + } + + /// Replaces the contained value with `value`, and returns the old contained value. + /// + /// # Errors + /// + /// This function will return an error containing the provided `value` if + /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer + /// panics while holding an exclusive lock. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.replace(11).unwrap(), 7); + /// assert_eq!(lock.get_cloned().unwrap(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + pub fn replace(&self, value: T) -> LockResult { + match self.write() { + Ok(mut guard) => Ok(mem::replace(&mut *guard, value)), + Err(_) => Err(PoisonError::new(value)), + } + } } impl RwLock { @@ -244,7 +341,8 @@ impl RwLock { /// This function will return an error if the `RwLock` is poisoned. An /// `RwLock` is poisoned whenever a writer panics while holding an exclusive /// lock. The failure will occur immediately after the lock has been - /// acquired. + /// acquired. The acquired lock guard will be contained in the returned + /// error. /// /// # Panics /// @@ -292,7 +390,8 @@ impl RwLock { /// This function will return the [`Poisoned`] error if the `RwLock` is /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding /// an exclusive lock. `Poisoned` will only be returned if the lock would - /// have otherwise been acquired. + /// have otherwise been acquired. An acquired lock guard will be contained + /// in the returned error. /// /// This function will return the [`WouldBlock`] error if the `RwLock` could /// not be acquired because it was already locked exclusively. @@ -337,7 +436,8 @@ impl RwLock { /// /// This function will return an error if the `RwLock` is poisoned. An /// `RwLock` is poisoned whenever a writer panics while holding an exclusive - /// lock. An error will be returned when the lock is acquired. + /// lock. An error will be returned when the lock is acquired. The acquired + /// lock guard will be contained in the returned error. /// /// # Panics /// @@ -380,7 +480,8 @@ impl RwLock { /// This function will return the [`Poisoned`] error if the `RwLock` is /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding /// an exclusive lock. `Poisoned` will only be returned if the lock would - /// have otherwise been acquired. + /// have otherwise been acquired. An acquired lock guard will be contained + /// in the returned error. /// /// This function will return the [`WouldBlock`] error if the `RwLock` could /// not be acquired because it was already locked exclusively. @@ -481,10 +582,10 @@ impl RwLock { /// /// # Errors /// - /// This function will return an error if the `RwLock` is poisoned. An - /// `RwLock` is poisoned whenever a writer panics while holding an exclusive - /// lock. An error will only be returned if the lock would have otherwise - /// been acquired. + /// This function will return an error containing the underlying data if + /// the `RwLock` is poisoned. An `RwLock` is poisoned whenever a writer + /// panics while holding an exclusive lock. An error will only be returned + /// if the lock would have otherwise been acquired. /// /// # Examples /// @@ -514,10 +615,11 @@ impl RwLock { /// /// # Errors /// - /// This function will return an error if the `RwLock` is poisoned. An - /// `RwLock` is poisoned whenever a writer panics while holding an exclusive - /// lock. An error will only be returned if the lock would have otherwise - /// been acquired. + /// This function will return an error containing a mutable reference to + /// the underlying data if the `RwLock` is poisoned. An `RwLock` is + /// poisoned whenever a writer panics while holding an exclusive lock. + /// An error will only be returned if the lock would have otherwise been + /// acquired. /// /// # Examples /// diff --git a/std/src/sync/rwlock/tests.rs b/std/src/sync/rwlock/tests.rs index 48d442921f7fc..057c2f1a5d7a7 100644 --- a/std/src/sync/rwlock/tests.rs +++ b/std/src/sync/rwlock/tests.rs @@ -1,16 +1,37 @@ use rand::Rng; +use crate::fmt::Debug; +use crate::ops::FnMut; +use crate::panic::{self, AssertUnwindSafe}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::mpsc::channel; use crate::sync::{ Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError, }; -use crate::thread; +use crate::{hint, mem, thread}; #[derive(Eq, PartialEq, Debug)] struct NonCopy(i32); +#[derive(Eq, PartialEq, Debug)] +struct NonCopyNeedsDrop(i32); + +impl Drop for NonCopyNeedsDrop { + fn drop(&mut self) { + hint::black_box(()); + } +} + +#[test] +fn test_needs_drop() { + assert!(!mem::needs_drop::()); + assert!(mem::needs_drop::()); +} + +#[derive(Clone, Eq, PartialEq, Debug)] +struct Cloneable(i32); + #[test] fn smoke() { let l = RwLock::new(()); @@ -255,6 +276,21 @@ fn test_rwlock_try_write() { drop(mapped_read_guard); } +fn new_poisoned_rwlock(value: T) -> RwLock { + let lock = RwLock::new(value); + + let catch_unwind_result = panic::catch_unwind(AssertUnwindSafe(|| { + let _guard = lock.write().unwrap(); + + panic!("test panic to poison RwLock"); + })); + + assert!(catch_unwind_result.is_err()); + assert!(lock.is_poisoned()); + + lock +} + #[test] fn test_into_inner() { let m = RwLock::new(NonCopy(10)); @@ -281,21 +317,31 @@ fn test_into_inner_drop() { #[test] fn test_into_inner_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }) - .join(); + let m = new_poisoned_rwlock(NonCopy(10)); - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { + match m.into_inner() { Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"), } } +#[test] +fn test_get_cloned() { + let m = RwLock::new(Cloneable(10)); + + assert_eq!(m.get_cloned().unwrap(), Cloneable(10)); +} + +#[test] +fn test_get_cloned_poison() { + let m = new_poisoned_rwlock(Cloneable(10)); + + match m.get_cloned() { + Err(e) => assert_eq!(e.into_inner(), ()), + Ok(x) => panic!("get of poisoned RwLock is Ok: {x:?}"), + } +} + #[test] fn test_get_mut() { let mut m = RwLock::new(NonCopy(10)); @@ -305,21 +351,90 @@ fn test_get_mut() { #[test] fn test_get_mut_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }) - .join(); + let mut m = new_poisoned_rwlock(NonCopy(10)); - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { + match m.get_mut() { Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"), } } +#[test] +fn test_set() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = RwLock::new(init()); + + assert_eq!(*m.read().unwrap(), init()); + m.set(value()).unwrap(); + assert_eq!(*m.read().unwrap(), value()); + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + +#[test] +fn test_set_poison() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = new_poisoned_rwlock(init()); + + match m.set(value()) { + Err(e) => { + assert_eq!(e.into_inner(), value()); + assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); + } + Ok(x) => panic!("set of poisoned RwLock is Ok: {x:?}"), + } + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + +#[test] +fn test_replace() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = RwLock::new(init()); + + assert_eq!(*m.read().unwrap(), init()); + assert_eq!(m.replace(value()).unwrap(), init()); + assert_eq!(*m.read().unwrap(), value()); + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + +#[test] +fn test_replace_poison() { + fn inner(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = new_poisoned_rwlock(init()); + + match m.replace(value()) { + Err(e) => { + assert_eq!(e.into_inner(), value()); + assert_eq!(m.into_inner().unwrap_err().into_inner(), init()); + } + Ok(x) => panic!("replace of poisoned RwLock is Ok: {x:?}"), + } + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); +} + #[test] fn test_read_guard_covariance() { fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {} @@ -370,7 +485,7 @@ fn test_mapping_mapped_guard() { fn panic_while_mapping_read_unlocked_no_poison() { let lock = RwLock::new(()); - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!()); }); @@ -385,7 +500,7 @@ fn panic_while_mapping_read_unlocked_no_poison() { } } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); }); @@ -400,7 +515,7 @@ fn panic_while_mapping_read_unlocked_no_poison() { } } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!()); @@ -416,7 +531,7 @@ fn panic_while_mapping_read_unlocked_no_poison() { } } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); @@ -439,7 +554,7 @@ fn panic_while_mapping_read_unlocked_no_poison() { fn panic_while_mapping_write_unlocked_poison() { let lock = RwLock::new(()); - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!()); }); @@ -452,7 +567,7 @@ fn panic_while_mapping_write_unlocked_poison() { Err(TryLockError::Poisoned(_)) => {} } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); }); @@ -467,7 +582,7 @@ fn panic_while_mapping_write_unlocked_poison() { Err(TryLockError::Poisoned(_)) => {} } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!()); @@ -483,7 +598,7 @@ fn panic_while_mapping_write_unlocked_poison() { Err(TryLockError::Poisoned(_)) => {} } - let _ = crate::panic::catch_unwind(|| { + let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); From 2aa7c2404aee768eb1f925fb6492cca444282c8b Mon Sep 17 00:00:00 2001 From: tkirishima Date: Sat, 14 Dec 2024 14:02:51 +0000 Subject: [PATCH 141/481] Replace i32 by char to add clarity In some `Vec` and `VecDeque` examples where elements are i32, examples can seem a bit confusing at first glance if a parameter of the method is an usize. --- alloc/src/collections/vec_deque/mod.rs | 21 ++++++++++--------- alloc/src/vec/mod.rs | 28 +++++++++++++------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/alloc/src/collections/vec_deque/mod.rs b/alloc/src/collections/vec_deque/mod.rs index cf51a84bb6f24..309d5c65efc31 100644 --- a/alloc/src/collections/vec_deque/mod.rs +++ b/alloc/src/collections/vec_deque/mod.rs @@ -1884,6 +1884,9 @@ impl VecDeque { /// /// vec_deque.insert(1, 'd'); /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); + /// + /// vec_deque.insert(4, 'e'); + /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c', 'e']); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] #[track_caller] @@ -1928,13 +1931,13 @@ impl VecDeque { /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// buf.push_back(1); - /// buf.push_back(2); - /// buf.push_back(3); - /// assert_eq!(buf, [1, 2, 3]); + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// assert_eq!(buf, ['a', 'b', 'c']); /// - /// assert_eq!(buf.remove(1), Some(2)); - /// assert_eq!(buf, [1, 3]); + /// assert_eq!(buf.remove(1), Some('b')); + /// assert_eq!(buf, ['a', 'c']); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("delete", "take")] @@ -1982,10 +1985,10 @@ impl VecDeque { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = [1, 2, 3].into(); + /// let mut buf: VecDeque<_> = ['a', 'b', 'c'].into(); /// let buf2 = buf.split_off(1); - /// assert_eq!(buf, [1]); - /// assert_eq!(buf2, [2, 3]); + /// assert_eq!(buf, ['a']); + /// assert_eq!(buf2, ['b', 'c']); /// ``` #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 457be3ae77fc6..7e7a8ff72c7b1 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -1953,11 +1953,11 @@ impl Vec { /// # Examples /// /// ``` - /// let mut vec = vec![1, 2, 3]; - /// vec.insert(1, 4); - /// assert_eq!(vec, [1, 4, 2, 3]); - /// vec.insert(4, 5); - /// assert_eq!(vec, [1, 4, 2, 3, 5]); + /// let mut vec = vec!['a', 'b', 'c']; + /// vec.insert(1, 'd'); + /// assert_eq!(vec, ['a', 'd', 'b', 'c']); + /// vec.insert(4, 'e'); + /// assert_eq!(vec, ['a', 'd', 'b', 'c', 'e']); /// ``` /// /// # Time complexity @@ -2024,9 +2024,9 @@ impl Vec { /// # Examples /// /// ``` - /// let mut v = vec![1, 2, 3]; - /// assert_eq!(v.remove(1), 2); - /// assert_eq!(v, [1, 3]); + /// let mut v = vec!['a', 'b', 'c']; + /// assert_eq!(v.remove(1), 'b'); + /// assert_eq!(v, ['a', 'c']); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] @@ -2715,10 +2715,10 @@ impl Vec { /// # Examples /// /// ``` - /// let mut vec = vec![1, 2, 3]; + /// let mut vec = vec!['a', 'b', 'c']; /// let vec2 = vec.split_off(1); - /// assert_eq!(vec, [1]); - /// assert_eq!(vec2, [2, 3]); + /// assert_eq!(vec, ['a']); + /// assert_eq!(vec2, ['b', 'c']); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] @@ -2982,9 +2982,9 @@ impl Vec { /// vec.resize(3, "world"); /// assert_eq!(vec, ["hello", "world", "world"]); /// - /// let mut vec = vec![1, 2, 3, 4]; - /// vec.resize(2, 0); - /// assert_eq!(vec, [1, 2]); + /// let mut vec = vec!['a', 'b', 'c', 'd']; + /// vec.resize(2, '_'); + /// assert_eq!(vec, ['a', 'b']); /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize", since = "1.5.0")] From 900d90aaec1f11ebc3e2cdefa94cd234127e7c02 Mon Sep 17 00:00:00 2001 From: tkirishima Date: Sat, 14 Dec 2024 14:03:58 +0000 Subject: [PATCH 142/481] Add clarity to the "greater" of `VecDeque::insert` --- alloc/src/collections/vec_deque/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/src/collections/vec_deque/mod.rs b/alloc/src/collections/vec_deque/mod.rs index 309d5c65efc31..0b6a55297e1ab 100644 --- a/alloc/src/collections/vec_deque/mod.rs +++ b/alloc/src/collections/vec_deque/mod.rs @@ -1869,7 +1869,7 @@ impl VecDeque { /// /// # Panics /// - /// Panics if `index` is greater than deque's length + /// Panics if `index` is strictly greater than deque's length /// /// # Examples /// From fcc93991c918fc342e24f826d942424e0eb9a5a8 Mon Sep 17 00:00:00 2001 From: tkirishima Date: Sat, 14 Dec 2024 14:23:53 +0000 Subject: [PATCH 143/481] Replace i32 by char in `split_at` & `_unchecked` --- core/src/slice/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 97a7338b0bfe8..de00bdf8594f1 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -1883,23 +1883,23 @@ impl [T] { /// # Examples /// /// ``` - /// let v = [1, 2, 3, 4, 5, 6]; + /// let v = ['a', 'b', 'c']; /// /// { /// let (left, right) = v.split_at(0); /// assert_eq!(left, []); - /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, ['a', 'b', 'c']); /// } /// /// { /// let (left, right) = v.split_at(2); - /// assert_eq!(left, [1, 2]); - /// assert_eq!(right, [3, 4, 5, 6]); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); /// } /// /// { - /// let (left, right) = v.split_at(6); - /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// let (left, right) = v.split_at(3); + /// assert_eq!(left, ['a', 'b', 'c']); /// assert_eq!(right, []); /// } /// ``` @@ -1969,23 +1969,23 @@ impl [T] { /// # Examples /// /// ``` - /// let v = [1, 2, 3, 4, 5, 6]; + /// let v = ['a', 'b', 'c']; /// /// unsafe { /// let (left, right) = v.split_at_unchecked(0); /// assert_eq!(left, []); - /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, ['a', 'b', 'c']); /// } /// /// unsafe { /// let (left, right) = v.split_at_unchecked(2); - /// assert_eq!(left, [1, 2]); - /// assert_eq!(right, [3, 4, 5, 6]); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); /// } /// /// unsafe { - /// let (left, right) = v.split_at_unchecked(6); - /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// let (left, right) = v.split_at_unchecked(3); + /// assert_eq!(left, ['a', 'b', 'c']); /// assert_eq!(right, []); /// } /// ``` From 613bcca28d6e1805e37173cbb8ff1d19f3ce7c18 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Dec 2024 11:05:30 -0700 Subject: [PATCH 144/481] rustdoc-search: let From and Into be unboxed --- core/src/convert/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/convert/mod.rs b/core/src/convert/mod.rs index 432e55e8c9a4c..e468f4f0f7e66 100644 --- a/core/src/convert/mod.rs +++ b/core/src/convert/mod.rs @@ -443,6 +443,7 @@ pub trait AsMut { /// [`Vec`]: ../../std/vec/struct.Vec.html #[rustc_diagnostic_item = "Into"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(search_unbox)] pub trait Into: Sized { /// Converts this type into the (usually inferred) input type. #[must_use] @@ -577,6 +578,7 @@ pub trait Into: Sized { all(_Self = "&str", T = "alloc::string::String"), note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] +#[doc(search_unbox)] pub trait From: Sized { /// Converts to this type from the input type. #[rustc_diagnostic_item = "from_fn"] From efd847080e74316c4160cf661ed8c6054866d939 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 12 Dec 2024 14:38:58 +1100 Subject: [PATCH 145/481] Move `doc(keyword = "while")`. All the other unconditional keywords are in the alphabetical order, but `while` is for some reason not. --- std/src/keyword_docs.rs | 116 ++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/std/src/keyword_docs.rs b/std/src/keyword_docs.rs index 4302e24781ee8..c8ff8bfaaefbc 100644 --- a/std/src/keyword_docs.rs +++ b/std/src/keyword_docs.rs @@ -807,64 +807,6 @@ mod in_keyword {} /// [Reference]: ../reference/statements.html#let-statements mod let_keyword {} -#[doc(keyword = "while")] -// -/// Loop while a condition is upheld. -/// -/// A `while` expression is used for predicate loops. The `while` expression runs the conditional -/// expression before running the loop body, then runs the loop body if the conditional -/// expression evaluates to `true`, or exits the loop otherwise. -/// -/// ```rust -/// let mut counter = 0; -/// -/// while counter < 10 { -/// println!("{counter}"); -/// counter += 1; -/// } -/// ``` -/// -/// Like the [`for`] expression, we can use `break` and `continue`. A `while` expression -/// cannot break with a value and always evaluates to `()` unlike [`loop`]. -/// -/// ```rust -/// let mut i = 1; -/// -/// while i < 100 { -/// i *= 2; -/// if i == 64 { -/// break; // Exit when `i` is 64. -/// } -/// } -/// ``` -/// -/// As `if` expressions have their pattern matching variant in `if let`, so too do `while` -/// expressions with `while let`. The `while let` expression matches the pattern against the -/// expression, then runs the loop body if pattern matching succeeds, or exits the loop otherwise. -/// We can use `break` and `continue` in `while let` expressions just like in `while`. -/// -/// ```rust -/// let mut counter = Some(0); -/// -/// while let Some(i) = counter { -/// if i == 10 { -/// counter = None; -/// } else { -/// println!("{i}"); -/// counter = Some (i + 1); -/// } -/// } -/// ``` -/// -/// For more information on `while` and loops in general, see the [reference]. -/// -/// See also, [`for`], [`loop`]. -/// -/// [`for`]: keyword.for.html -/// [`loop`]: keyword.loop.html -/// [reference]: ../reference/expressions/loop-expr.html#predicate-loops -mod while_keyword {} - #[doc(keyword = "loop")] // /// Loop indefinitely. @@ -2343,6 +2285,64 @@ mod use_keyword {} /// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md mod where_keyword {} +#[doc(keyword = "while")] +// +/// Loop while a condition is upheld. +/// +/// A `while` expression is used for predicate loops. The `while` expression runs the conditional +/// expression before running the loop body, then runs the loop body if the conditional +/// expression evaluates to `true`, or exits the loop otherwise. +/// +/// ```rust +/// let mut counter = 0; +/// +/// while counter < 10 { +/// println!("{counter}"); +/// counter += 1; +/// } +/// ``` +/// +/// Like the [`for`] expression, we can use `break` and `continue`. A `while` expression +/// cannot break with a value and always evaluates to `()` unlike [`loop`]. +/// +/// ```rust +/// let mut i = 1; +/// +/// while i < 100 { +/// i *= 2; +/// if i == 64 { +/// break; // Exit when `i` is 64. +/// } +/// } +/// ``` +/// +/// As `if` expressions have their pattern matching variant in `if let`, so too do `while` +/// expressions with `while let`. The `while let` expression matches the pattern against the +/// expression, then runs the loop body if pattern matching succeeds, or exits the loop otherwise. +/// We can use `break` and `continue` in `while let` expressions just like in `while`. +/// +/// ```rust +/// let mut counter = Some(0); +/// +/// while let Some(i) = counter { +/// if i == 10 { +/// counter = None; +/// } else { +/// println!("{i}"); +/// counter = Some (i + 1); +/// } +/// } +/// ``` +/// +/// For more information on `while` and loops in general, see the [reference]. +/// +/// See also, [`for`], [`loop`]. +/// +/// [`for`]: keyword.for.html +/// [`loop`]: keyword.loop.html +/// [reference]: ../reference/expressions/loop-expr.html#predicate-loops +mod while_keyword {} + // 2018 Edition keywords #[doc(alias = "promise")] From bf084687057289d4233efa2217976fe7a5a1148a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 12 Dec 2024 13:57:46 +1100 Subject: [PATCH 146/481] Remove `rustc::existing_doc_keyword` lint. `CheckAttrVisitor::check_doc_keyword` checks `#[doc(keyword = "..")]` attributes to ensure they are on an empty module, and that the value is a non-empty identifier. The `rustc::existing_doc_keyword` lint checks these attributes to ensure that the value is the name of a keyword. It's silly to have two different checking mechanisms for these attributes. This commit does the following. - Changes `check_doc_keyword` to check that the value is the name of a keyword (avoiding the need for the identifier check, which removes a dependency on `rustc_lexer`). - Removes the lint. - Updates tests accordingly. There is one hack: the `SelfTy` FIXME case used to used to be handled by disabling the lint, but now is handled with a special case in `is_doc_keyword`. That hack will go away if/when the FIXME is fixed. Co-Authored-By: Guillaume Gomez --- std/src/keyword_docs.rs | 6 +++--- std/src/lib.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/std/src/keyword_docs.rs b/std/src/keyword_docs.rs index c8ff8bfaaefbc..0c526eafdf36f 100644 --- a/std/src/keyword_docs.rs +++ b/std/src/keyword_docs.rs @@ -1263,10 +1263,10 @@ mod return_keyword {} /// [Reference]: ../reference/items/associated-items.html#methods mod self_keyword {} -// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can remove the -// three next lines and put back: `#[doc(keyword = "Self")]`. +// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can replace +// these two lines with `#[doc(keyword = "Self")]` and update `is_doc_keyword` in +// `CheckAttrVisitor`. #[doc(alias = "Self")] -#[allow(rustc::existing_doc_keyword)] #[doc(keyword = "SelfTy")] // /// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type diff --git a/std/src/lib.rs b/std/src/lib.rs index 2b97f73f79aa9..1c80694ca8f24 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -251,7 +251,6 @@ #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] #![allow(internal_features)] -#![deny(rustc::existing_doc_keyword)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] #![allow(rustdoc::redundant_explicit_links)] From d7c2aa28ec9918a737dfc6c0d67a8c1e9253e1b8 Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 23 Sep 2024 19:40:22 -0400 Subject: [PATCH 147/481] Stabilize #[coverage] attribute --- core/src/cmp.rs | 2 +- core/src/lib.rs | 2 +- core/src/macros/mod.rs | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/cmp.rs b/core/src/cmp.rs index 5a3b9365cd220..66a6578fc7268 100644 --- a/core/src/cmp.rs +++ b/core/src/cmp.rs @@ -348,7 +348,7 @@ pub trait Eq: PartialEq { #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] -#[allow_internal_unstable(coverage_attribute)] +#[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))] pub macro Eq($item:item) { /* compiler built-in */ } diff --git a/core/src/lib.rs b/core/src/lib.rs index d45cb01910f66..922866f95dcf6 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -107,12 +107,12 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(coverage_attribute))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_eval_select)] #![feature(const_typed_swap)] #![feature(core_intrinsics)] -#![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(internal_impls_macro)] #![feature(ip)] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index ab674b58902b5..bff7ad98df3fa 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1673,7 +1673,8 @@ pub(crate) mod builtin { /// /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] + #[allow_internal_unstable(test, rustc_attrs)] + #[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))] #[rustc_builtin_macro] pub macro test($item:item) { /* compiler built-in */ @@ -1686,7 +1687,8 @@ pub(crate) mod builtin { soft, reason = "`bench` is a part of custom test frameworks which are unstable" )] - #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] + #[allow_internal_unstable(test, rustc_attrs)] + #[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))] #[rustc_builtin_macro] pub macro bench($item:item) { /* compiler built-in */ From 09ecff6599da95b15a9e83cbe893eaf23b7e9217 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 20 Nov 2024 22:50:58 +0100 Subject: [PATCH 148/481] Add a range argument to vec.extract_if --- alloc/src/vec/extract_if.rs | 23 +++++++++++++---- alloc/src/vec/mod.rs | 43 ++++++++++++++++++++------------ alloc/tests/vec.rs | 49 ++++++++++++++++++++++++++++--------- 3 files changed, 83 insertions(+), 32 deletions(-) diff --git a/alloc/src/vec/extract_if.rs b/alloc/src/vec/extract_if.rs index 72d51e8904488..f722d89d4005a 100644 --- a/alloc/src/vec/extract_if.rs +++ b/alloc/src/vec/extract_if.rs @@ -1,4 +1,4 @@ -use core::{ptr, slice}; +use core::{ops::{Range, RangeBounds}, ptr, slice}; use super::Vec; use crate::alloc::{Allocator, Global}; @@ -14,7 +14,7 @@ use crate::alloc::{Allocator, Global}; /// #![feature(extract_if)] /// /// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0); +/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] #[derive(Debug)] @@ -30,6 +30,8 @@ pub struct ExtractIf< pub(super) vec: &'a mut Vec, /// The index of the item that will be inspected by the next call to `next`. pub(super) idx: usize, + /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`. + pub(super) end: usize, /// The number of items that have been drained (removed) thus far. pub(super) del: usize, /// The original length of `vec` prior to draining. @@ -38,10 +40,21 @@ pub struct ExtractIf< pub(super) pred: F, } -impl ExtractIf<'_, T, F, A> +impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> where F: FnMut(&mut T) -> bool, { + pub(super) fn new>(vec: &'a mut Vec, pred: F, range: R) -> Self { + let old_len = vec.len(); + let Range { start, end } = slice::range(range, ..old_len); + + // Guard against the vec getting leaked (leak amplification) + unsafe { + vec.set_len(0); + } + ExtractIf { vec, idx: start, del: 0, end, old_len, pred } + } + /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] @@ -59,7 +72,7 @@ where fn next(&mut self) -> Option { unsafe { - while self.idx < self.old_len { + while self.idx < self.end { let i = self.idx; let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); let drained = (self.pred)(&mut v[i]); @@ -82,7 +95,7 @@ where } fn size_hint(&self) -> (usize, Option) { - (0, Some(self.old_len - self.idx)) + (0, Some(self.end - self.idx)) } } diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 7e7a8ff72c7b1..5f4b85b58a98c 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -3615,12 +3615,15 @@ impl Vec { Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } } - /// Creates an iterator which uses a closure to determine if an element should be removed. + /// Creates an iterator which uses a closure to determine if element in the range should be removed. /// /// If the closure returns true, then the element is removed and yielded. /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// + /// Only elements that fall in the provided range are considered for extraction, but any elements + /// after the range will still have to be moved if any element has been extracted. + /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. /// Use [`retain`] with a negated predicate if you do not need the returned iterator. @@ -3630,10 +3633,12 @@ impl Vec { /// Using this method is equivalent to the following code: /// /// ``` + /// # use std::cmp::min; /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; /// # let mut vec = vec![1, 2, 3, 4, 5, 6]; - /// let mut i = 0; - /// while i < vec.len() { + /// # let range = 1..4; + /// let mut i = range.start; + /// while i < min(vec.len(), range.end) { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); /// // your code here @@ -3648,8 +3653,12 @@ impl Vec { /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `extract_if` also lets you mutate every element in the filter closure, - /// regardless of whether you choose to keep or remove it. + /// Note that `extract_if` also lets you mutate the elements passed to the filter closure, + /// regardless of whether you choose to keep or remove them. + /// + /// # Panics + /// + /// If `range` is out of bounds. /// /// # Examples /// @@ -3659,25 +3668,29 @@ impl Vec { /// #![feature(extract_if)] /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// - /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::>(); + /// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::>(); /// let odds = numbers; /// /// assert_eq!(evens, vec![2, 4, 6, 8, 14]); /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]); /// ``` + /// + /// Using the range argument to only process a part of the vector: + /// + /// ``` + /// #![feature(extract_if)] + /// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2]; + /// let ones = items.extract_if(7.., |x| *x == 1).collect::>(); + /// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); + /// assert_eq!(ones.len(), 3); + /// ``` #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] - pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> + pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, + R: RangeBounds, { - let old_len = self.len(); - - // Guard against us getting leaked (leak amplification) - unsafe { - self.set_len(0); - } - - ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter } + ExtractIf::new(self, filter, range) } } diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index 0f27fdff3e182..84679827ba1c0 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1414,7 +1414,7 @@ fn extract_if_empty() { let mut vec: Vec = vec![]; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); assert_eq!(iter.size_hint(), (0, Some(0))); @@ -1431,7 +1431,7 @@ fn extract_if_zst() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1454,7 +1454,7 @@ fn extract_if_false() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| false); + let mut iter = vec.extract_if(.., |_| false); assert_eq!(iter.size_hint(), (0, Some(initial_len))); for _ in iter.by_ref() { count += 1; @@ -1476,7 +1476,7 @@ fn extract_if_true() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1492,6 +1492,31 @@ fn extract_if_true() { assert_eq!(vec, vec![]); } +#[test] +fn extract_if_ranges() { + let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let mut count = 0; + let it = vec.extract_if(1..=3, |_| { + count += 1; + true + }); + assert_eq!(it.collect::>(), vec![1, 2, 3]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); + assert_eq!(count, 3); + + let it = vec.extract_if(1..=3, |_| false); + assert_eq!(it.collect::>(), vec![]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); +} + +#[test] +#[should_panic] +fn extract_if_out_of_bounds() { + let mut vec = vec![0, 1]; + let _ = vec.extract_if(5.., |_| true).for_each(drop); +} + #[test] fn extract_if_complex() { { @@ -1501,7 +1526,7 @@ fn extract_if_complex() { 39, ]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1515,7 +1540,7 @@ fn extract_if_complex() { 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39, ]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1528,7 +1553,7 @@ fn extract_if_complex() { let mut vec = vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1540,7 +1565,7 @@ fn extract_if_complex() { // [xxxxxxxxxx+++++++++++] let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); @@ -1552,7 +1577,7 @@ fn extract_if_complex() { // [+++++++++++xxxxxxxxxx] let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); @@ -1600,7 +1625,7 @@ fn extract_if_consumed_panic() { } c.index < 6 }; - let drain = data.extract_if(filter); + let drain = data.extract_if(.., filter); // NOTE: The ExtractIf is explicitly consumed drain.for_each(drop); @@ -1653,7 +1678,7 @@ fn extract_if_unconsumed_panic() { } c.index < 6 }; - let _drain = data.extract_if(filter); + let _drain = data.extract_if(.., filter); // NOTE: The ExtractIf is dropped without being consumed }); @@ -1669,7 +1694,7 @@ fn extract_if_unconsumed_panic() { #[test] fn extract_if_unconsumed() { let mut vec = vec![1, 2, 3, 4]; - let drain = vec.extract_if(|&mut x| x % 2 != 0); + let drain = vec.extract_if(.., |&mut x| x % 2 != 0); drop(drain); assert_eq!(vec, [1, 2, 3, 4]); } From d613d33fd50f0e8dfef2c09188b61898e8c7c2a2 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 20 Nov 2024 23:13:45 +0100 Subject: [PATCH 149/481] remove bounds from vec and linkedlist ExtractIf since drain-on-drop behavior was removed those bounds no longer serve a purpose --- alloc/src/collections/linked_list.rs | 9 ++------- alloc/src/vec/extract_if.rs | 17 +++++------------ 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/alloc/src/collections/linked_list.rs b/alloc/src/collections/linked_list.rs index ca0ea1ec8b2ba..13168b7a39fe4 100644 --- a/alloc/src/collections/linked_list.rs +++ b/alloc/src/collections/linked_list.rs @@ -1939,9 +1939,7 @@ pub struct ExtractIf< T: 'a, F: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ +> { list: &'a mut LinkedList, it: Option>>, pred: F, @@ -1979,10 +1977,7 @@ where } #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] -impl fmt::Debug for ExtractIf<'_, T, F> -where - F: FnMut(&mut T) -> bool, -{ +impl fmt::Debug for ExtractIf<'_, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExtractIf").field(&self.list).finish() } diff --git a/alloc/src/vec/extract_if.rs b/alloc/src/vec/extract_if.rs index f722d89d4005a..1ea7cbdc7e8a4 100644 --- a/alloc/src/vec/extract_if.rs +++ b/alloc/src/vec/extract_if.rs @@ -1,4 +1,5 @@ -use core::{ops::{Range, RangeBounds}, ptr, slice}; +use core::ops::{Range, RangeBounds}; +use core::{ptr, slice}; use super::Vec; use crate::alloc::{Allocator, Global}; @@ -24,9 +25,7 @@ pub struct ExtractIf< T, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ +> { pub(super) vec: &'a mut Vec, /// The index of the item that will be inspected by the next call to `next`. pub(super) idx: usize, @@ -40,10 +39,7 @@ pub struct ExtractIf< pub(super) pred: F, } -impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { pub(super) fn new>(vec: &'a mut Vec, pred: F, range: R) -> Self { let old_len = vec.len(); let Range { start, end } = slice::range(range, ..old_len); @@ -100,10 +96,7 @@ where } #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] -impl Drop for ExtractIf<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { if self.idx < self.old_len && self.del > 0 { From f76f1a08c68cea380c05ac64edfb630aa3509be1 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 20 Nov 2024 23:53:35 +0100 Subject: [PATCH 150/481] remove obsolete comment and pub(super) visibility --- alloc/src/vec/extract_if.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/alloc/src/vec/extract_if.rs b/alloc/src/vec/extract_if.rs index 1ea7cbdc7e8a4..4db13981596bc 100644 --- a/alloc/src/vec/extract_if.rs +++ b/alloc/src/vec/extract_if.rs @@ -26,17 +26,17 @@ pub struct ExtractIf< F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - pub(super) vec: &'a mut Vec, + vec: &'a mut Vec, /// The index of the item that will be inspected by the next call to `next`. - pub(super) idx: usize, + idx: usize, /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`. - pub(super) end: usize, + end: usize, /// The number of items that have been drained (removed) thus far. - pub(super) del: usize, + del: usize, /// The original length of `vec` prior to draining. - pub(super) old_len: usize, + old_len: usize, /// The filter test predicate. - pub(super) pred: F, + pred: F, } impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { @@ -100,12 +100,6 @@ impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { if self.idx < self.old_len && self.del > 0 { - // This is a pretty messed up state, and there isn't really an - // obviously right thing to do. We don't want to keep trying - // to execute `pred`, so we just backshift all the unprocessed - // elements and tell the vec that they still exist. The backshift - // is required to prevent a double-drop of the last successfully - // drained item prior to a panic in the predicate. let ptr = self.vec.as_mut_ptr(); let src = ptr.add(self.idx); let dst = src.sub(self.del); From f2a605f143dfa8580ba625e175663ccde629a58b Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 17 Dec 2024 14:43:22 +0100 Subject: [PATCH 151/481] Fix typo in uint_macros.rs --- core/src/num/uint_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index c79b2f7ad8ed3..151d879fabeed 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -4,7 +4,7 @@ macro_rules! uint_impl { ActualT = $ActualT:ident, SignedT = $SignedT:ident, - // There are all for use *only* in doc comments. + // These are all for use *only* in doc comments. // As such, they're all passed as literals -- passing them as a string // literal is fine if they need to be multiple code tokens. // In non-comments, use the associated constants rather than these. From 5fba99124e606dd6a327be18baa454ab7c0533a2 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 17 Dec 2024 13:17:39 +0000 Subject: [PATCH 152/481] compiler & tools dependencies: Updating allocator-api2 v0.2.20 -> v0.2.21 Updating annotate-snippets v0.11.4 -> v0.11.5 Updating anyhow v1.0.93 -> v1.0.94 Updating bstr v1.11.0 -> v1.11.1 Updating chrono v0.4.38 -> v0.4.39 Updating clap v4.5.21 -> v4.5.23 Updating clap_builder v4.5.21 -> v4.5.23 Updating clap_complete v4.5.38 -> v4.5.39 Updating clap_lex v0.7.3 -> v0.7.4 Updating colored v2.1.0 -> v2.2.0 Updating console v0.15.8 -> v0.15.10 Updating crossbeam-channel v0.5.13 -> v0.5.14 Updating crossbeam-deque v0.8.5 -> v0.8.6 Updating crossbeam-utils v0.8.20 -> v0.8.21 Updating encode_unicode v0.3.6 -> v1.0.0 Updating fastrand v2.2.0 -> v2.3.0 Updating home v0.5.9 -> v0.5.11 Updating js-sys v0.3.74 -> v0.3.76 Updating libc v0.2.167 -> v0.2.168 Updating miniz_oxide v0.8.0 -> v0.8.1 Updating pest v2.7.14 -> v2.7.15 Updating pest_derive v2.7.14 -> v2.7.15 Updating pest_generator v2.7.14 -> v2.7.15 Updating pest_meta v2.7.14 -> v2.7.15 Updating redox_syscall v0.5.7 -> v0.5.8 Updating rustc-stable-hash v0.1.0 -> v0.1.1 Updating rustix v0.38.41 -> v0.38.42 Updating self_cell v1.0.4 -> v1.1.0 Updating semver v1.0.23 -> v1.0.24 Updating serde v1.0.215 -> v1.0.216 Updating serde_derive v1.0.215 -> v1.0.216 Adding thiserror v2.0.7 Adding thiserror-impl v2.0.7 Updating time v0.3.36 -> v0.3.37 Updating time-macros v0.2.18 -> v0.2.19 Updating tokio v1.41.1 -> v1.42.0 Updating wasm-bindgen v0.2.97 -> v0.2.99 Updating wasm-bindgen-backend v0.2.97 -> v0.2.99 Updating wasm-bindgen-macro v0.2.97 -> v0.2.99 Updating wasm-bindgen-macro-support v0.2.97 -> v0.2.99 Updating wasm-bindgen-shared v0.2.97 -> v0.2.99 Updating wasm-encoder v0.221.0 -> v0.221.2 Updating wasmparser v0.221.0 -> v0.221.2 Updating wast v221.0.0 -> v221.0.2 Updating wat v1.221.0 -> v1.221.2 library dependencies: Updating allocator-api2 v0.2.20 -> v0.2.21 Updating libc v0.2.167 -> v0.2.168 rustbook dependencies: Updating anyhow v1.0.93 -> v1.0.94 Updating bstr v1.11.0 -> v1.11.1 Updating chrono v0.4.38 -> v0.4.39 Updating clap v4.5.21 -> v4.5.23 Updating clap_builder v4.5.21 -> v4.5.23 Updating clap_complete v4.5.38 -> v4.5.39 Updating clap_lex v0.7.3 -> v0.7.4 Updating fastrand v2.2.0 -> v2.3.0 Updating js-sys v0.3.74 -> v0.3.76 Updating libc v0.2.167 -> v0.2.168 Updating miniz_oxide v0.8.0 -> v0.8.1 Updating pest v2.7.14 -> v2.7.15 Updating pest_derive v2.7.14 -> v2.7.15 Updating pest_generator v2.7.14 -> v2.7.15 Updating pest_meta v2.7.14 -> v2.7.15 Updating pulldown-cmark-to-cmark v19.0.0 -> v19.0.1 Updating redox_syscall v0.5.7 -> v0.5.8 Updating rustix v0.38.41 -> v0.38.42 Updating semver v1.0.23 -> v1.0.24 Updating serde v1.0.215 -> v1.0.216 Updating serde_derive v1.0.215 -> v1.0.216 Adding thiserror v2.0.7 Adding thiserror-impl v2.0.7 Updating wasm-bindgen v0.2.97 -> v0.2.99 Updating wasm-bindgen-backend v0.2.97 -> v0.2.99 Updating wasm-bindgen-macro v0.2.97 -> v0.2.99 Updating wasm-bindgen-macro-support v0.2.97 -> v0.2.99 Updating wasm-bindgen-shared v0.2.97 -> v0.2.99 Removing windows-sys v0.52.0 --- Cargo.lock | 8 ++++---- profiler_builtins/Cargo.toml | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03c2356e542a5..fd450c7d3dd8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "cc" @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" dependencies = [ "rustc-std-workspace-core", ] diff --git a/profiler_builtins/Cargo.toml b/profiler_builtins/Cargo.toml index c601a41b433c7..230e8051602e4 100644 --- a/profiler_builtins/Cargo.toml +++ b/profiler_builtins/Cargo.toml @@ -11,4 +11,5 @@ doc = false [dependencies] [build-dependencies] -cc = "1.2" +# Pinned so `cargo update` bumps don't cause breakage +cc = "=1.2.0" From a2d4c6194f26b034bc4cbcc3b23eb6dbfafb12ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jalil=20David=20Salam=C3=A9=20Messina?= Date: Wed, 18 Dec 2024 09:37:45 +0100 Subject: [PATCH 153/481] fix(LazyCell): documentation of get[_mut] was wrong - `LazyCell::get`: said it was returning a **mutable** reference. - `LazyCell::get_mut`: said it was returning a reference (the mutable was missing). --- core/src/cell/lazy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/cell/lazy.rs b/core/src/cell/lazy.rs index 5ac33516684d7..84cbbc71f40ae 100644 --- a/core/src/cell/lazy.rs +++ b/core/src/cell/lazy.rs @@ -219,7 +219,7 @@ impl T> LazyCell { } impl LazyCell { - /// Returns a reference to the value if initialized, or `None` if not. + /// Returns a mutable reference to the value if initialized, or `None` if not. /// /// # Examples /// @@ -245,7 +245,7 @@ impl LazyCell { } } - /// Returns a mutable reference to the value if initialized, or `None` if not. + /// Returns a reference to the value if initialized, or `None` if not. /// /// # Examples /// From 3dff69d78168afe64d98f4e09fb2bd2916522b60 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 17 Dec 2024 14:33:10 -0800 Subject: [PATCH 154/481] Use field init shorthand where possible Field init shorthand allows writing initializers like `tcx: tcx` as `tcx`. The compiler already uses it extensively. Fix the last few places where it isn't yet used. --- alloc/src/rc.rs | 2 +- alloc/src/sync.rs | 2 +- core/src/task/wake.rs | 2 +- std/src/sys/pal/hermit/fs.rs | 2 +- std/src/sys/pal/hermit/thread.rs | 2 +- std/src/sys/pal/hermit/time.rs | 2 +- std/src/sys/pal/sgx/fd.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index bb27fe3c62dcd..b7ec3af9818a0 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -795,7 +795,7 @@ impl Rc { let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); let init_ptr: NonNull> = uninit_ptr.cast(); - let weak = Weak { ptr: init_ptr, alloc: alloc }; + let weak = Weak { ptr: init_ptr, alloc }; // It's important we don't give up ownership of the weak pointer, or // else the memory might be freed by the time `data_fn` returns. If diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 6cf41a3fa4e16..9be0b3e3e8801 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -784,7 +784,7 @@ impl Arc { let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); let init_ptr: NonNull> = uninit_ptr.cast(); - let weak = Weak { ptr: init_ptr, alloc: alloc }; + let weak = Weak { ptr: init_ptr, alloc }; // It's important we don't give up ownership of the weak pointer, or // else the memory might be freed by the time `data_fn` returns. If diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index bfffcc24a46a2..ba429005fab3d 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -322,7 +322,7 @@ impl<'a> ContextBuilder<'a> { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; Self { - waker: waker, + waker, local_waker, ext: ExtData::None(()), _marker: PhantomData, diff --git a/std/src/sys/pal/hermit/fs.rs b/std/src/sys/pal/hermit/fs.rs index 88fc40687195d..783623552bb17 100644 --- a/std/src/sys/pal/hermit/fs.rs +++ b/std/src/sys/pal/hermit/fs.rs @@ -135,7 +135,7 @@ impl FileAttr { S_IFREG => DT_REG, _ => DT_UNKNOWN, }; - FileType { mode: mode } + FileType { mode } } } diff --git a/std/src/sys/pal/hermit/thread.rs b/std/src/sys/pal/hermit/thread.rs index 2a0b8dcb4ed60..4a7afddbec107 100644 --- a/std/src/sys/pal/hermit/thread.rs +++ b/std/src/sys/pal/hermit/thread.rs @@ -43,7 +43,7 @@ impl Thread { } Err(io::const_error!(io::ErrorKind::Uncategorized, "Unable to create thread!")) } else { - Ok(Thread { tid: tid }) + Ok(Thread { tid }) }; extern "C" fn thread_start(main: usize) { diff --git a/std/src/sys/pal/hermit/time.rs b/std/src/sys/pal/hermit/time.rs index e0b6eb76b03af..f76a5f96c8750 100644 --- a/std/src/sys/pal/hermit/time.rs +++ b/std/src/sys/pal/hermit/time.rs @@ -22,7 +22,7 @@ impl Timespec { const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec { assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC); // SAFETY: The assert above checks tv_nsec is within the valid range - Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } } + Timespec { t: timespec { tv_sec, tv_nsec } } } fn sub_timespec(&self, other: &Timespec) -> Result { diff --git a/std/src/sys/pal/sgx/fd.rs b/std/src/sys/pal/sgx/fd.rs index c41b527cff798..3bb3189a1d127 100644 --- a/std/src/sys/pal/sgx/fd.rs +++ b/std/src/sys/pal/sgx/fd.rs @@ -12,7 +12,7 @@ pub struct FileDesc { impl FileDesc { pub fn new(fd: Fd) -> FileDesc { - FileDesc { fd: fd } + FileDesc { fd } } pub fn raw(&self) -> Fd { From d2a2444c70b1c7e36d794fcf4866253db6d7f464 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Wed, 23 Oct 2024 08:09:15 +0200 Subject: [PATCH 155/481] Stabilize `#[diagnostic::do_not_recommend]` This commit seeks to stabilize the `#[diagnostic::do_not_recommend]` attribute. This attribute was first proposed as `#[do_not_recommend`] attribute in RFC 2397 (https://github.com/rust-lang/rfcs/pull/2397). It gives the crate authors the ability to not suggest to the compiler to not show certain traits in it's error messages. With the presence of the `#[diagnostic]` tool attribute namespace it was decided to move the attribute there, as that lowers the amount of guarantees the compiler needs to give about the exact way this influences error messages. It turns the attribute into a hint which can be ignored. In addition to the original proposed functionality this attribute now also hides the marked trait in help messages ("This trait is implemented by: "). The attribute does not accept any argument and can only be placed on trait implementations. If it is placed somewhere else a lint warning is emitted and the attribute is otherwise ignored. If an argument is detected a lint warning is emitted and the argument is ignored. This follows the rules outlined by the diagnostic namespace. This attribute allows crates like diesel to improve their error messages drastically. The most common example here is the following error message: ``` error[E0277]: the trait bound `&str: Expression` is not satisfied --> /home/weiznich/Documents/rust/rust/tests/ui/diagnostic_namespace/do_not_recommend.rs:53:15 | LL | SelectInt.check("bar"); | ^^^^^ the trait `Expression` is not implemented for `&str`, which is required by `&str: AsExpression` | = help: the following other types implement trait `Expression`: Bound SelectInt note: required for `&str` to implement `AsExpression` --> /home/weiznich/Documents/rust/rust/tests/ui/diagnostic_namespace/do_not_recommend.rs:26:13 | LL | impl AsExpression for T | ^^^^^^^^^^^^^^^^ ^ LL | where LL | T: Expression, | ------------------------ unsatisfied trait bound introduced here ``` By applying the new attribute to the wild card trait implementation of `AsExpression` for `T: Expression` the error message becomes: ``` error[E0277]: the trait bound `&str: AsExpression` is not satisfied --> $DIR/as_expression.rs:55:15 | LL | SelectInt.check("bar"); | ^^^^^ the trait `AsExpression` is not implemented for `&str` | = help: the trait `AsExpression` is implemented for `&str` = help: for that trait implementation, expected `Text`, found `Integer` ``` which makes it much easier for users to understand that they are facing a type mismatch. Other explored example usages included * This standard library error message: https://github.com/rust-lang/rust/pull/128008 * That bevy derived example: https://github.com/rust-lang/rust/blob/e1f306899514ea80abc1d1c9f6a57762afb304a3/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs (No more tuple pyramids) Fixes #51992 --- core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 922866f95dcf6..18bd9bb811836 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -108,12 +108,12 @@ // Library features: // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(coverage_attribute))] +#![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_eval_select)] #![feature(const_typed_swap)] #![feature(core_intrinsics)] -#![feature(do_not_recommend)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] From 5b8b54d3d5828e151c6dd52389a644da748050a0 Mon Sep 17 00:00:00 2001 From: leejaehong Date: Thu, 19 Dec 2024 10:37:19 +0900 Subject: [PATCH 156/481] fix typo in ptr/mod.rs Signed-off-by: leejaehong --- core/src/ptr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 51ab2054b3beb..1423e7ea8d10c 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -84,7 +84,7 @@ // ^ we use this term instead of saying that the produced reference must // be valid, as the validity of a reference is easily confused for the // validity of the thing it refers to, and while the two concepts are -// closly related, they are not identical. +// closely related, they are not identical. //! //! These rules apply even if the result is unused! //! (The part about being initialized is not yet fully decided, but until From afd4811a4769abe7b66385b8d73ae011c66e95c0 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Date: Thu, 19 Dec 2024 10:08:29 +0100 Subject: [PATCH 157/481] build: Update libc version --- Cargo.lock | 4 ++-- std/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd450c7d3dd8a..2026cd584ccb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" dependencies = [ "rustc-std-workspace-core", ] diff --git a/std/Cargo.toml b/std/Cargo.toml index ca8b6af056550..f43dcc1630c6a 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -34,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.167", default-features = false, features = [ +libc = { version = "0.2.169", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } From 5a884c863722f2bcb530f7489215dd0b429432e7 Mon Sep 17 00:00:00 2001 From: Jan Ferdinand Sauer Date: Fri, 7 Jun 2024 14:43:52 +0200 Subject: [PATCH 158/481] docs: Mention `spare_capacity_mut()` in `Vec::set_len` --- alloc/src/vec/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 5f4b85b58a98c..55496005f4088 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -1824,7 +1824,10 @@ impl Vec { /// /// # Examples /// - /// This method can be useful for situations in which the vector + /// See [`spare_capacity_mut()`] for an example with safe + /// initialization of capacity elements and use of this method. + /// + /// `set_len()` can be useful for situations in which the vector /// is serving as a buffer for other code, particularly over FFI: /// /// ```no_run @@ -1884,6 +1887,8 @@ impl Vec { /// /// Normally, here, one would use [`clear`] instead to correctly drop /// the contents and thus not leak memory. + /// + /// [`spare_capacity_mut()`]: Vec::spare_capacity_mut #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn set_len(&mut self, new_len: usize) { From 2eda9a9e595b124f638a6ee93d3609052c70067b Mon Sep 17 00:00:00 2001 From: wr7 Date: Sat, 9 Nov 2024 16:49:53 -0600 Subject: [PATCH 159/481] Rename `elem_offset` to `element_offset` --- core/src/slice/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index de00bdf8594f1..c56d7c8851c38 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -4661,7 +4661,7 @@ impl [T] { /// let num = &nums[2]; /// /// assert_eq!(num, &1); - /// assert_eq!(nums.elem_offset(num), Some(2)); + /// assert_eq!(nums.element_offset(num), Some(2)); /// ``` /// Returning `None` with an in-between element: /// ``` @@ -4676,12 +4676,12 @@ impl [T] { /// assert_eq!(ok_elm, &[0, 1]); /// assert_eq!(weird_elm, &[1, 2]); /// - /// assert_eq!(arr.elem_offset(ok_elm), Some(0)); // Points to element 0 - /// assert_eq!(arr.elem_offset(weird_elm), None); // Points between element 0 and 1 + /// assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 + /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 /// ``` #[must_use] #[unstable(feature = "substr_range", issue = "126769")] - pub fn elem_offset(&self, element: &T) -> Option { + pub fn element_offset(&self, element: &T) -> Option { if T::IS_ZST { panic!("elements are zero-sized"); } From d39d7efc7ab0b6296205b33388b1f37feb8a2087 Mon Sep 17 00:00:00 2001 From: wr7 Date: Sat, 9 Nov 2024 16:28:15 -0600 Subject: [PATCH 160/481] Improve documentation of `element_offset` and related methods --- core/src/slice/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index c56d7c8851c38..ab65f9d6d2fcc 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -4641,7 +4641,7 @@ impl [T] { /// Returns the index that an element reference points to. /// - /// Returns `None` if `element` does not point within the slice or if it points between elements. + /// Returns `None` if `element` does not point to the start of an element within the slice. /// /// This method is useful for extending slice iterators like [`slice::split`]. /// @@ -4663,7 +4663,7 @@ impl [T] { /// assert_eq!(num, &1); /// assert_eq!(nums.element_offset(num), Some(2)); /// ``` - /// Returning `None` with an in-between element: + /// Returning `None` with an unaligned element: /// ``` /// #![feature(substr_range)] /// @@ -4702,7 +4702,8 @@ impl [T] { /// Returns the range of indices that a subslice points to. /// - /// Returns `None` if `subslice` does not point within the slice or if it points between elements. + /// Returns `None` if `subslice` does not point within the slice or if it is not aligned with the + /// elements in the slice. /// /// This method **does not compare elements**. Instead, this method finds the location in the slice that /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use From bdc2ca0275cd99daeae454c79c1b772840ca2692 Mon Sep 17 00:00:00 2001 From: hltj Date: Fri, 20 Dec 2024 11:47:02 +0800 Subject: [PATCH 161/481] fix typos in the example code in the doc comments of `Ipv4Addr::from_bits()`, `Ipv6Addr::from_bits()` & `Ipv6Addr::to_bits()` --- core/src/net/ip_addr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/net/ip_addr.rs b/core/src/net/ip_addr.rs index 82f11f0eaac3c..7dd5c21401264 100644 --- a/core/src/net/ip_addr.rs +++ b/core/src/net/ip_addr.rs @@ -527,7 +527,7 @@ impl Ipv4Addr { /// ``` /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::from(0x12345678); + /// let addr = Ipv4Addr::from_bits(0x12345678); /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); /// ``` #[rustc_const_stable(feature = "ip_bits", since = "1.80.0")] @@ -1294,7 +1294,7 @@ impl Ipv6Addr { /// 0x1020, 0x3040, 0x5060, 0x7080, /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, /// ); - /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); + /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, addr.to_bits()); /// ``` /// /// ``` @@ -1330,7 +1330,7 @@ impl Ipv6Addr { /// ``` /// use std::net::Ipv6Addr; /// - /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); + /// let addr = Ipv6Addr::from_bits(0x102030405060708090A0B0C0D0E0F00D_u128); /// assert_eq!( /// Ipv6Addr::new( /// 0x1020, 0x3040, 0x5060, 0x7080, From 8773984493ad1d52d7654120928c30a682df7d30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Dec 2024 15:03:51 +0100 Subject: [PATCH 162/481] mri: add track_caller to thread spawning methods for better backtraces --- std/src/sys/pal/unix/thread.rs | 1 + std/src/sys/pal/windows/thread.rs | 1 + std/src/thread/mod.rs | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/std/src/sys/pal/unix/thread.rs b/std/src/sys/pal/unix/thread.rs index 131a6e81b1e92..e360ba0f6d7d8 100644 --- a/std/src/sys/pal/unix/thread.rs +++ b/std/src/sys/pal/unix/thread.rs @@ -45,6 +45,7 @@ unsafe impl Sync for Thread {} impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = Box::into_raw(Box::new(p)); let mut native: libc::pthread_t = mem::zeroed(); diff --git a/std/src/sys/pal/windows/thread.rs b/std/src/sys/pal/windows/thread.rs index 2c8ce42f4148b..45e52cf4d047f 100644 --- a/std/src/sys/pal/windows/thread.rs +++ b/std/src/sys/pal/windows/thread.rs @@ -19,6 +19,7 @@ pub struct Thread { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = Box::into_raw(Box::new(p)); diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index cfbf6548a380c..85ee369ca2b66 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -391,6 +391,7 @@ impl Builder { /// handler.join().unwrap(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn spawn(self, f: F) -> io::Result> where F: FnOnce() -> T, @@ -458,6 +459,7 @@ impl Builder { /// /// [`io::Result`]: crate::io::Result #[stable(feature = "thread_spawn_unchecked", since = "1.82.0")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn spawn_unchecked(self, f: F) -> io::Result> where F: FnOnce() -> T, @@ -467,6 +469,7 @@ impl Builder { Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?)) } + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn spawn_unchecked_<'scope, F, T>( self, f: F, @@ -721,6 +724,7 @@ impl Builder { /// [`join`]: JoinHandle::join /// [`Err`]: crate::result::Result::Err #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn spawn(f: F) -> JoinHandle where F: FnOnce() -> T, From 5b880aa2bf86673eae48bccda46982b90e223cfa Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 20 Dec 2024 18:20:40 +0100 Subject: [PATCH 163/481] remove reference to dangling from slice::Iter This aligns the comment with reality and with IterMut. Also dangling does not seem to take any arguments. --- core/src/slice/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index c5746157d01b2..a27baf9db224c 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -68,7 +68,7 @@ pub struct Iter<'a, T: 'a> { ptr: NonNull, /// For non-ZSTs, the non-null pointer to the past-the-end element. /// - /// For ZSTs, this is `ptr::dangling(len)`. + /// For ZSTs, this is `ptr::without_provenance_mut(len)`. end_or_len: *const T, _marker: PhantomData<&'a T>, } From 946746e35a0ed67eb954546e9cdc8fb08e125b6b Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 20 Dec 2024 16:57:14 +0100 Subject: [PATCH 164/481] split up `#[rustc_deny_explicit_impl]` attribute This commit splits the `#[rustc_deny_explicit_impl(implement_via_object = ...)]` attribute into two attributes `#[rustc_deny_explicit_impl]` and `#[rustc_do_not_implement_via_object]`. This allows us to have special traits that can have user-defined impls but do not have the automatic trait impl for trait objects (`impl Trait for dyn Trait`). --- core/src/future/async_drop.rs | 4 +++- core/src/marker.rs | 24 ++++++++++++++++++------ core/src/mem/transmutability.rs | 4 +++- core/src/ptr/metadata.rs | 4 +++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/core/src/future/async_drop.rs b/core/src/future/async_drop.rs index 7de5fe67cd096..ea6d3b800e64d 100644 --- a/core/src/future/async_drop.rs +++ b/core/src/future/async_drop.rs @@ -133,7 +133,9 @@ pub trait AsyncDrop { } #[lang = "async_destruct"] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] trait AsyncDestruct { type AsyncDestructor: Future; } diff --git a/core/src/marker.rs b/core/src/marker.rs index 1620b949590d0..31b27b7ef2641 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -141,7 +141,9 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] #[rustc_coinductive] pub trait Sized { // Empty. @@ -181,7 +183,9 @@ pub trait Sized { /// [^1]: Formerly known as *object safe*. #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Unsize { // Empty. } @@ -815,7 +819,9 @@ impl StructuralPartialEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -956,7 +962,9 @@ marker_impls! { #[unstable(feature = "const_destruct", issue = "133214")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] #[cfg_attr(not(bootstrap), const_trait)] pub trait Destruct {} @@ -967,7 +975,9 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Tuple {} /// A marker for pointer-like types. @@ -1068,7 +1078,9 @@ marker_impls! { reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait FnPtr: Copy + Clone { /// Returns the address of the function pointer. #[lang = "fn_ptr_addr"] diff --git a/core/src/mem/transmutability.rs b/core/src/mem/transmutability.rs index 7fa3c33439170..9cf587650d949 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -84,7 +84,9 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// `usize` is stable, but not portable. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] #[rustc_coinductive] pub unsafe trait TransmuteFrom where diff --git a/core/src/ptr/metadata.rs b/core/src/ptr/metadata.rs index ae9810e558aa1..b1d5e1fa3a059 100644 --- a/core/src/ptr/metadata.rs +++ b/core/src/ptr/metadata.rs @@ -53,7 +53,9 @@ use crate::ptr::NonNull; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[rustc_deny_explicit_impl(implement_via_object = false)] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] From 7c9bb98c3c3642d35423b8e4949fd4de49a58612 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 20 Dec 2024 17:35:29 +0100 Subject: [PATCH 165/481] unimplement `PointerLike` for trait objects --- core/src/marker.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/marker.rs b/core/src/marker.rs index 31b27b7ef2641..bdfa162919f21 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -990,6 +990,7 @@ pub trait Tuple {} message = "`{Self}` needs to have the same ABI as a pointer", label = "`{Self}` needs to be a pointer-like type" )] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait PointerLike {} #[cfg(not(bootstrap))] From 8f1f7883501ed6a9c0125d73175a906f7fc9f376 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 20 Dec 2024 17:37:34 +0100 Subject: [PATCH 166/481] fix `PointerLike` docs --- core/src/marker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index bdfa162919f21..3d79706f8ecf9 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -982,8 +982,8 @@ pub trait Tuple {} /// A marker for pointer-like types. /// -/// All types that have the same size and alignment as a `usize` or -/// `*const ()` automatically implement this trait. +/// This trait can only be implemented for types that have the same size and alignment +/// as a `usize` or `*const ()`. #[unstable(feature = "pointer_like_trait", issue = "none")] #[lang = "pointer_like"] #[diagnostic::on_unimplemented( From 1978a734ab125373ce3a647ccdecd22e63662179 Mon Sep 17 00:00:00 2001 From: Michael van Straten Date: Sun, 7 Apr 2024 21:08:37 +0200 Subject: [PATCH 167/481] Abstract `ProcThreadAttributeList` into its own struct --- std/src/os/windows/process.rs | 328 ++++++++++++++++++++++++----- std/src/process/tests.rs | 14 +- std/src/sys/pal/windows/process.rs | 103 ++------- 3 files changed, 294 insertions(+), 151 deletions(-) diff --git a/std/src/os/windows/process.rs b/std/src/os/windows/process.rs index c2830d2eb61d1..0277b79b8b69c 100644 --- a/std/src/os/windows/process.rs +++ b/std/src/os/windows/process.rs @@ -4,13 +4,14 @@ #![stable(feature = "process_extensions", since = "1.2.0")] -use crate::ffi::OsStr; +use crate::ffi::{OsStr, c_void}; +use crate::mem::MaybeUninit; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, }; use crate::sealed::Sealed; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -use crate::{process, sys}; +use crate::{io, marker, process, ptr, sys}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -295,41 +296,25 @@ pub trait CommandExt: Sealed { #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")] fn async_pipes(&mut self, always_async: bool) -> &mut process::Command; - /// Set a raw attribute on the command, providing extended configuration options for Windows - /// processes. + /// Executes the command as a child process with the given + /// [`ProcThreadAttributeList`], returning a handle to it. /// - /// This method allows you to specify custom attributes for a child process on Windows systems - /// using raw attribute values. Raw attributes provide extended configurability for process - /// creation, but their usage can be complex and potentially unsafe. - /// - /// The `attribute` parameter specifies the raw attribute to be set, while the `value` - /// parameter holds the value associated with that attribute. Please refer to the - /// [`windows-rs` documentation] or the [Win32 API documentation] for detailed information - /// about available attributes and their meanings. - /// - /// [`windows-rs` documentation]: https://microsoft.github.io/windows-docs-rs/doc/windows/ - /// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute + /// This method enables the customization of attributes for the spawned + /// child process on Windows systems. + /// Attributes offer extended configurability for process creation, + /// but their usage can be intricate and potentially unsafe. /// /// # Note /// - /// The maximum number of raw attributes is the value of [`u32::MAX`]. - /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` - /// indicating that the maximum number of attributes has been exceeded. - /// - /// # Safety - /// - /// The usage of raw attributes is potentially unsafe and should be done with caution. - /// Incorrect attribute values or improper configuration can lead to unexpected behavior or - /// errors. + /// By default, stdin, stdout, and stderr are inherited from the parent + /// process. /// /// # Example /// - /// The following example demonstrates how to create a child process with a specific parent - /// process ID using a raw attribute. - /// - /// ```rust + /// ``` /// #![feature(windows_process_extensions_raw_attribute)] - /// use std::os::windows::{process::CommandExt, io::AsRawHandle}; + /// use std::os::windows::io::AsRawHandle; + /// use std::os::windows::process::{CommandExt, ProcThreadAttributeList}; /// use std::process::Command; /// /// # struct ProcessDropGuard(std::process::Child); @@ -338,36 +323,27 @@ pub trait CommandExt: Sealed { /// # let _ = self.0.kill(); /// # } /// # } - /// + /// # /// let parent = Command::new("cmd").spawn()?; - /// - /// let mut child_cmd = Command::new("cmd"); + /// let parent_process_handle = parent.as_raw_handle(); + /// # let parent = ProcessDropGuard(parent); /// /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; + /// let mut attribute_list = ProcThreadAttributeList::build() + /// .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle) + /// .finish() + /// .unwrap(); /// - /// unsafe { - /// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize); - /// } + /// let mut child = Command::new("cmd").spawn_with_attributes(&attribute_list)?; /// # - /// # let parent = ProcessDropGuard(parent); - /// - /// let mut child = child_cmd.spawn()?; - /// /// # child.kill()?; /// # Ok::<(), std::io::Error>(()) /// ``` - /// - /// # Safety Note - /// - /// Remember that improper use of raw attributes can lead to undefined behavior or security - /// vulnerabilities. Always consult the documentation and ensure proper attribute values are - /// used. #[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] - unsafe fn raw_attribute( + fn spawn_with_attributes( &mut self, - attribute: usize, - value: T, - ) -> &mut process::Command; + attribute_list: &ProcThreadAttributeList<'_>, + ) -> io::Result; } #[stable(feature = "windows_process_extensions", since = "1.16.0")] @@ -401,13 +377,13 @@ impl CommandExt for process::Command { self } - unsafe fn raw_attribute( + fn spawn_with_attributes( &mut self, - attribute: usize, - value: T, - ) -> &mut process::Command { - unsafe { self.as_inner_mut().raw_attribute(attribute, value) }; - self + attribute_list: &ProcThreadAttributeList<'_>, + ) -> io::Result { + self.as_inner_mut() + .spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list)) + .map(process::Child::from_inner) } } @@ -447,3 +423,245 @@ impl ExitCodeExt for process::ExitCode { process::ExitCode::from_inner(From::from(raw)) } } + +/// A wrapper around windows [`ProcThreadAttributeList`][1]. +/// +/// [1]: +#[derive(Debug)] +#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] +pub struct ProcThreadAttributeList<'a> { + attribute_list: Box<[MaybeUninit]>, + _lifetime_marker: marker::PhantomData<&'a ()>, +} + +#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] +impl<'a> ProcThreadAttributeList<'a> { + /// Creates a new builder for constructing a [`ProcThreadAttributeList`]. + pub fn build() -> ProcThreadAttributeListBuilder<'a> { + ProcThreadAttributeListBuilder::new() + } + + /// Returns a pointer to the underling attribute list. + #[doc(hidden)] + pub fn as_ptr(&self) -> *const MaybeUninit { + self.attribute_list.as_ptr() + } +} + +#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] +impl<'a> Drop for ProcThreadAttributeList<'a> { + /// Deletes the attribute list. + /// + /// This method calls [`DeleteProcThreadAttributeList`][1] to delete the + /// underlying attribute list. + /// + /// [1]: + fn drop(&mut self) { + let lp_attribute_list = self.attribute_list.as_mut_ptr().cast::(); + unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) } + } +} + +/// Builder for constructing a [`ProcThreadAttributeList`]. +#[derive(Clone, Debug)] +#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] +pub struct ProcThreadAttributeListBuilder<'a> { + attributes: alloc::collections::BTreeMap, + _lifetime_marker: marker::PhantomData<&'a ()>, +} + +#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] +impl<'a> ProcThreadAttributeListBuilder<'a> { + fn new() -> Self { + ProcThreadAttributeListBuilder { + attributes: alloc::collections::BTreeMap::new(), + _lifetime_marker: marker::PhantomData, + } + } + + /// Sets an attribute on the attribute list. + /// + /// The `attribute` parameter specifies the raw attribute to be set, while + /// the `value` parameter holds the value associated with that attribute. + /// Please refer to the [Windows documentation][1] for a list of valid attributes. + /// + /// # Note + /// + /// The maximum number of attributes is the value of [`u32::MAX`]. If this + /// limit is exceeded, the call to [`Self::finish`] will return an `Error` + /// indicating that the maximum number of attributes has been exceeded. + /// + /// # Safety Note + /// + /// Remember that improper use of attributes can lead to undefined behavior + /// or security vulnerabilities. Always consult the documentation and ensure + /// proper attribute values are used. + /// + /// [1]: + pub fn attribute(self, attribute: usize, value: &'a T) -> Self { + unsafe { + self.raw_attribute( + attribute, + ptr::addr_of!(*value).cast::(), + crate::mem::size_of::(), + ) + } + } + + /// Sets a raw attribute on the attribute list. + /// + /// This function is useful for setting attributes with pointers or sizes + /// that cannot be derived directly from their values. + /// + /// # Safety + /// + /// This function is marked as `unsafe` because it deals with raw pointers + /// and sizes. It is the responsibility of the caller to ensure the value + /// lives longer than the resulting [`ProcThreadAttributeList`] as well as + /// the validity of the size parameter. + /// + /// # Example + /// + /// ``` + /// #![feature(windows_process_extensions_raw_attribute)] + /// use std::ffi::c_void; + /// use std::os::windows::process::{CommandExt, ProcThreadAttributeList}; + /// use std::os::windows::raw::HANDLE; + /// use std::process::Command; + /// + /// #[repr(C)] + /// pub struct COORD { + /// pub X: i16, + /// pub Y: i16, + /// } + /// + /// extern "system" { + /// fn CreatePipe( + /// hreadpipe: *mut HANDLE, + /// hwritepipe: *mut HANDLE, + /// lppipeattributes: *const c_void, + /// nsize: u32, + /// ) -> i32; + /// fn CreatePseudoConsole( + /// size: COORD, + /// hinput: HANDLE, + /// houtput: HANDLE, + /// dwflags: u32, + /// phpc: *mut isize, + /// ) -> i32; + /// fn CloseHandle(hobject: HANDLE) -> i32; + /// } + /// + /// let [mut input_read_side, mut output_write_side, mut output_read_side, mut input_write_side] = + /// [unsafe { std::mem::zeroed::() }; 4]; + /// + /// unsafe { + /// CreatePipe(&mut input_read_side, &mut input_write_side, std::ptr::null(), 0); + /// CreatePipe(&mut output_read_side, &mut output_write_side, std::ptr::null(), 0); + /// } + /// + /// let size = COORD { X: 60, Y: 40 }; + /// let mut h_pc = unsafe { std::mem::zeroed() }; + /// unsafe { CreatePseudoConsole(size, input_read_side, output_write_side, 0, &mut h_pc) }; + /// + /// unsafe { CloseHandle(input_read_side) }; + /// unsafe { CloseHandle(output_write_side) }; + /// + /// const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 131094; + /// + /// let attribute_list = unsafe { + /// ProcThreadAttributeList::build() + /// .raw_attribute( + /// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + /// h_pc as *const c_void, + /// std::mem::size_of::(), + /// ) + /// .finish()? + /// }; + /// + /// let mut child = Command::new("cmd").spawn_with_attributes(&attribute_list)?; + /// # + /// # child.kill()?; + /// # Ok::<(), std::io::Error>(()) + /// ``` + pub unsafe fn raw_attribute( + mut self, + attribute: usize, + value_ptr: *const T, + value_size: usize, + ) -> Self { + self.attributes.insert(attribute, ProcThreadAttributeValue { + ptr: value_ptr.cast::(), + size: value_size, + }); + self + } + + /// Finalizes the construction of the `ProcThreadAttributeList`. + /// + /// # Errors + /// + /// Returns an error if the maximum number of attributes is exceeded + /// or if there is an I/O error during initialization. + pub fn finish(&self) -> io::Result> { + // To initialize our ProcThreadAttributeList, we need to determine + // how many bytes to allocate for it. The Windows API simplifies this + // process by allowing us to call `InitializeProcThreadAttributeList` + // with a null pointer to retrieve the required size. + let mut required_size = 0; + let Ok(attribute_count) = self.attributes.len().try_into() else { + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "maximum number of ProcThreadAttributes exceeded", + )); + }; + unsafe { + sys::c::InitializeProcThreadAttributeList( + ptr::null_mut(), + attribute_count, + 0, + &mut required_size, + ) + }; + + let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice(); + + // Once we've allocated the necessary memory, it's safe to invoke + // `InitializeProcThreadAttributeList` to properly initialize the list. + sys::cvt(unsafe { + sys::c::InitializeProcThreadAttributeList( + attribute_list.as_mut_ptr().cast::(), + attribute_count, + 0, + &mut required_size, + ) + })?; + + // # Add our attributes to the buffer. + // It's theoretically possible for the attribute count to exceed a u32 + // value. Therefore, we ensure that we don't add more attributes than + // the buffer was initialized for. + for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) { + sys::cvt(unsafe { + sys::c::UpdateProcThreadAttribute( + attribute_list.as_mut_ptr().cast::(), + 0, + attribute, + value.ptr, + value.size, + ptr::null_mut(), + ptr::null_mut(), + ) + })?; + } + + Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData }) + } +} + +/// Wrapper around the value data to be used as a Process Thread Attribute. +#[derive(Clone, Debug)] +struct ProcThreadAttributeValue { + ptr: *const c_void, + size: usize, +} diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index fb0b495961c36..e8cbfe337bccf 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -450,7 +450,7 @@ fn test_creation_flags() { fn test_proc_thread_attributes() { use crate::mem; use crate::os::windows::io::AsRawHandle; - use crate::os::windows::process::CommandExt; + use crate::os::windows::process::{CommandExt, ProcThreadAttributeList}; use crate::sys::c::{BOOL, CloseHandle, HANDLE}; use crate::sys::cvt; @@ -490,12 +490,14 @@ fn test_proc_thread_attributes() { let mut child_cmd = Command::new("cmd"); - unsafe { - child_cmd - .raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.0.as_raw_handle() as isize); - } + let parent_process_handle = parent.0.as_raw_handle(); + + let mut attribute_list = ProcThreadAttributeList::build() + .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle) + .finish() + .unwrap(); - let child = ProcessDropGuard(child_cmd.spawn().unwrap()); + let child = ProcessDropGuard(child_cmd.spawn_with_attributes(&mut attribute_list).unwrap()); let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; diff --git a/std/src/sys/pal/windows/process.rs b/std/src/sys/pal/windows/process.rs index da0daacd1dde3..2ca20a21dfe51 100644 --- a/std/src/sys/pal/windows/process.rs +++ b/std/src/sys/pal/windows/process.rs @@ -10,10 +10,10 @@ use crate::collections::BTreeMap; use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, Error, ErrorKind}; -use crate::mem::MaybeUninit; use crate::num::NonZero; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; +use crate::os::windows::process::ProcThreadAttributeList; use crate::path::{Path, PathBuf}; use crate::sync::Mutex; use crate::sys::args::{self, Arg}; @@ -162,7 +162,6 @@ pub struct Command { stdout: Option, stderr: Option, force_quotes_enabled: bool, - proc_thread_attributes: BTreeMap, } pub enum Stdio { @@ -194,7 +193,6 @@ impl Command { stdout: None, stderr: None, force_quotes_enabled: false, - proc_thread_attributes: Default::default(), } } @@ -248,21 +246,19 @@ impl Command { self.cwd.as_ref().map(Path::new) } - pub unsafe fn raw_attribute( + pub fn spawn( &mut self, - attribute: usize, - value: T, - ) { - self.proc_thread_attributes.insert(attribute, ProcThreadAttributeValue { - size: mem::size_of::(), - data: Box::new(value), - }); + default: Stdio, + needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + self.spawn_with_attributes(default, needs_stdin, None) } - pub fn spawn( + pub fn spawn_with_attributes( &mut self, default: Stdio, needs_stdin: bool, + proc_thread_attribute_list: Option<&ProcThreadAttributeList<'_>>, ) -> io::Result<(Process, StdioPipes)> { let maybe_env = self.env.capture_if_changed(); @@ -355,18 +351,18 @@ impl Command { let si_ptr: *mut c::STARTUPINFOW; - let mut proc_thread_attribute_list; let mut si_ex; - if !self.proc_thread_attributes.is_empty() { + if let Some(proc_thread_attribute_list) = proc_thread_attribute_list { si.cb = mem::size_of::() as u32; flags |= c::EXTENDED_STARTUPINFO_PRESENT; - proc_thread_attribute_list = - make_proc_thread_attribute_list(&self.proc_thread_attributes)?; si_ex = c::STARTUPINFOEXW { StartupInfo: si, - lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _, + // SAFETY: Casting this `*const` pointer to a `*mut` pointer is "safe" + // here because windows does not internally mutate the attribute list. + // Ideally this should be reflected in the interface of the `windows-sys` crate. + lpAttributeList: proc_thread_attribute_list.as_ptr().cast::().cast_mut(), }; si_ptr = (&raw mut si_ex) as _; } else { @@ -896,79 +892,6 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { } } -struct ProcThreadAttributeList(Box<[MaybeUninit]>); - -impl Drop for ProcThreadAttributeList { - fn drop(&mut self) { - let lp_attribute_list = self.0.as_mut_ptr() as _; - unsafe { c::DeleteProcThreadAttributeList(lp_attribute_list) } - } -} - -/// Wrapper around the value data to be used as a Process Thread Attribute. -struct ProcThreadAttributeValue { - data: Box, - size: usize, -} - -fn make_proc_thread_attribute_list( - attributes: &BTreeMap, -) -> io::Result { - // To initialize our ProcThreadAttributeList, we need to determine - // how many bytes to allocate for it. The Windows API simplifies this process - // by allowing us to call `InitializeProcThreadAttributeList` with - // a null pointer to retrieve the required size. - let mut required_size = 0; - let Ok(attribute_count) = attributes.len().try_into() else { - return Err(io::const_error!( - ErrorKind::InvalidInput, - "maximum number of ProcThreadAttributes exceeded", - )); - }; - unsafe { - c::InitializeProcThreadAttributeList( - ptr::null_mut(), - attribute_count, - 0, - &mut required_size, - ) - }; - - let mut proc_thread_attribute_list = - ProcThreadAttributeList(vec![MaybeUninit::uninit(); required_size].into_boxed_slice()); - - // Once we've allocated the necessary memory, it's safe to invoke - // `InitializeProcThreadAttributeList` to properly initialize the list. - cvt(unsafe { - c::InitializeProcThreadAttributeList( - proc_thread_attribute_list.0.as_mut_ptr() as *mut _, - attribute_count, - 0, - &mut required_size, - ) - })?; - - // # Add our attributes to the buffer. - // It's theoretically possible for the attribute count to exceed a u32 value. - // Therefore, we ensure that we don't add more attributes than the buffer was initialized for. - for (&attribute, value) in attributes.iter().take(attribute_count as usize) { - let value_ptr = (&raw const *value.data) as _; - cvt(unsafe { - c::UpdateProcThreadAttribute( - proc_thread_attribute_list.0.as_mut_ptr() as _, - 0, - attribute, - value_ptr, - value.size, - ptr::null_mut(), - ptr::null_mut(), - ) - })?; - } - - Ok(proc_thread_attribute_list) -} - pub struct CommandArgs<'a> { iter: crate::slice::Iter<'a, Arg>, } From 85278b6809c95437adb7652b925b5ed10ca4ab22 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 20 Dec 2024 18:55:48 +0100 Subject: [PATCH 168/481] Improve prose around basic examples of Iter and IterMut --- core/src/slice/iter.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index a27baf9db224c..e076fbe517f22 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -46,13 +46,19 @@ impl<'a, T> IntoIterator for &'a mut [T] { /// Basic usage: /// /// ``` -/// // First, we declare a type which has `iter` method to get the `Iter` struct (`&[usize]` here): +/// // First, we need a slice to call the `iter` method on: /// let slice = &[1, 2, 3]; /// -/// // Then, we iterate over it: +/// // Then we call `iter` on the slice to get the `Iter` struct, +/// // and iterate over it: /// for element in slice.iter() { /// println!("{element}"); /// } +/// +/// // This for loop actually already works without calling `iter`: +/// for element in slice { +/// println!("{element}"); +/// } /// ``` /// /// [`iter`]: slice::iter @@ -166,11 +172,11 @@ impl AsRef<[T]> for Iter<'_, T> { /// Basic usage: /// /// ``` -/// // First, we declare a type which has `iter_mut` method to get the `IterMut` -/// // struct (`&[usize]` here): -/// let mut slice = &mut [1, 2, 3]; +/// // First, we need a slice to call the `iter_mut` method on: +/// let slice = &mut [1, 2, 3]; /// -/// // Then, we iterate over it and increment each element value: +/// // Then we call `iter_mut` on the slice to get the `IterMut` struct, +/// // iterate over it and increment each element value: /// for element in slice.iter_mut() { /// *element += 1; /// } From 7c064c727caa5b7de259f5fea218d5c2c0077335 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 20 Dec 2024 19:19:34 +0100 Subject: [PATCH 169/481] Improve prose around `as_slice` example of Iter --- core/src/slice/iter.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index e076fbe517f22..d3e79f5ff5a8d 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -115,19 +115,25 @@ impl<'a, T> Iter<'a, T> { /// Basic usage: /// /// ``` - /// // First, we declare a type which has the `iter` method to get the `Iter` + /// // First, we need a slice to call the `iter` method on: /// // struct (`&[usize]` here): /// let slice = &[1, 2, 3]; /// - /// // Then, we get the iterator: + /// // Then we call `iter` on the slice to get the `Iter` struct: /// let mut iter = slice.iter(); - /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": + /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]": /// println!("{:?}", iter.as_slice()); /// - /// // Next, we move to the second element of the slice: + /// // Now, we call the `next` method to remove the first element of the iterator: /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": + /// // Here the iterator does not contain the first element of the slice any more, + /// // so `as_slice` only returns the last two elements of the slice, + /// // and so this prints "[2, 3]": /// println!("{:?}", iter.as_slice()); + /// + /// // The underlying slice has not been modified and still contains three elements, + /// // so this prints "[1, 2, 3]": + /// println!("{:?}", slice); /// ``` #[must_use] #[stable(feature = "iter_to_slice", since = "1.4.0")] From adf35ebf71b8ac883e823de692a6a9cd698630ac Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 20 Dec 2024 19:57:20 +0100 Subject: [PATCH 170/481] Improve prose around into_slice example of IterMut --- core/src/slice/iter.rs | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index d3e79f5ff5a8d..d2842f69008e2 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -259,28 +259,21 @@ impl<'a, T> IterMut<'a, T> { /// Basic usage: /// /// ``` - /// // First, we declare a type which has `iter_mut` method to get the `IterMut` - /// // struct (`&[usize]` here): + /// // First, we need a slice to call the `iter_mut` method on: /// let mut slice = &mut [1, 2, 3]; /// - /// { - /// // Then, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // We move to next element: - /// iter.next(); - /// // So if we print what `into_slice` method returns here, we have "[2, 3]": - /// println!("{:?}", iter.into_slice()); - /// } - /// - /// // Now let's modify a value of the slice: - /// { - /// // First we get back the iterator: - /// let mut iter = slice.iter_mut(); - /// // We change the value of the first element of the slice returned by the `next` method: - /// *iter.next().unwrap() += 1; - /// } - /// // Now slice is "[2, 2, 3]": - /// println!("{slice:?}"); + /// // Then we call `iter_mut` on the slice to get the `IterMut` struct: + /// let mut iter = slice.iter_mut(); + /// // Now, we call the `next` method to remove the first element of the iterator, + /// // unwrap and dereference what we get from `next` and increase its value by 1: + /// *iter.next().unwrap() += 1; + /// // Here the iterator does not contain the first element of the slice any more, + /// // so `into_slice` only returns the last two elements of the slice, + /// // and so this prints "[2, 3]": + /// println!("{:?}", iter.into_slice()); + /// // The underlying slice still contains three elements, but its first element + /// // was increased by 1, so this prints "[2, 2, 3]": + /// println!("{:?}", slice); /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "iter_to_slice", since = "1.4.0")] From c50ee886afef08f6dec467647f2d351f7dd732c8 Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 20 Dec 2024 17:02:46 +0000 Subject: [PATCH 171/481] Less unwrap() in documentation --- alloc/src/collections/binary_heap/mod.rs | 3 +-- core/src/cell/once.rs | 12 ++++++---- core/src/fmt/mod.rs | 11 +++++---- core/src/iter/sources/once.rs | 3 ++- core/src/iter/traits/iterator.rs | 6 ++--- core/src/option.rs | 8 ++++++- core/src/ptr/const_ptr.rs | 9 +++++--- core/src/result.rs | 11 ++++++--- core/src/str/converts.rs | 5 ++-- core/src/sync/atomic.rs | 4 ++-- std/src/io/mod.rs | 25 ++++++++++++-------- std/src/process.rs | 29 ++++++++++++------------ 12 files changed, 76 insertions(+), 50 deletions(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 116e0e73e9659..965fd63a52981 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -531,8 +531,7 @@ impl BinaryHeap { /// heap.push(1); /// heap.push(5); /// heap.push(2); - /// { - /// let mut val = heap.peek_mut().unwrap(); + /// if let Some(mut val) = heap.peek_mut() { /// *val = 0; /// } /// assert_eq!(heap.peek(), Some(&2)); diff --git a/core/src/cell/once.rs b/core/src/cell/once.rs index c14afe0f4761c..6a85791916a61 100644 --- a/core/src/cell/once.rs +++ b/core/src/cell/once.rs @@ -262,7 +262,9 @@ impl OnceCell { /// /// let value = cell.get_mut_or_try_init(|| "1234".parse()); /// assert_eq!(value, Ok(&mut 1234)); - /// *value.unwrap() += 2; + /// + /// let Ok(value) = value else { return; }; + /// *value += 2; /// assert_eq!(cell.get(), Some(&1236)) /// ``` #[unstable(feature = "once_cell_get_mut", issue = "121641")] @@ -304,8 +306,8 @@ impl OnceCell { /// assert_eq!(cell.into_inner(), None); /// /// let cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// let _ = cell.set("hello".to_owned()); + /// assert_eq!(cell.into_inner(), Some("hello".to_owned())); /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] @@ -332,8 +334,8 @@ impl OnceCell { /// assert_eq!(cell.take(), None); /// /// let mut cell = OnceCell::new(); - /// cell.set("hello".to_string()).unwrap(); - /// assert_eq!(cell.take(), Some("hello".to_string())); + /// let _ = cell.set("hello".to_owned()); + /// assert_eq!(cell.take(), Some("hello".to_owned())); /// assert_eq!(cell.get(), None); /// ``` #[inline] diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index 14c7006510162..c2c78dd9c67eb 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -152,8 +152,9 @@ pub trait Write { /// } /// /// let mut buf = String::new(); - /// writer(&mut buf, "hola").unwrap(); + /// writer(&mut buf, "hola")?; /// assert_eq!(&buf, "hola"); + /// # std::fmt::Result::Ok(()) /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_str(&mut self, s: &str) -> Result; @@ -179,9 +180,10 @@ pub trait Write { /// } /// /// let mut buf = String::new(); - /// writer(&mut buf, 'a').unwrap(); - /// writer(&mut buf, 'b').unwrap(); + /// writer(&mut buf, 'a')?; + /// writer(&mut buf, 'b')?; /// assert_eq!(&buf, "ab"); + /// # std::fmt::Result::Ok(()) /// ``` #[stable(feature = "fmt_write_char", since = "1.1.0")] fn write_char(&mut self, c: char) -> Result { @@ -208,8 +210,9 @@ pub trait Write { /// } /// /// let mut buf = String::new(); - /// writer(&mut buf, "world").unwrap(); + /// writer(&mut buf, "world")?; /// assert_eq!(&buf, "world"); + /// # std::fmt::Result::Ok(()) /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_fmt(&mut self, args: Arguments<'_>) -> Result { diff --git a/core/src/iter/sources/once.rs b/core/src/iter/sources/once.rs index 21be4377da1ca..c4a9860bdd76c 100644 --- a/core/src/iter/sources/once.rs +++ b/core/src/iter/sources/once.rs @@ -34,7 +34,7 @@ use crate::iter::{FusedIterator, TrustedLen}; /// use std::fs; /// use std::path::PathBuf; /// -/// let dirs = fs::read_dir(".foo").unwrap(); +/// let dirs = fs::read_dir(".foo")?; /// /// // we need to convert from an iterator of DirEntry-s to an iterator of /// // PathBufs, so we use map @@ -50,6 +50,7 @@ use crate::iter::{FusedIterator, TrustedLen}; /// for f in files { /// println!("{f:?}"); /// } +/// # std::io::Result::Ok(()) /// ``` #[stable(feature = "iter_once", since = "1.2.0")] pub fn once(value: T) -> Once { diff --git a/core/src/iter/traits/iterator.rs b/core/src/iter/traits/iterator.rs index 38dfbbef39323..ff39e8ac25f8f 100644 --- a/core/src/iter/traits/iterator.rs +++ b/core/src/iter/traits/iterator.rs @@ -2564,7 +2564,7 @@ pub trait Iterator { /// # Example /// /// ``` - /// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap(); + /// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap_or(0); /// assert_eq!(reduced, 45); /// /// // Which is equivalent to doing it with `fold`: @@ -3087,7 +3087,7 @@ pub trait Iterator { /// [2.4, f32::NAN, 1.3] /// .into_iter() /// .reduce(f32::max) - /// .unwrap(), + /// .unwrap_or(0.), /// 2.4 /// ); /// ``` @@ -3123,7 +3123,7 @@ pub trait Iterator { /// [2.4, f32::NAN, 1.3] /// .into_iter() /// .reduce(f32::min) - /// .unwrap(), + /// .unwrap_or(0.), /// 1.3 /// ); /// ``` diff --git a/core/src/option.rs b/core/src/option.rs index f4ac7af63961b..a9f06b92ad5dd 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -937,10 +937,16 @@ impl Option { /// Returns the contained [`Some`] value, consuming the `self` value. /// /// Because this function may panic, its use is generally discouraged. + /// Panics are meant for unrecoverable errors, and + /// [may abort the entire program][panic-abort]. + /// /// Instead, prefer to use pattern matching and handle the [`None`] /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or - /// [`unwrap_or_default`]. + /// [`unwrap_or_default`]. In functions returning `Option`, you can use + /// [the `?` (try) operator][try-option]. /// + /// [panic-abort]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html + /// [try-option]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#where-the--operator-can-be-used /// [`unwrap_or`]: Option::unwrap_or /// [`unwrap_or_else`]: Option::unwrap_or_else /// [`unwrap_or_default`]: Option::unwrap_or_default diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index f100adecbbb76..ac905eceaa803 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -502,11 +502,12 @@ impl *const T { /// let mut out = String::new(); /// while ptr != end_rounded_up { /// unsafe { - /// write!(&mut out, "{}, ", *ptr).unwrap(); + /// write!(&mut out, "{}, ", *ptr)?; /// } /// ptr = ptr.wrapping_offset(step); /// } /// assert_eq!(out.as_str(), "1, 3, 5, "); + /// # std::fmt::Result::Ok(()) /// ``` #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] @@ -1125,11 +1126,12 @@ impl *const T { /// let mut out = String::new(); /// while ptr != end_rounded_up { /// unsafe { - /// write!(&mut out, "{}, ", *ptr).unwrap(); + /// write!(&mut out, "{}, ", *ptr)?; /// } /// ptr = ptr.wrapping_add(step); /// } /// assert_eq!(out, "1, 3, 5, "); + /// # std::fmt::Result::Ok(()) /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] @@ -1203,11 +1205,12 @@ impl *const T { /// let mut out = String::new(); /// while ptr != start_rounded_down { /// unsafe { - /// write!(&mut out, "{}, ", *ptr).unwrap(); + /// write!(&mut out, "{}, ", *ptr)?; /// } /// ptr = ptr.wrapping_sub(step); /// } /// assert_eq!(out, "5, 3, 1, "); + /// # std::fmt::Result::Ok(()) /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] diff --git a/core/src/result.rs b/core/src/result.rs index 9c7be618bc773..92b5cba153166 100644 --- a/core/src/result.rs +++ b/core/src/result.rs @@ -1065,10 +1065,15 @@ impl Result { /// Returns the contained [`Ok`] value, consuming the `self` value. /// /// Because this function may panic, its use is generally discouraged. - /// Instead, prefer to use pattern matching and handle the [`Err`] - /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or - /// [`unwrap_or_default`]. + /// Panics are meant for unrecoverable errors, and + /// [may abort the entire program][panic-abort]. + /// + /// Instead, prefer to use [the `?` (try) operator][try-operator], or pattern matching + /// to handle the [`Err`] case explicitly, or call [`unwrap_or`], + /// [`unwrap_or_else`], or [`unwrap_or_default`]. /// + /// [panic-abort]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html + /// [try-operator]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator /// [`unwrap_or`]: Result::unwrap_or /// [`unwrap_or_else`]: Result::unwrap_or_else /// [`unwrap_or_default`]: Result::unwrap_or_default diff --git a/core/src/str/converts.rs b/core/src/str/converts.rs index c7bae42765f4e..de68f80aa0c8e 100644 --- a/core/src/str/converts.rs +++ b/core/src/str/converts.rs @@ -47,10 +47,11 @@ use crate::{mem, ptr}; /// // some bytes, in a vector /// let sparkle_heart = vec![240, 159, 146, 150]; /// -/// // We know these bytes are valid, so just use `unwrap()`. -/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// // We can use the ? (try) operator to check if the bytes are valid +/// let sparkle_heart = str::from_utf8(&sparkle_heart)?; /// /// assert_eq!("💖", sparkle_heart); +/// # Ok::<_, str::Utf8Error>(()) /// ``` /// /// Incorrect bytes: diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 487fffba881b3..fda26a672990a 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -86,7 +86,7 @@ //! // This is fine: `join` synchronizes the code in a way such that the atomic //! // store happens-before the non-atomic write. //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store -//! handle.join().unwrap(); // synchronize +//! handle.join().expect("thread won't panic"); // synchronize //! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); //! @@ -103,7 +103,7 @@ //! // This is fine: `join` synchronizes the code in a way such that //! // the 1-byte store happens-before the 2-byte store. //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); -//! handle.join().unwrap(); +//! handle.join().expect("thread won't panic"); //! s.spawn(|| unsafe { //! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic); //! differently_sized.store(2, Ordering::Relaxed); diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 4ffb04630061f..7912f969bbd9f 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1083,7 +1083,7 @@ pub trait Read { /// let f = BufReader::new(File::open("foo.txt")?); /// /// for byte in f.bytes() { - /// println!("{}", byte.unwrap()); + /// println!("{}", byte?); /// } /// Ok(()) /// } @@ -1995,15 +1995,16 @@ pub trait Seek { /// .write(true) /// .read(true) /// .create(true) - /// .open("foo.txt").unwrap(); + /// .open("foo.txt")?; /// /// let hello = "Hello!\n"; - /// write!(f, "{hello}").unwrap(); - /// f.rewind().unwrap(); + /// write!(f, "{hello}")?; + /// f.rewind()?; /// /// let mut buf = String::new(); - /// f.read_to_string(&mut buf).unwrap(); + /// f.read_to_string(&mut buf)?; /// assert_eq!(&buf, hello); + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "seek_rewind", since = "1.55.0")] fn rewind(&mut self) -> Result<()> { @@ -2212,8 +2213,9 @@ fn skip_until(r: &mut R, delim: u8) -> Result { /// /// let stdin = io::stdin(); /// for line in stdin.lock().lines() { -/// println!("{}", line.unwrap()); +/// println!("{}", line?); /// } +/// # std::io::Result::Ok(()) /// ``` /// /// If you have something that implements [`Read`], you can use the [`BufReader` @@ -2236,7 +2238,8 @@ fn skip_until(r: &mut R, delim: u8) -> Result { /// let f = BufReader::new(f); /// /// for line in f.lines() { -/// println!("{}", line.unwrap()); +/// let line = line?; +/// println!("{line}"); /// } /// /// Ok(()) @@ -2274,7 +2277,7 @@ pub trait BufRead: Read { /// let stdin = io::stdin(); /// let mut stdin = stdin.lock(); /// - /// let buffer = stdin.fill_buf().unwrap(); + /// let buffer = stdin.fill_buf()?; /// /// // work with buffer /// println!("{buffer:?}"); @@ -2282,6 +2285,7 @@ pub trait BufRead: Read { /// // ensure the bytes we worked with aren't returned again later /// let length = buffer.len(); /// stdin.consume(length); + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn fill_buf(&mut self) -> Result<&[u8]>; @@ -2327,12 +2331,13 @@ pub trait BufRead: Read { /// let stdin = io::stdin(); /// let mut stdin = stdin.lock(); /// - /// while stdin.has_data_left().unwrap() { + /// while stdin.has_data_left()? { /// let mut line = String::new(); - /// stdin.read_line(&mut line).unwrap(); + /// stdin.read_line(&mut line)?; /// // work with line /// println!("{line:?}"); /// } + /// # std::io::Result::Ok(()) /// ``` #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")] fn has_data_left(&mut self) -> Result { diff --git a/std/src/process.rs b/std/src/process.rs index 6933528cdbd0a..929d2b57afe5c 100644 --- a/std/src/process.rs +++ b/std/src/process.rs @@ -224,7 +224,7 @@ pub struct Child { /// has been captured. You might find it helpful to do /// /// ```ignore (incomplete) - /// let stdin = child.stdin.take().unwrap(); + /// let stdin = child.stdin.take().expect("handle present"); /// ``` /// /// to avoid partially moving the `child` and thus blocking yourself from calling @@ -236,7 +236,7 @@ pub struct Child { /// has been captured. You might find it helpful to do /// /// ```ignore (incomplete) - /// let stdout = child.stdout.take().unwrap(); + /// let stdout = child.stdout.take().expect("handle present"); /// ``` /// /// to avoid partially moving the `child` and thus blocking yourself from calling @@ -248,7 +248,7 @@ pub struct Child { /// has been captured. You might find it helpful to do /// /// ```ignore (incomplete) - /// let stderr = child.stderr.take().unwrap(); + /// let stderr = child.stderr.take().expect("handle present"); /// ``` /// /// to avoid partially moving the `child` and thus blocking yourself from calling @@ -1052,14 +1052,14 @@ impl Command { /// use std::io::{self, Write}; /// let output = Command::new("/bin/cat") /// .arg("file.txt") - /// .output() - /// .expect("failed to execute process"); + /// .output()?; /// /// println!("status: {}", output.status); - /// io::stdout().write_all(&output.stdout).unwrap(); - /// io::stderr().write_all(&output.stderr).unwrap(); + /// io::stdout().write_all(&output.stdout)?; + /// io::stderr().write_all(&output.stderr)?; /// /// assert!(output.status.success()); + /// # io::Result::Ok(()) /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn output(&mut self) -> io::Result { @@ -1391,11 +1391,11 @@ impl Stdio { /// let output = Command::new("rev") /// .stdin(Stdio::inherit()) /// .stdout(Stdio::piped()) - /// .output() - /// .expect("Failed to execute command"); + /// .output()?; /// /// print!("You piped in the reverse of: "); - /// io::stdout().write_all(&output.stdout).unwrap(); + /// io::stdout().write_all(&output.stdout)?; + /// # io::Result::Ok(()) /// ``` #[must_use] #[stable(feature = "process", since = "1.0.0")] @@ -1575,14 +1575,14 @@ impl From for Stdio { /// use std::process::Command; /// /// // With the `foo.txt` file containing "Hello, world!" - /// let file = File::open("foo.txt").unwrap(); + /// let file = File::open("foo.txt")?; /// /// let reverse = Command::new("rev") /// .stdin(file) // Implicit File conversion into a Stdio - /// .output() - /// .expect("failed reverse command"); + /// .output()?; /// /// assert_eq!(reverse.stdout, b"!dlrow ,olleH"); + /// # std::io::Result::Ok(()) /// ``` fn from(file: fs::File) -> Stdio { Stdio::from_inner(file.into_inner().into()) @@ -2179,7 +2179,7 @@ impl Child { /// ```no_run /// use std::process::Command; /// - /// let mut child = Command::new("ls").spawn().unwrap(); + /// let mut child = Command::new("ls").spawn()?; /// /// match child.try_wait() { /// Ok(Some(status)) => println!("exited with: {status}"), @@ -2190,6 +2190,7 @@ impl Child { /// } /// Err(e) => println!("error attempting to wait: {e}"), /// } + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "process_try_wait", since = "1.18.0")] pub fn try_wait(&mut self) -> io::Result> { From 3d17aa4d68c8b4f8efe9fb959e9a13a2f64396ef Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Mon, 30 Sep 2024 19:12:05 +0200 Subject: [PATCH 172/481] Win: Use `FILE_RENAME_FLAG_POSIX_SEMANTICS` for `std::fs::rename` if available Windows 10 1601 introduced `FileRenameInfoEx` as well as `FILE_RENAME_FLAG_POSIX_SEMANTICS`, allowing for atomic renaming. If it isn't supported, we fall back to `FileRenameInfo`. This commit also replicates `MoveFileExW`'s behavior of checking whether the source file is a mount point and moving the mount point instead of resolving the target path. --- std/src/fs.rs | 8 +- std/src/sys/pal/windows/c/bindings.txt | 3 + std/src/sys/pal/windows/c/windows_sys.rs | 16 +++ std/src/sys/pal/windows/fs.rs | 145 ++++++++++++++++++++++- 4 files changed, 168 insertions(+), 4 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 2d5d869630e0e..0178691c0e551 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -2397,12 +2397,14 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// # Platform-specific behavior /// /// This function currently corresponds to the `rename` function on Unix -/// and the `MoveFileEx` function with the `MOVEFILE_REPLACE_EXISTING` flag on Windows. +/// and the `SetFileInformationByHandle` function on Windows. /// /// Because of this, the behavior when both `from` and `to` exist differs. On /// Unix, if `from` is a directory, `to` must also be an (empty) directory. If -/// `from` is not a directory, `to` must also be not a directory. In contrast, -/// on Windows, `from` can be anything, but `to` must *not* be a directory. +/// `from` is not a directory, `to` must also be not a directory. The behavior +/// on Windows is the same on Windows 10 1607 and higher if `FileRenameInfoEx` +/// is supported by the filesystem; otherwise, `from` can be anything, but +/// `to` must *not* be a directory. /// /// Note that, this [may change in the future][changes]. /// diff --git a/std/src/sys/pal/windows/c/bindings.txt b/std/src/sys/pal/windows/c/bindings.txt index 248ce3c9ff624..d98e90eedfec8 100644 --- a/std/src/sys/pal/windows/c/bindings.txt +++ b/std/src/sys/pal/windows/c/bindings.txt @@ -2295,6 +2295,7 @@ Windows.Win32.Storage.FileSystem.FILE_NAME_OPENED Windows.Win32.Storage.FileSystem.FILE_READ_ATTRIBUTES Windows.Win32.Storage.FileSystem.FILE_READ_DATA Windows.Win32.Storage.FileSystem.FILE_READ_EA +Windows.Win32.Storage.FileSystem.FILE_RENAME_INFO Windows.Win32.Storage.FileSystem.FILE_SHARE_DELETE Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE Windows.Win32.Storage.FileSystem.FILE_SHARE_NONE @@ -2603,5 +2604,7 @@ Windows.Win32.System.Threading.WaitForMultipleObjects Windows.Win32.System.Threading.WaitForSingleObject Windows.Win32.System.Threading.WakeAllConditionVariable Windows.Win32.System.Threading.WakeConditionVariable +Windows.Win32.System.WindowsProgramming.FILE_RENAME_FLAG_POSIX_SEMANTICS +Windows.Win32.System.WindowsProgramming.FILE_RENAME_FLAG_REPLACE_IF_EXISTS Windows.Win32.System.WindowsProgramming.PROGRESS_CONTINUE Windows.Win32.UI.Shell.GetUserProfileDirectoryW diff --git a/std/src/sys/pal/windows/c/windows_sys.rs b/std/src/sys/pal/windows/c/windows_sys.rs index 19925e59dfe9c..ed29f3d264ca4 100644 --- a/std/src/sys/pal/windows/c/windows_sys.rs +++ b/std/src/sys/pal/windows/c/windows_sys.rs @@ -2472,6 +2472,22 @@ pub const FILE_RANDOM_ACCESS: NTCREATEFILE_CREATE_OPTIONS = 2048u32; pub const FILE_READ_ATTRIBUTES: FILE_ACCESS_RIGHTS = 128u32; pub const FILE_READ_DATA: FILE_ACCESS_RIGHTS = 1u32; pub const FILE_READ_EA: FILE_ACCESS_RIGHTS = 8u32; +pub const FILE_RENAME_FLAG_POSIX_SEMANTICS: u32 = 2u32; +pub const FILE_RENAME_FLAG_REPLACE_IF_EXISTS: u32 = 1u32; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct FILE_RENAME_INFO { + pub Anonymous: FILE_RENAME_INFO_0, + pub RootDirectory: HANDLE, + pub FileNameLength: u32, + pub FileName: [u16; 1], +} +#[repr(C)] +#[derive(Clone, Copy)] +pub union FILE_RENAME_INFO_0 { + pub ReplaceIfExists: BOOLEAN, + pub Flags: u32, +} pub const FILE_RESERVE_OPFILTER: NTCREATEFILE_CREATE_OPTIONS = 1048576u32; pub const FILE_SEQUENTIAL_ONLY: NTCREATEFILE_CREATE_OPTIONS = 4u32; pub const FILE_SESSION_AWARE: NTCREATEFILE_CREATE_OPTIONS = 262144u32; diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 5bdd5f81b9c3d..85ad773ca8095 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -1,5 +1,6 @@ use super::api::{self, WinError}; use super::{IoResult, to_u16s}; +use crate::alloc::{alloc, handle_alloc_error}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; @@ -1223,7 +1224,149 @@ pub fn unlink(p: &Path) -> io::Result<()> { pub fn rename(old: &Path, new: &Path) -> io::Result<()> { let old = maybe_verbatim(old)?; let new = maybe_verbatim(new)?; - cvt(unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) })?; + + let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap(); + + let struct_size = mem::size_of::() - mem::size_of::() + + new.len() * mem::size_of::(); + + let struct_size: u32 = struct_size.try_into().unwrap(); + + let create_file = |extra_access, extra_flags| { + let handle = unsafe { + HandleOrInvalid::from_raw_handle(c::CreateFileW( + old.as_ptr(), + c::SYNCHRONIZE | c::DELETE | extra_access, + c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE, + ptr::null(), + c::OPEN_EXISTING, + c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags, + ptr::null_mut(), + )) + }; + + OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error()) + }; + + // The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly. + // If `old` refers to a mount point, we move it instead of the target. + let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) { + Ok(handle) => { + let mut file_attribute_tag_info: MaybeUninit = + MaybeUninit::uninit(); + + let result = unsafe { + cvt(c::GetFileInformationByHandleEx( + handle.as_raw_handle(), + c::FileAttributeTagInfo, + file_attribute_tag_info.as_mut_ptr().cast(), + mem::size_of::().try_into().unwrap(), + )) + }; + + if let Err(err) = result { + if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) + || err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _) + { + // `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes. + // Since we know we passed the correct arguments, this means the underlying driver didn't understand our request; + // `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior. + None + } else { + Some(Err(err)) + } + } else { + // SAFETY: The struct has been initialized by GetFileInformationByHandleEx + let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() }; + + if file_attribute_tag_info.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 + && file_attribute_tag_info.ReparseTag != c::IO_REPARSE_TAG_MOUNT_POINT + { + // The file is not a mount point: Reopen the file without inhibiting reparse point behavior. + None + } else { + // The file is a mount point: Don't reopen the file so that the mount point gets renamed. + Some(Ok(handle)) + } + } + } + // The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it. + Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None, + Err(err) => Some(Err(err)), + } + .unwrap_or_else(|| create_file(0, 0))?; + + // The last field of FILE_RENAME_INFO, the file name, is unsized. + // Therefore we need to subtract the size of one wide char. + let layout = core::alloc::Layout::from_size_align( + struct_size as _, + mem::align_of::(), + ) + .unwrap(); + + let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO; + + if file_rename_info.is_null() { + handle_alloc_error(layout); + } + + // SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator. + let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) }; + + // SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename. + unsafe { + (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { + // Don't bother with FileRenameInfo on Windows 7 since it doesn't exist. + #[cfg(not(target_vendor = "win7"))] + Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, + #[cfg(target_vendor = "win7")] + ReplaceIfExists: 1, + }); + + (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); + (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); + + new.as_ptr() + .copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len()); + } + + #[cfg(not(target_vendor = "win7"))] + const FileInformationClass: c::FILE_INFO_BY_HANDLE_CLASS = c::FileRenameInfoEx; + #[cfg(target_vendor = "win7")] + const FileInformationClass: c::FILE_INFO_BY_HANDLE_CLASS = c::FileRenameInfo; + + // We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`. + let result = unsafe { + cvt(c::SetFileInformationByHandle( + handle.as_raw_handle(), + FileInformationClass, + (&raw const *file_rename_info).cast::(), + struct_size, + )) + }; + + #[cfg(not(target_vendor = "win7"))] + if let Err(err) = result { + if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) { + // FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo. + file_rename_info.Anonymous.ReplaceIfExists = 1; + + cvt(unsafe { + c::SetFileInformationByHandle( + handle.as_raw_handle(), + c::FileRenameInfo, + (&raw const *file_rename_info).cast::(), + struct_size, + ) + })?; + } else { + return Err(err); + } + } + + #[cfg(target_vendor = "win7")] + result?; + Ok(()) } From 65326ce8fd775c5a4b30318854af336380a818e4 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Mon, 30 Sep 2024 19:49:18 +0200 Subject: [PATCH 173/481] Win: Add test cases for renaming a directory while the target file is opened and for renaming over a non-empty directory --- std/src/fs/tests.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 018e19586418e..0308a5f433a99 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -1912,3 +1912,44 @@ fn test_hidden_file_truncation() { let metadata = file.metadata().unwrap(); assert_eq!(metadata.len(), 0); } + +#[cfg(windows)] +#[test] +fn test_rename_file_over_open_file() { + // Make sure that std::fs::rename works if the target file is already opened with FILE_SHARE_DELETE. See #123985. + let tmpdir = tmpdir(); + + // Create source with test data to read. + let source_path = tmpdir.join("source_file.txt"); + fs::write(&source_path, b"source hello world").unwrap(); + + // Create target file with test data to read; + let target_path = tmpdir.join("target_file.txt"); + fs::write(&target_path, b"target hello world").unwrap(); + + // Open target file + let target_file = fs::File::open(&target_path).unwrap(); + + // Rename source + fs::rename(source_path, &target_path).unwrap(); + + core::mem::drop(target_file); + assert_eq!(fs::read(target_path).unwrap(), b"source hello world"); +} + +#[test] +#[cfg(windows)] +fn test_rename_directory_to_non_empty_directory() { + // Renaming a directory over a non-empty existing directory should fail on Windows. + let tmpdir: TempDir = tmpdir(); + + let source_path = tmpdir.join("source_directory"); + let target_path = tmpdir.join("target_directory"); + + fs::create_dir(&source_path).unwrap(); + fs::create_dir(&target_path).unwrap(); + + fs::write(target_path.join("target_file.txt"), b"target hello world").unwrap(); + + error!(fs::rename(source_path, target_path), 145); // ERROR_DIR_NOT_EMPTY +} From f1deb6ed94ce9fc8e0e1685428140da42be3be24 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Thu, 17 Oct 2024 00:27:46 +0200 Subject: [PATCH 174/481] Win: Remove special casing of the win7 target for `std::fs::rename` --- std/src/sys/pal/windows/fs.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 85ad773ca8095..2d584ec051401 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -1316,11 +1316,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { // SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename. unsafe { (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { - // Don't bother with FileRenameInfo on Windows 7 since it doesn't exist. - #[cfg(not(target_vendor = "win7"))] Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, - #[cfg(target_vendor = "win7")] - ReplaceIfExists: 1, }); (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); @@ -1330,22 +1326,16 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { .copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len()); } - #[cfg(not(target_vendor = "win7"))] - const FileInformationClass: c::FILE_INFO_BY_HANDLE_CLASS = c::FileRenameInfoEx; - #[cfg(target_vendor = "win7")] - const FileInformationClass: c::FILE_INFO_BY_HANDLE_CLASS = c::FileRenameInfo; - // We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`. let result = unsafe { cvt(c::SetFileInformationByHandle( handle.as_raw_handle(), - FileInformationClass, + c::FileRenameInfoEx, (&raw const *file_rename_info).cast::(), struct_size, )) }; - #[cfg(not(target_vendor = "win7"))] if let Err(err) = result { if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) { // FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo. @@ -1364,9 +1354,6 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { } } - #[cfg(target_vendor = "win7")] - result?; - Ok(()) } From a193ed9edb6c6a9d7a0fd02528edac87720231c3 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Tue, 29 Oct 2024 14:14:06 +0100 Subject: [PATCH 175/481] Win: rename: Use offset_of! in struct size calculation --- std/src/sys/pal/windows/fs.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 2d584ec051401..642be872dceb2 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -1227,8 +1227,13 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap(); - let struct_size = mem::size_of::() - mem::size_of::() - + new.len() * mem::size_of::(); + // The last field of FILE_RENAME_INFO, the file name, is unsized, + // and FILE_RENAME_INFO has two padding bytes. + // Therefore we need to make sure to not allocate less than + // size_of::() bytes, which would be the case with + // 0 or 1 character paths + a null byte. + let struct_size = mem::size_of::() + .max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * mem::size_of::()); let struct_size: u32 = struct_size.try_into().unwrap(); @@ -1296,8 +1301,6 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { } .unwrap_or_else(|| create_file(0, 0))?; - // The last field of FILE_RENAME_INFO, the file name, is unsized. - // Therefore we need to subtract the size of one wide char. let layout = core::alloc::Layout::from_size_align( struct_size as _, mem::align_of::(), From 0587f3e44d1a7a8716679f46ae0b3c7a2e18429f Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Sun, 15 Dec 2024 12:37:14 +0700 Subject: [PATCH 176/481] Correctly document is_null CTFE behavior. The "panic in const if CTFE doesn't know the answer" behavior was discussed to be the desired behavior in #74939, and is currently how the function actually behaves. I intentionally wrote this documentation to allow for the possibility that a panic might not occur even if the pointer is out of bounds, because of #133700 and other potential changes in the future. --- core/src/ptr/const_ptr.rs | 19 +++++++++++-------- core/src/ptr/mut_ptr.rs | 19 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index ac905eceaa803..5cfebe31f7296 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -12,14 +12,17 @@ impl *const T { /// Therefore, two pointers that are null may still not compare equal to /// each other. /// - /// ## Behavior during const evaluation - /// - /// When this function is used during const evaluation, it may return `false` for pointers - /// that turn out to be null at runtime. Specifically, when a pointer to some memory - /// is offset beyond its bounds in such a way that the resulting pointer is null, - /// the function will still return `false`. There is no way for CTFE to know - /// the absolute position of that memory, so we cannot tell if the pointer is - /// null or not. + /// # Panics during const evaluation + /// + /// If this method is used during const evaluation, and `self` is a pointer + /// that is offset beyond the bounds of the memory it initially pointed to, + /// then there might not be enough information to determine whether the + /// pointer is null. This is because the absolute address in memory is not + /// known at compile time. If the nullness of the pointer cannot be + /// determined, this method will panic. + /// + /// In-bounds pointers are never null, so the method will never panic for + /// such pointers. /// /// # Examples /// diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 3639feaacf3ab..c0f6f5b3ac51d 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -12,14 +12,17 @@ impl *mut T { /// Therefore, two pointers that are null may still not compare equal to /// each other. /// - /// ## Behavior during const evaluation - /// - /// When this function is used during const evaluation, it may return `false` for pointers - /// that turn out to be null at runtime. Specifically, when a pointer to some memory - /// is offset beyond its bounds in such a way that the resulting pointer is null, - /// the function will still return `false`. There is no way for CTFE to know - /// the absolute position of that memory, so we cannot tell if the pointer is - /// null or not. + /// # Panics during const evaluation + /// + /// If this method is used during const evaluation, and `self` is a pointer + /// that is offset beyond the bounds of the memory it initially pointed to, + /// then there might not be enough information to determine whether the + /// pointer is null. This is because the absolute address in memory is not + /// known at compile time. If the nullness of the pointer cannot be + /// determined, this method will panic. + /// + /// In-bounds pointers are never null, so the method will never panic for + /// such pointers. /// /// # Examples /// From 453dec419f249d81bc935c80442575f13a5e6def Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Sat, 21 Dec 2024 16:32:47 +0700 Subject: [PATCH 177/481] Document CTFE behavior of methods that call is_null --- core/src/ptr/const_ptr.rs | 21 ++++++++++++++++++++ core/src/ptr/mut_ptr.rs | 41 +++++++++++++++++++++++++++++++++++++++ core/src/ptr/non_null.rs | 7 +++++++ 3 files changed, 69 insertions(+) diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 5cfebe31f7296..ec569291853a5 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -257,6 +257,13 @@ impl *const T { /// When calling this method, you have to ensure that *either* the pointer is null *or* /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null + /// /// # Examples /// /// ``` @@ -334,6 +341,13 @@ impl *const T { /// When calling this method, you have to ensure that *either* the pointer is null *or* /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null + /// /// # Examples /// /// ``` @@ -1610,6 +1624,13 @@ impl *const [T] { /// /// [valid]: crate::ptr#safety /// [allocated object]: crate::ptr#allocated-object + /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index c0f6f5b3ac51d..34567917b523a 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -246,6 +246,13 @@ impl *mut T { /// When calling this method, you have to ensure that *either* the pointer is null *or* /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null-1 + /// /// # Examples /// /// ``` @@ -330,6 +337,13 @@ impl *mut T { /// Note that because the created reference is to `MaybeUninit`, the /// source pointer can point to uninitialized memory. /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null-1 + /// /// # Examples /// /// ``` @@ -593,6 +607,12 @@ impl *mut T { /// the pointer is null *or* /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null-1 /// /// # Examples /// @@ -676,6 +696,13 @@ impl *mut T { /// /// When calling this method, you have to ensure that *either* the pointer is null *or* /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). + /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null-1 #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit> @@ -1952,6 +1979,13 @@ impl *mut [T] { /// /// [valid]: crate::ptr#safety /// [allocated object]: crate::ptr#allocated-object + /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null-1 #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit]> { @@ -2003,6 +2037,13 @@ impl *mut [T] { /// /// [valid]: crate::ptr#safety /// [allocated object]: crate::ptr#allocated-object + /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: #method.is_null-1 #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit]> { diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 6b601405e1c2a..3eeb9129347f5 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -204,6 +204,13 @@ impl NonNull { /// Creates a new `NonNull` if `ptr` is non-null. /// + /// # Panics during const evaluation + /// + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. See [`is_null`] for more information. + /// + /// [`is_null`]: ../primitive.pointer.html#method.is_null-1 + /// /// # Examples /// /// ``` From 3a7edb46d6d1515c1e57902029f3ed368f9f31f1 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Mon, 23 Sep 2024 00:10:18 -0400 Subject: [PATCH 178/481] Add new implementation benchmark Add LONG benchmarks for more comparison between the methods --- core/benches/ascii/is_ascii.rs | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/core/benches/ascii/is_ascii.rs b/core/benches/ascii/is_ascii.rs index 4b2920c5eb45f..417d3e0fcbfe7 100644 --- a/core/benches/ascii/is_ascii.rs +++ b/core/benches/ascii/is_ascii.rs @@ -10,9 +10,12 @@ macro_rules! benches { // Ensure we benchmark cases where the functions are called with strings // that are not perfectly aligned or have a length which is not a // multiple of size_of::() (or both) - benches!(mod unaligned_head MEDIUM[1..] $($name $arg $body)+); - benches!(mod unaligned_tail MEDIUM[..(MEDIUM.len() - 1)] $($name $arg $body)+); - benches!(mod unaligned_both MEDIUM[1..(MEDIUM.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_head_medium MEDIUM[1..] $($name $arg $body)+); + benches!(mod unaligned_tail_medium MEDIUM[..(MEDIUM.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_both_medium MEDIUM[1..(MEDIUM.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_head_long LONG[1..] $($name $arg $body)+); + benches!(mod unaligned_tail_long LONG[..(LONG.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_both_long LONG[1..(LONG.len() - 1)] $($name $arg $body)+); }; (mod $mod_name: ident $input: ident [$range: expr] $($name: ident $arg: ident $body: block)+) => { @@ -49,6 +52,42 @@ benches! { fn case03_align_to_unrolled(bytes: &[u8]) { is_ascii_align_to_unrolled(bytes) } + + fn case04_while_loop(bytes: &[u8]) { + // Constant chosen to enable `pmovmskb` instruction on x86-64 + const N: usize = 32; + + let mut i = 0; + + while i + N <= bytes.len() { + let chunk_end = i + N; + + // Get LLVM to produce a `pmovmskb` instruction on x86-64 which + // creates a mask from the most significant bit of each byte. + // ASCII bytes are less than 128 (0x80), so their most significant + // bit is unset. Thus, detecting non-ASCII bytes can be done in one + // instruction. + let mut count = 0; + while i < chunk_end { + count += (bytes[i] <= 127) as u8; + i += 1; + } + + // All bytes should be <= 127 so count is equal to chunk size. + if count != N as u8 { + return false; + } + } + + // Process the remaining `bytes.len() % N` bytes. + let mut is_ascii = true; + while i < bytes.len() { + is_ascii &= bytes[i] <= 127; + i += 1; + } + + is_ascii + } } // These are separate since it's easier to debug errors if they don't go through From f8c0112d16e04c1cee577aa87e6ad755b0547450 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Thu, 26 Sep 2024 19:39:14 -0400 Subject: [PATCH 179/481] Add `is_ascii` function optimized for x86-64 for [u8] The new `is_ascii` function is optimized to use the `pmovmskb` vector instruction which tests the high bit in a lane. This corresponds to the same check of whether a byte is ASCII so ASCII validity checking can be vectorized. This instruction does not exist on other platforms so it is likely to regress performance and is gated to all(target_arch = "x86_64", target_feature = "sse2"). Add codegen test Remove crate::mem import for functions included in the prelude --- core/benches/ascii/is_ascii.rs | 20 +++++----- core/src/slice/ascii.rs | 70 ++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/core/benches/ascii/is_ascii.rs b/core/benches/ascii/is_ascii.rs index 417d3e0fcbfe7..ced7084fb0e48 100644 --- a/core/benches/ascii/is_ascii.rs +++ b/core/benches/ascii/is_ascii.rs @@ -54,27 +54,29 @@ benches! { } fn case04_while_loop(bytes: &[u8]) { - // Constant chosen to enable `pmovmskb` instruction on x86-64 - const N: usize = 32; + // Process chunks of 32 bytes at a time in the fast path to enable + // auto-vectorization and use of `pmovmskb`. Two 128-bit vector registers + // can be OR'd together and then the resulting vector can be tested for + // non-ASCII bytes. + const CHUNK_SIZE: usize = 32; let mut i = 0; - while i + N <= bytes.len() { - let chunk_end = i + N; + while i + CHUNK_SIZE <= bytes.len() { + let chunk_end = i + CHUNK_SIZE; // Get LLVM to produce a `pmovmskb` instruction on x86-64 which // creates a mask from the most significant bit of each byte. // ASCII bytes are less than 128 (0x80), so their most significant - // bit is unset. Thus, detecting non-ASCII bytes can be done in one - // instruction. + // bit is unset. let mut count = 0; while i < chunk_end { - count += (bytes[i] <= 127) as u8; + count += bytes[i].is_ascii() as u8; i += 1; } // All bytes should be <= 127 so count is equal to chunk size. - if count != N as u8 { + if count != CHUNK_SIZE as u8 { return false; } } @@ -82,7 +84,7 @@ benches! { // Process the remaining `bytes.len() % N` bytes. let mut is_ascii = true; while i < bytes.len() { - is_ascii &= bytes[i] <= 127; + is_ascii &= bytes[i].is_ascii(); i += 1; } diff --git a/core/src/slice/ascii.rs b/core/src/slice/ascii.rs index 7cdb896586f13..51b25fa40e3d9 100644 --- a/core/src/slice/ascii.rs +++ b/core/src/slice/ascii.rs @@ -3,8 +3,9 @@ use core::ascii::EscapeDefault; use crate::fmt::{self, Write}; +#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] use crate::intrinsics::const_eval_select; -use crate::{ascii, iter, mem, ops}; +use crate::{ascii, iter, ops}; #[cfg(not(test))] impl [u8] { @@ -328,14 +329,6 @@ impl<'a> fmt::Debug for EscapeAscii<'a> { } } -/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed -/// from `../str/mod.rs`, which does something similar for utf8 validation. -#[inline] -const fn contains_nonascii(v: usize) -> bool { - const NONASCII_MASK: usize = usize::repeat_u8(0x80); - (NONASCII_MASK & v) != 0 -} - /// ASCII test *without* the chunk-at-a-time optimizations. /// /// This is carefully structured to produce nice small code -- it's smaller in @@ -366,6 +359,7 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool { /// /// If any of these loads produces something for which `contains_nonascii` /// (above) returns true, then we know the answer is false. +#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior const fn is_ascii(s: &[u8]) -> bool { @@ -376,7 +370,14 @@ const fn is_ascii(s: &[u8]) -> bool { if const { is_ascii_simple(s) } else { - const USIZE_SIZE: usize = mem::size_of::(); + /// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed + /// from `../str/mod.rs`, which does something similar for utf8 validation. + const fn contains_nonascii(v: usize) -> bool { + const NONASCII_MASK: usize = usize::repeat_u8(0x80); + (NONASCII_MASK & v) != 0 + } + + const USIZE_SIZE: usize = size_of::(); let len = s.len(); let align_offset = s.as_ptr().align_offset(USIZE_SIZE); @@ -386,7 +387,7 @@ const fn is_ascii(s: &[u8]) -> bool { // // We also do this for architectures where `size_of::()` isn't // sufficient alignment for `usize`, because it's a weird edge case. - if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { + if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < align_of::() { return is_ascii_simple(s); } @@ -420,7 +421,7 @@ const fn is_ascii(s: &[u8]) -> bool { // have alignment information it should have given a `usize::MAX` for // `align_offset` earlier, sending things through the scalar path instead of // this one, so this check should pass if it's reachable. - debug_assert!(word_ptr.is_aligned_to(mem::align_of::())); + debug_assert!(word_ptr.is_aligned_to(align_of::())); // Read subsequent words until the last aligned word, excluding the last // aligned word by itself to be done in tail check later, to ensure that @@ -455,3 +456,48 @@ const fn is_ascii(s: &[u8]) -> bool { } ) } + +/// ASCII test optimized to use the `pmovmskb` instruction available on `x86-64` +/// platforms. +/// +/// Other platforms are not likely to benefit from this code structure, so they +/// use SWAR techniques to test for ASCII in `usize`-sized chunks. +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +#[inline] +const fn is_ascii(bytes: &[u8]) -> bool { + // Process chunks of 32 bytes at a time in the fast path to enable + // auto-vectorization and use of `pmovmskb`. Two 128-bit vector registers + // can be OR'd together and then the resulting vector can be tested for + // non-ASCII bytes. + const CHUNK_SIZE: usize = 32; + + let mut i = 0; + + while i + CHUNK_SIZE <= bytes.len() { + let chunk_end = i + CHUNK_SIZE; + + // Get LLVM to produce a `pmovmskb` instruction on x86-64 which + // creates a mask from the most significant bit of each byte. + // ASCII bytes are less than 128 (0x80), so their most significant + // bit is unset. + let mut count = 0; + while i < chunk_end { + count += bytes[i].is_ascii() as u8; + i += 1; + } + + // All bytes should be <= 127 so count is equal to chunk size. + if count != CHUNK_SIZE as u8 { + return false; + } + } + + // Process the remaining `bytes.len() % N` bytes. + let mut is_ascii = true; + while i < bytes.len() { + is_ascii &= bytes[i].is_ascii(); + i += 1; + } + + is_ascii +} From 4c0fb0ca0cd76903d92ec02761151a074791f8d9 Mon Sep 17 00:00:00 2001 From: Yusuf Bham Date: Sat, 21 Dec 2024 15:35:33 -0500 Subject: [PATCH 180/481] Use `&raw` for `ptr` primitive docs --- core/src/primitive_docs.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/primitive_docs.rs b/core/src/primitive_docs.rs index e105ceadff757..c5f029363e589 100644 --- a/core/src/primitive_docs.rs +++ b/core/src/primitive_docs.rs @@ -563,11 +563,11 @@ impl () {} /// Note that here the call to [`drop`] is for clarity - it indicates /// that we are done with the given value and it should be destroyed. /// -/// ## 3. Create it using `ptr::addr_of!` +/// ## 3. Create it using `&raw` /// -/// Instead of coercing a reference to a raw pointer, you can use the macros -/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`). -/// These macros allow you to create raw pointers to fields to which you cannot +/// Instead of coercing a reference to a raw pointer, you can use the raw borrow +/// operators `&raw const` (for `*const T`) and `&raw mut` (for `*mut T`). +/// These operators allow you to create raw pointers to fields to which you cannot /// create a reference (without causing undefined behavior), such as an /// unaligned field. This might be necessary if packed structs or uninitialized /// memory is involved. @@ -580,7 +580,7 @@ impl () {} /// unaligned: u32, /// } /// let s = S::default(); -/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion +/// let p = &raw const s.unaligned; // not allowed with coercion /// ``` /// /// ## 4. Get it from C. From f63d9260cfadde5b9a45b0b30db87578ddd14519 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 20 Dec 2024 14:58:37 -0800 Subject: [PATCH 181/481] Document `PointerLike` implementation restrictions. --- core/src/marker.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index 3d79706f8ecf9..d0d8609f43f08 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -982,8 +982,14 @@ pub trait Tuple {} /// A marker for pointer-like types. /// -/// This trait can only be implemented for types that have the same size and alignment -/// as a `usize` or `*const ()`. +/// 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( From 08c5694a7759c988513fec311094750502bd8c8d Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sun, 15 Dec 2024 15:44:56 +0800 Subject: [PATCH 182/481] Asserts the maximum value that can be returned from `Vec::len` --- alloc/src/vec/mod.rs | 11 +++++++++-- core/src/mem/mod.rs | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 55496005f4088..3a706d5f36b7f 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -56,7 +56,6 @@ #[cfg(not(no_global_oom_handling))] use core::cmp; use core::cmp::Ordering; -use core::fmt; use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter; @@ -65,6 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; +use core::{fmt, intrinsics}; #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] pub use self::extract_if::ExtractIf; @@ -2680,7 +2680,14 @@ impl Vec { #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { - self.len + let len = self.len; + + // SAFETY: The maximum capacity of `Vec` is `isize::MAX` bytes, so the maximum value can + // be returned is `usize::checked_div(mem::size_of::()).unwrap_or(usize::MAX)`, which + // matches the definition of `T::MAX_SLICE_LEN`. + unsafe { intrinsics::assume(len <= T::MAX_SLICE_LEN) }; + + len } /// Returns `true` if the vector contains no elements. diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 78ad6880709fb..57acc9dcd6ee7 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -1241,6 +1241,17 @@ pub trait SizedTypeProperties: Sized { #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] const LAYOUT: Layout = Layout::new::(); + + /// The largest safe length for a `[Self]`. + /// + /// Anything larger than this would make `size_of_val` overflow `isize::MAX`, + /// which is never allowed for a single object. + #[doc(hidden)] + #[unstable(feature = "sized_type_properties", issue = "none")] + const MAX_SLICE_LEN: usize = match size_of::() { + 0 => usize::MAX, + n => (isize::MAX as usize) / n, + }; } #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] From fc6211677ea450b6100b227c2d7c2508c02c32c0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 13 Dec 2024 17:43:16 -0800 Subject: [PATCH 183/481] Delete `Rvalue::Len` Everything's moved to `PtrMetadata` instead. --- core/src/intrinsics/mir.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/intrinsics/mir.rs b/core/src/intrinsics/mir.rs index 55dcf7cd47e97..834f44c7790d9 100644 --- a/core/src/intrinsics/mir.rs +++ b/core/src/intrinsics/mir.rs @@ -233,7 +233,7 @@ //! //! - Operands implicitly convert to `Use` rvalues. //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. -//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions. +//! - [`Discriminant`] and [`CopyForDeref`] have associated functions. //! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. //! - The binary operation `Offset` can be created via [`Offset`]. //! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. @@ -401,7 +401,6 @@ define!("mir_storage_dead", fn StorageDead(local: T)); define!("mir_assume", fn Assume(operand: bool)); define!("mir_deinit", fn Deinit(place: T)); define!("mir_checked", fn Checked(binop: T) -> (T, bool)); -define!("mir_len", fn Len(place: T) -> usize); define!( "mir_ptr_metadata", fn PtrMetadata(place: *const P) ->

::Metadata From 50503f330998603868f18e30794537f4750694d7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Dec 2024 00:22:56 +0000 Subject: [PATCH 184/481] cargo update compiler & tools dependencies: Locking 15 packages to latest compatible versions Updating clap_complete v4.5.39 -> v4.5.40 Updating env_filter v0.1.2 -> v0.1.3 Updating env_logger v0.11.5 -> v0.11.6 Updating expect-test v1.5.0 -> v1.5.1 Updating foldhash v0.1.3 -> v0.1.4 Updating miniz_oxide v0.8.1 -> v0.8.2 Updating object v0.36.5 -> v0.36.7 Updating serde_json v1.0.133 -> v1.0.134 Updating thiserror v2.0.7 -> v2.0.9 Updating thiserror-impl v2.0.7 -> v2.0.9 Updating tinyvec v1.8.0 -> v1.8.1 Updating wasm-encoder v0.221.2 -> v0.222.0 Removing wasmparser v0.218.0 Removing wasmparser v0.221.2 Adding wasmparser v0.222.0 Updating wast v221.0.2 -> v222.0.0 Updating wat v1.221.2 -> v1.222.0 note: pass `--verbose` to see 35 unchanged dependencies behind latest library dependencies: Locking 1 package to latest compatible version Updating object v0.36.5 -> v0.36.7 note: pass `--verbose` to see 6 unchanged dependencies behind latest rustbook dependencies: Locking 9 packages to latest compatible versions Updating cc v1.2.0 -> v1.2.5 Updating clap_complete v4.5.39 -> v4.5.40 Updating env_filter v0.1.2 -> v0.1.3 Updating env_logger v0.11.5 -> v0.11.6 Updating libc v0.2.168 -> v0.2.169 Updating miniz_oxide v0.8.1 -> v0.8.2 Updating serde_json v1.0.133 -> v1.0.134 Updating thiserror v2.0.7 -> v2.0.9 Updating thiserror-impl v2.0.7 -> v2.0.9 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2026cd584ccb8..22f6e1edf21ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "compiler_builtins", "memchr", From 1050d705e7c898e36ecd25e88c0cb631e1c2931c Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Fri, 13 Sep 2024 01:14:22 +0300 Subject: [PATCH 185/481] docs: Permissions.readonly() also ignores root user special permissions The root user can write to files without any (write) access bits set. But this is not taken into account by `std::fs::Permissions.readonly()`. --- std/src/fs.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 0178691c0e551..9b752ed14437c 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -1869,8 +1869,10 @@ impl Permissions { /// /// # Note /// - /// This function does not take Access Control Lists (ACLs) or Unix group - /// membership into account. + /// This function does not take Access Control Lists (ACLs), Unix group + /// membership and other nuances into account. + /// Therefore the return value of this function cannot be relied upon + /// to predict whether attempts to read or write the file will actually succeed. /// /// # Windows /// @@ -1885,10 +1887,13 @@ impl Permissions { /// # Unix (including macOS) /// /// On Unix-based platforms this checks if *any* of the owner, group or others - /// write permission bits are set. It does not check if the current - /// user is in the file's assigned group. It also does not check ACLs. - /// Therefore the return value of this function cannot be relied upon - /// to predict whether attempts to read or write the file will actually succeed. + /// write permission bits are set. It does not consider anything else, including: + /// + /// * Whether the current user is in the file's assigned group. + /// * Permissions granted by ACL. + /// * That `root` user can write to files that do not have any write bits set. + /// * Writable files on a filesystem that is mounted read-only. + /// /// The [`PermissionsExt`] trait gives direct access to the permission bits but /// also does not read ACLs. /// From 441a2c9ff3a91c00bfd001ca9b268dc6472faf4a Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 20 Dec 2024 19:20:23 +0100 Subject: [PATCH 186/481] docs: `transmute<&mut T, &mut MaybeUninit>` is unsound when exposed to safe code In the playground the example program terminates with an unpredictable exit code. The undefined behavior is also detected by miri: error: Undefined Behavior: using uninitialized data --- core/src/mem/maybe_uninit.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 9b3d690209856..58fb5be5812c8 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -232,6 +232,26 @@ use crate::{fmt, intrinsics, ptr, slice}; /// remain `#[repr(transparent)]`. That said, `MaybeUninit` will *always* guarantee that it has /// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that /// guarantee may evolve. +/// +/// Note that even though `T` and `MaybeUninit` are ABI compatible it is still unsound to +/// transmute `&mut T` to `&mut MaybeUninit` and expose that to safe code because it would allow +/// safe code to access uninitialized memory: +/// +/// ```rust,no_run +/// use core::mem::MaybeUninit; +/// +/// fn unsound_transmute(val: &mut T) -> &mut MaybeUninit { +/// unsafe { core::mem::transmute(val) } +/// } +/// +/// fn main() { +/// let mut code = 0; +/// let code = &mut code; +/// let code2 = unsound_transmute(code); +/// *code2 = MaybeUninit::uninit(); +/// std::process::exit(*code); // UB! Accessing uninitialized memory. +/// } +/// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] // Lang item so we can wrap other types in it. This is useful for coroutines. #[lang = "maybe_uninit"] From 7f74767d51095d2a0818c7bdcf9312aa109f7581 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sat, 21 Dec 2024 17:13:52 -0800 Subject: [PATCH 187/481] Implement `PointerLike` for `isize`, `NonNull`, `Cell`, `UnsafeCell`, and `SyncUnsafeCell`. Implementing `PointerLike` for `UnsafeCell` enables the possibility of interior mutable `dyn*` values. Since this means potentially exercising new codegen behavior, I added a test for it in `tests/ui/dyn-star/cell.rs`. Also updated UI tests to account for the `isize` implementation changing error messages. --- core/src/cell.rs | 11 ++++++++++- core/src/marker.rs | 1 + core/src/ptr/non_null.rs | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/src/cell.rs b/core/src/cell.rs index cfa4c1fb56479..306d565a77e66 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -252,7 +252,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; -use crate::marker::{PhantomData, Unsize}; +use crate::marker::{PhantomData, PointerLike, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::pin::PinCoerceUnsized; @@ -677,6 +677,9 @@ 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]>` /// @@ -2258,6 +2261,9 @@ 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` @@ -2364,6 +2370,9 @@ 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/core/src/marker.rs b/core/src/marker.rs index d0d8609f43f08..29fc01d37fe3f 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -1003,6 +1003,7 @@ pub trait PointerLike {} marker_impls! { #[unstable(feature = "pointer_like_trait", issue = "none")] PointerLike for + isize, usize, {T} &T, {T} &mut T, diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 3eeb9129347f5..e0ba469272ed1 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -1555,6 +1555,10 @@ impl DispatchFromDyn> for NonNull where T: U #[stable(feature = "pin", since = "1.33.0")] unsafe impl PinCoerceUnsized for NonNull {} +#[unstable(feature = "pointer_like_trait", issue = "none")] +#[cfg(not(bootstrap))] +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 { From 37c2ec6df6cb6bb9bd794a2c9a258232829a65d0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 22 Dec 2024 14:26:54 +1100 Subject: [PATCH 188/481] Revert "Auto merge of #130766 - clarfonthey:stable-coverage-attribute, r=wesleywiser" This reverts commit cd63cc68e5d11d2996acf12d0f8562de54142da4, reversing changes made to f23a80a4c2fbca593b64e70f5970368824b4c5e9. --- core/src/cmp.rs | 2 +- core/src/lib.rs | 2 +- core/src/macros/mod.rs | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/cmp.rs b/core/src/cmp.rs index 66a6578fc7268..5a3b9365cd220 100644 --- a/core/src/cmp.rs +++ b/core/src/cmp.rs @@ -348,7 +348,7 @@ pub trait Eq: PartialEq { #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] -#[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))] +#[allow_internal_unstable(coverage_attribute)] pub macro Eq($item:item) { /* compiler built-in */ } diff --git a/core/src/lib.rs b/core/src/lib.rs index 18bd9bb811836..a7f741a940896 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -107,13 +107,13 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(coverage_attribute))] #![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_eval_select)] #![feature(const_typed_swap)] #![feature(core_intrinsics)] +#![feature(coverage_attribute)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index bff7ad98df3fa..ab674b58902b5 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1673,8 +1673,7 @@ pub(crate) mod builtin { /// /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(test, rustc_attrs)] - #[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))] + #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] #[rustc_builtin_macro] pub macro test($item:item) { /* compiler built-in */ @@ -1687,8 +1686,7 @@ pub(crate) mod builtin { soft, reason = "`bench` is a part of custom test frameworks which are unstable" )] - #[allow_internal_unstable(test, rustc_attrs)] - #[cfg_attr(bootstrap, allow_internal_unstable(coverage_attribute))] + #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] #[rustc_builtin_macro] pub macro bench($item:item) { /* compiler built-in */ From e7aecaa03c85af002a7a1f06ca773ceaa98b8489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 11 Dec 2024 01:37:17 +0000 Subject: [PATCH 189/481] Use `#[derive(Default)]` instead of manually implementing it --- core/tests/hash/mod.rs | 15 +++------------ proc_macro/src/bridge/fxhash.rs | 8 +------- std/src/panicking.rs | 9 ++------- std/src/sys_common/process.rs | 8 +------- 4 files changed, 7 insertions(+), 33 deletions(-) diff --git a/core/tests/hash/mod.rs b/core/tests/hash/mod.rs index bf91e9e5df0e2..9f14995f73fe2 100644 --- a/core/tests/hash/mod.rs +++ b/core/tests/hash/mod.rs @@ -4,16 +4,11 @@ use std::hash::{BuildHasher, Hash, Hasher}; use std::ptr; use std::rc::Rc; +#[derive(Default)] struct MyHasher { hash: u64, } -impl Default for MyHasher { - fn default() -> MyHasher { - MyHasher { hash: 0 } - } -} - impl Hasher for MyHasher { fn write(&mut self, buf: &[u8]) { for byte in buf { @@ -107,6 +102,8 @@ fn test_writer_hasher() { struct Custom { hash: u64, } + +#[derive(Default)] struct CustomHasher { output: u64, } @@ -123,12 +120,6 @@ impl Hasher for CustomHasher { } } -impl Default for CustomHasher { - fn default() -> CustomHasher { - CustomHasher { output: 0 } - } -} - impl Hash for Custom { fn hash(&self, state: &mut H) { state.write_u64(self.hash); diff --git a/proc_macro/src/bridge/fxhash.rs b/proc_macro/src/bridge/fxhash.rs index 74a41451825ff..3345e099a3724 100644 --- a/proc_macro/src/bridge/fxhash.rs +++ b/proc_macro/src/bridge/fxhash.rs @@ -22,6 +22,7 @@ pub type FxHashMap = HashMap>; /// out-performs an FNV-based hash within rustc itself -- the collision rate is /// similar or slightly worse than FNV, but the speed of the hash function /// itself is much higher because it works on up to 8 bytes at a time. +#[derive(Default)] pub struct FxHasher { hash: usize, } @@ -31,13 +32,6 @@ const K: usize = 0x9e3779b9; #[cfg(target_pointer_width = "64")] const K: usize = 0x517cc1b727220a95; -impl Default for FxHasher { - #[inline] - fn default() -> FxHasher { - FxHasher { hash: 0 } - } -} - impl FxHasher { #[inline] fn add_to_hash(&mut self, i: usize) { diff --git a/std/src/panicking.rs b/std/src/panicking.rs index dca5ccca0c404..e7ce5bc61401d 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -81,7 +81,9 @@ extern "C" fn __rust_foreign_exception() -> ! { rtabort!("Rust cannot catch foreign exceptions"); } +#[derive(Default)] enum Hook { + #[default] Default, Custom(Box) + 'static + Sync + Send>), } @@ -96,13 +98,6 @@ impl Hook { } } -impl Default for Hook { - #[inline] - fn default() -> Hook { - Hook::Default - } -} - static HOOK: RwLock = RwLock::new(Hook::Default); /// Registers a custom panic hook, replacing the previously registered hook. diff --git a/std/src/sys_common/process.rs b/std/src/sys_common/process.rs index 5333ee146f7d6..9f61d69d85875 100644 --- a/std/src/sys_common/process.rs +++ b/std/src/sys_common/process.rs @@ -8,19 +8,13 @@ use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes}; use crate::{env, fmt, io}; // Stores a set of changes to an environment -#[derive(Clone)] +#[derive(Clone, Default)] pub struct CommandEnv { clear: bool, saw_path: bool, vars: BTreeMap>, } -impl Default for CommandEnv { - fn default() -> Self { - CommandEnv { clear: false, saw_path: false, vars: Default::default() } - } -} - impl fmt::Debug for CommandEnv { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut debug_command_env = f.debug_struct("CommandEnv"); From 352a6559f92b47a9fb180caceefb90d262b1d90f Mon Sep 17 00:00:00 2001 From: Mostafa Khaled Date: Sun, 22 Dec 2024 21:38:23 +0200 Subject: [PATCH 190/481] Fixes safety docs for `dyn Any + Send {+ Sync}` --- core/src/any.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/core/src/any.rs b/core/src/any.rs index 58107b1e7d074..17d9455592787 100644 --- a/core/src/any.rs +++ b/core/src/any.rs @@ -423,7 +423,8 @@ impl dyn Any + Send { /// /// # Safety /// - /// Same as the method on the type `dyn Any`. + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &T { @@ -451,7 +452,8 @@ impl dyn Any + Send { /// /// # Safety /// - /// Same as the method on the type `dyn Any`. + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { @@ -552,6 +554,10 @@ impl dyn Any + Send + Sync { /// assert_eq!(*x.downcast_ref_unchecked::(), 1); /// } /// ``` + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &T { @@ -576,6 +582,10 @@ impl dyn Any + Send + Sync { /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); /// ``` + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { From 02a0d3c61a4f6fa3ae99a90dde9b2309523b9e26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Dec 2024 15:30:27 +0100 Subject: [PATCH 191/481] core: fix const ptr::swap_nonoverlapping when there are pointers at odd offsets in the type --- core/src/intrinsics/mod.rs | 14 ++++---- core/src/ptr/mod.rs | 73 ++++++++++++++++++++++---------------- core/tests/lib.rs | 1 + core/tests/ptr.rs | 63 ++++++++++++++++++++++++++------ 4 files changed, 103 insertions(+), 48 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 3e53c0497cc78..42b8eb33a1a95 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3795,7 +3795,7 @@ where /// See [`const_eval_select()`] for the rules and requirements around that intrinsic. pub(crate) macro const_eval_select { ( - @capture { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? : + @capture$([$($binders:tt)*])? { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? : if const $(#[$compiletime_attr:meta])* $compiletime:block else @@ -3803,7 +3803,7 @@ pub(crate) macro const_eval_select { ) => { // Use the `noinline` arm, after adding explicit `inline` attributes $crate::intrinsics::const_eval_select!( - @capture { $($arg : $ty = $val),* } $(-> $ret)? : + @capture$([$($binders)*])? { $($arg : $ty = $val),* } $(-> $ret)? : #[noinline] if const #[inline] // prevent codegen on this function @@ -3817,7 +3817,7 @@ pub(crate) macro const_eval_select { }, // With a leading #[noinline], we don't add inline attributes ( - @capture { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? : + @capture$([$($binders:tt)*])? { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? : #[noinline] if const $(#[$compiletime_attr:meta])* $compiletime:block @@ -3825,12 +3825,12 @@ pub(crate) macro const_eval_select { $(#[$runtime_attr:meta])* $runtime:block ) => {{ $(#[$runtime_attr])* - fn runtime($($arg: $ty),*) $( -> $ret )? { + fn runtime$(<$($binders)*>)?($($arg: $ty),*) $( -> $ret )? { $runtime } $(#[$compiletime_attr])* - const fn compiletime($($arg: $ty),*) $( -> $ret )? { + const fn compiletime$(<$($binders)*>)?($($arg: $ty),*) $( -> $ret )? { // Don't warn if one of the arguments is unused. $(let _ = $arg;)* @@ -3842,14 +3842,14 @@ pub(crate) macro const_eval_select { // We support leaving away the `val` expressions for *all* arguments // (but not for *some* arguments, that's too tricky). ( - @capture { $($arg:ident : $ty:ty),* $(,)? } $( -> $ret:ty )? : + @capture$([$($binders:tt)*])? { $($arg:ident : $ty:ty),* $(,)? } $( -> $ret:ty )? : if const $(#[$compiletime_attr:meta])* $compiletime:block else $(#[$runtime_attr:meta])* $runtime:block ) => { $crate::intrinsics::const_eval_select!( - @capture { $($arg : $ty = $arg),* } $(-> $ret)? : + @capture$([$($binders)*])? { $($arg : $ty = $arg),* } $(-> $ret)? : if const $(#[$compiletime_attr])* $compiletime else diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 1423e7ea8d10c..e6e13eaff7b0f 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -395,6 +395,7 @@ #![allow(clippy::not_unsafe_ptr_arg_deref)] use crate::cmp::Ordering; +use crate::intrinsics::const_eval_select; use crate::marker::FnPtr; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; use crate::{fmt, hash, intrinsics, ub_checks}; @@ -1074,25 +1075,6 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { #[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { - #[allow(unused)] - macro_rules! attempt_swap_as_chunks { - ($ChunkTy:ty) => { - if mem::align_of::() >= mem::align_of::<$ChunkTy>() - && mem::size_of::() % mem::size_of::<$ChunkTy>() == 0 - { - let x: *mut $ChunkTy = x.cast(); - let y: *mut $ChunkTy = y.cast(); - let count = count * (mem::size_of::() / mem::size_of::<$ChunkTy>()); - // SAFETY: these are the same bytes that the caller promised were - // ok, just typed as `MaybeUninit`s instead of as `T`s. - // The `if` condition above ensures that we're not violating - // alignment requirements, and that the division is exact so - // that we don't lose any bytes off the end. - return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }; - } - }; - } - ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \ @@ -1111,19 +1093,48 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { } ); - // Split up the slice into small power-of-two-sized chunks that LLVM is able - // to vectorize (unless it's a special type with more-than-pointer alignment, - // because we don't want to pessimize things like slices of SIMD vectors.) - if mem::align_of::() <= mem::size_of::() - && (!mem::size_of::().is_power_of_two() - || mem::size_of::() > mem::size_of::() * 2) - { - attempt_swap_as_chunks!(usize); - attempt_swap_as_chunks!(u8); - } + const_eval_select!( + @capture[T] { x: *mut T, y: *mut T, count: usize }: + if const { + // At compile-time we want to always copy this in chunks of `T`, to ensure that if there + // are pointers inside `T` we will copy them in one go rather than trying to copy a part + // of a pointer (which would not work). + // SAFETY: Same preconditions as this function + unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } + } else { + macro_rules! attempt_swap_as_chunks { + ($ChunkTy:ty) => { + if mem::align_of::() >= mem::align_of::<$ChunkTy>() + && mem::size_of::() % mem::size_of::<$ChunkTy>() == 0 + { + let x: *mut $ChunkTy = x.cast(); + let y: *mut $ChunkTy = y.cast(); + let count = count * (mem::size_of::() / mem::size_of::<$ChunkTy>()); + // SAFETY: these are the same bytes that the caller promised were + // ok, just typed as `MaybeUninit`s instead of as `T`s. + // The `if` condition above ensures that we're not violating + // alignment requirements, and that the division is exact so + // that we don't lose any bytes off the end. + return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }; + } + }; + } + + // Split up the slice into small power-of-two-sized chunks that LLVM is able + // to vectorize (unless it's a special type with more-than-pointer alignment, + // because we don't want to pessimize things like slices of SIMD vectors.) + if mem::align_of::() <= mem::size_of::() + && (!mem::size_of::().is_power_of_two() + || mem::size_of::() > mem::size_of::() * 2) + { + attempt_swap_as_chunks!(usize); + attempt_swap_as_chunks!(u8); + } - // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } + // SAFETY: Same preconditions as this function + unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } + } + ) } /// Same behavior and safety conditions as [`swap_nonoverlapping`] diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 89b65eefd027e..9f0ab7b3f2977 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -16,6 +16,7 @@ #![feature(const_black_box)] #![feature(const_eval_select)] #![feature(const_swap)] +#![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index 454b13a7ee389..e6825d8e39e2c 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -860,7 +860,10 @@ fn swap_copy_untyped() { } #[test] -fn test_const_copy() { +fn test_const_copy_ptr() { + // `copy` and `copy_nonoverlapping` are thin layers on top of intrinsics. Ensure they correctly + // deal with pointers even when the pointers cross the boundary from one "element" being copied + // to another. const { let ptr1 = &1; let mut ptr2 = &666; @@ -899,21 +902,61 @@ fn test_const_copy() { } #[test] -fn test_const_swap() { +fn test_const_swap_ptr() { + // The `swap` functions are implemented in the library, they are not primitives. + // Only `swap_nonoverlapping` takes a count; pointers that cross multiple elements + // are *not* supported. + // We put the pointer at an odd offset in the type and copy them as an array of bytes, + // which should catch most of the ways that the library implementation can get it wrong. + + #[cfg(target_pointer_width = "32")] + type HalfPtr = i16; + #[cfg(target_pointer_width = "64")] + type HalfPtr = i32; + + #[repr(C, packed)] + #[allow(unused)] + struct S { + f1: HalfPtr, + // Crucially this field is at an offset that is not a multiple of the pointer size. + ptr: &'static i32, + // Make sure the entire type does not have a power-of-2 size: + // make it 3 pointers in size. This used to hit a bug in `swap_nonoverlapping`. + f2: [HalfPtr; 3], + } + + // Ensure the entire thing is usize-aligned, so in principle this + // looks like it could be eligible for a `usize` copying loop. + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + struct A(S); + const { - let mut ptr1 = &1; - let mut ptr2 = &666; + let mut s1 = A(S { ptr: &1, f1: 0, f2: [0; 3] }); + let mut s2 = A(S { ptr: &666, f1: 0, f2: [0; 3] }); - // Swap ptr1 and ptr2, bytewise. `swap` does not take a count - // so the best we can do is use an array. - type T = [u8; mem::size_of::<&i32>()]; + // Swap ptr1 and ptr2, as an array. + type T = [u8; mem::size_of::()]; unsafe { - ptr::swap(ptr::from_mut(&mut ptr1).cast::(), ptr::from_mut(&mut ptr2).cast::()); + ptr::swap(ptr::from_mut(&mut s1).cast::(), ptr::from_mut(&mut s2).cast::()); } // Make sure they still work. - assert!(*ptr1 == 666); - assert!(*ptr2 == 1); + assert!(*s1.0.ptr == 666); + assert!(*s2.0.ptr == 1); + + // Swap them back, again as an array. + unsafe { + ptr::swap_nonoverlapping( + ptr::from_mut(&mut s1).cast::(), + ptr::from_mut(&mut s2).cast::(), + 1, + ); + } + + // Make sure they still work. + assert!(*s1.0.ptr == 1); + assert!(*s2.0.ptr == 666); }; } From 508a6c2fd6b5702f2e8ff58f5bc3e65f36c85da8 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 15 Dec 2024 09:59:15 +0100 Subject: [PATCH 192/481] Bump `stdarch` --- portable-simd/crates/core_simd/src/vendor/arm.rs | 13 ++----------- stdarch | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/portable-simd/crates/core_simd/src/vendor/arm.rs b/portable-simd/crates/core_simd/src/vendor/arm.rs index f8878d11f094d..3dc54481b6fd4 100644 --- a/portable-simd/crates/core_simd/src/vendor/arm.rs +++ b/portable-simd/crates/core_simd/src/vendor/arm.rs @@ -48,17 +48,6 @@ mod neon { from_transmute! { unsafe u64x2 => poly64x2_t } } -#[cfg(any( - all(target_feature = "v5te", not(target_feature = "mclass")), - all(target_feature = "mclass", target_feature = "dsp"), -))] -mod dsp { - use super::*; - - from_transmute! { unsafe Simd => uint16x2_t } - from_transmute! { unsafe Simd => int16x2_t } -} - #[cfg(any( all(target_feature = "v6", not(target_feature = "mclass")), all(target_feature = "mclass", target_feature = "dsp"), @@ -68,6 +57,8 @@ mod simd32 { from_transmute! { unsafe Simd => uint8x4_t } from_transmute! { unsafe Simd => int8x4_t } + from_transmute! { unsafe Simd => uint16x2_t } + from_transmute! { unsafe Simd => int16x2_t } } #[cfg(all( diff --git a/stdarch b/stdarch index e5e00aab0a8c8..684de0d6fef70 160000 --- a/stdarch +++ b/stdarch @@ -1 +1 @@ -Subproject commit e5e00aab0a8c8fa35fb7865e88fa82366f615c53 +Subproject commit 684de0d6fef708cae08214fef9643dd9ec7296e1 From fcd11af1ae03b79108c734301086534ac4fdd77c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 24 Dec 2024 11:04:12 +0000 Subject: [PATCH 193/481] Windows: Use FILE_ALLOCATION_INFO for truncation But fallback to FILE_END_OF_FILE_INFO for WINE --- std/src/sys/pal/windows/fs.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 642be872dceb2..dda4259919b6d 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -316,19 +316,31 @@ impl File { && api::get_last_error() == WinError::ALREADY_EXISTS { unsafe { - // This originally used `FileAllocationInfo` instead of - // `FileEndOfFileInfo` but that wasn't supported by WINE. - // It's arguable which fits the semantics of `OpenOptions` - // better so let's just use the more widely supported method. - let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; + // This first tries `FileAllocationInfo` but falls back to + // `FileEndOfFileInfo` in order to support WINE. + // If WINE gains support for FileAllocationInfo, we should + // remove the fallback. + let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), c::FileEndOfFileInfo, - (&raw const eof).cast::(), - mem::size_of::() as u32, + (&raw const alloc).cast::(), + mem::size_of::() as u32, ); if result == 0 { - return Err(io::Error::last_os_error()); + if api::get_last_error().code != 0 { + panic!("FILE_ALLOCATION_INFO failed!!!"); + } + let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; + let result = c::SetFileInformationByHandle( + handle.as_raw_handle(), + c::FileEndOfFileInfo, + (&raw const eof).cast::(), + mem::size_of::() as u32, + ); + if result == 0 { + return Err(io::Error::last_os_error()); + } } } } From 2b26cc9e461b4b927935b444e0ccfcf2898df629 Mon Sep 17 00:00:00 2001 From: oliveredget <188809800+oliveredget@users.noreply.github.com> Date: Tue, 24 Dec 2024 23:37:30 +0800 Subject: [PATCH 194/481] chore: fix typos --- core/src/macros/mod.rs | 2 +- core/src/str/lossy.rs | 4 ++-- core/tests/iter/adapters/take.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index ab674b58902b5..402b436d28e68 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1549,7 +1549,7 @@ pub(crate) mod builtin { /// NAME is a string that represents a valid function name. /// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst. /// INPUT_ACTIVITIES consists of one valid activity for each input parameter. - /// OUTPUT_ACTIVITY must not be set if we implicitely return nothing (or explicitely return + /// OUTPUT_ACTIVITY must not be set if we implicitly return nothing (or explicitly return /// `-> ()`). Otherwise it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] diff --git a/core/src/str/lossy.rs b/core/src/str/lossy.rs index e7677c8317a9f..ed2cefc59a51c 100644 --- a/core/src/str/lossy.rs +++ b/core/src/str/lossy.rs @@ -8,7 +8,7 @@ impl [u8] { /// Creates an iterator over the contiguous valid UTF-8 ranges of this /// slice, and the non-UTF-8 fragments in between. /// - /// See the [`Utf8Chunk`] type for documenation of the items yielded by this iterator. + /// See the [`Utf8Chunk`] type for documentation of the items yielded by this iterator. /// /// # Examples /// @@ -150,7 +150,7 @@ impl fmt::Debug for Debug<'_> { /// If you want a simple conversion from UTF-8 byte slices to string slices, /// [`from_utf8`] is easier to use. /// -/// See the [`Utf8Chunk`] type for documenation of the items yielded by this iterator. +/// See the [`Utf8Chunk`] type for documentation of the items yielded by this iterator. /// /// [byteslice]: slice /// [`from_utf8`]: super::from_utf8 diff --git a/core/tests/iter/adapters/take.rs b/core/tests/iter/adapters/take.rs index 65a8a93b4a916..b932059afec8a 100644 --- a/core/tests/iter/adapters/take.rs +++ b/core/tests/iter/adapters/take.rs @@ -255,7 +255,7 @@ fn test_reverse_on_zip() { let zipped_iter = vec_1.iter().zip(core::iter::repeat(0).take(20)); - // Cannot call rev here for automatic reversed zip constuction + // Cannot call rev here for automatic reversed zip construction for (&one, zero) in zipped_iter.rev() { assert_eq!((1, 0), (one, zero)); } From 75c911d6f71cae4d9e7b51eaa9a2dded7cabee43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Dec 2024 19:28:52 +0100 Subject: [PATCH 195/481] stabilize const_alloc_layout --- core/src/alloc/layout.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index d884fa69efbb0..e6f39db9dced3 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -178,8 +178,7 @@ impl Layout { /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[rustc_const_stable_indirect] + #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { @@ -253,8 +252,7 @@ impl Layout { /// Returns an error if the combination of `self.size()` and the given /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[rustc_const_stable_indirect] + #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn align_to(&self, align: usize) -> Result { if let Some(align) = Alignment::new(align) { @@ -329,8 +327,7 @@ impl Layout { /// This is equivalent to adding the result of `padding_needed_for` /// to the layout's current size. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[rustc_const_stable_indirect] + #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns a new `Layout`, \ without modifying the original"] #[inline] @@ -429,8 +426,7 @@ impl Layout { /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16]))); /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[rustc_const_stable_indirect] + #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = Alignment::max(self.align, next.align); @@ -493,8 +489,7 @@ impl Layout { /// On arithmetic overflow or when the total size would exceed /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] - #[rustc_const_stable_indirect] + #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn array(n: usize) -> Result { // Reduce the amount of code we need to monomorphize per `T`. From d23b8baee80016aa035720c2a80cd0bf83518cbe Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Thu, 26 Dec 2024 08:30:51 +0100 Subject: [PATCH 196/481] Fix formatting --- core/src/iter/traits/collect.rs | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index 8ab1c26f95e32..de090d2a50fad 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -629,7 +629,7 @@ macro_rules! spec_tuple_impl { } impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter - where + where $($extend_ty_names: Extend<$ty_names>,)* Iter: Iterator, { @@ -639,7 +639,7 @@ macro_rules! spec_tuple_impl { } impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter - where + where $($extend_ty_names: Extend<$ty_names>,)* Iter: TrustedLen, { @@ -647,29 +647,29 @@ macro_rules! spec_tuple_impl { fn extend<'a, $($ty_names,)*>( $($var_names: &'a mut impl Extend<$ty_names>,)* ) -> impl FnMut((), ($($ty_names,)*)) + 'a { - #[allow(non_snake_case)] - // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen` - // so its `size_hint` is exact. - move |(), ($($extend_ty_names,)*)| unsafe { - $($var_names.extend_one_unchecked($extend_ty_names);)* + #[allow(non_snake_case)] + // SAFETY: We reserve enough space for the `size_hint`, and the iterator is + // `TrustedLen` so its `size_hint` is exact. + move |(), ($($extend_ty_names,)*)| unsafe { + $($var_names.extend_one_unchecked($extend_ty_names);)* + } } - } - let (lower_bound, upper_bound) = self.size_hint(); + let (lower_bound, upper_bound) = self.size_hint(); - if upper_bound.is_none() { - // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. - $default_fn_name(self, $($var_names,)*); - return; - } + if upper_bound.is_none() { + // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. + $default_fn_name(self, $($var_names,)*); + return; + } - if lower_bound > 0 { - $($var_names.extend_reserve(lower_bound);)* - } + if lower_bound > 0 { + $($var_names.extend_reserve(lower_bound);)* + } - self.fold((), extend($($var_names,)*)); + self.fold((), extend($($var_names,)*)); + } } - } }; } From 1b2642e0df06d080242ed9a772ae6fa12b0b4950 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Thu, 26 Dec 2024 08:38:08 +0100 Subject: [PATCH 197/481] Impl FromIterator for tuples with arity 1-12 --- core/src/iter/traits/collect.rs | 68 +++++++++++++++--------------- core/tests/iter/traits/iterator.rs | 12 ++++++ 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index de090d2a50fad..73e6d93106096 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -152,39 +152,6 @@ pub trait FromIterator: Sized { fn from_iter>(iter: T) -> Self; } -/// This implementation turns an iterator of tuples into a tuple of types which implement -/// [`Default`] and [`Extend`]. -/// -/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`] -/// implementations: -/// -/// ```rust -/// # fn main() -> Result<(), core::num::ParseIntError> { -/// let string = "1,2,123,4"; -/// -/// let (numbers, lengths): (Vec<_>, Vec<_>) = string -/// .split(',') -/// .map(|s| s.parse().map(|n: u32| (n, s.len()))) -/// .collect::>()?; -/// -/// assert_eq!(numbers, [1, 2, 123, 4]); -/// assert_eq!(lengths, [1, 1, 3, 1]); -/// # Ok(()) } -/// ``` -#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")] -impl FromIterator<(AE, BE)> for (A, B) -where - A: Default + Extend, - B: Default + Extend, -{ - fn from_iter>(iter: I) -> Self { - let mut res = <(A, B)>::default(); - res.extend(iter); - - res - } -} - /// Conversion into an [`Iterator`]. /// /// By implementing `IntoIterator` for a type, you define how it will be @@ -671,6 +638,41 @@ macro_rules! spec_tuple_impl { } } + /// This implementation turns an iterator of tuples into a tuple of types which implement + /// [`Default`] and [`Extend`]. + /// + /// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`] + /// implementations: + /// + /// ```rust + /// # fn main() -> Result<(), core::num::ParseIntError> { + /// let string = "1,2,123,4"; + /// + /// // Example given for a 2-tuple, but 1- through 12-tuples are supported + /// let (numbers, lengths): (Vec<_>, Vec<_>) = string + /// .split(',') + /// .map(|s| s.parse().map(|n: u32| (n, s.len()))) + /// .collect::>()?; + /// + /// assert_eq!(numbers, [1, 2, 123, 4]); + /// assert_eq!(lengths, [1, 1, 3, 1]); + /// # Ok(()) } + /// ``` + #[$meta] + $(#[$doctext])? + #[stable(feature = "from_iterator_for_tuple", since = "1.79.0")] + impl<$($ty_names,)* $($extend_ty_names,)*> FromIterator<($($extend_ty_names,)*)> for ($($ty_names,)*) + where + $($ty_names: Default + Extend<$extend_ty_names>,)* + { + fn from_iter>(iter: Iter) -> Self { + let mut res = <($($ty_names,)*)>::default(); + res.extend(iter); + + res + } + } + }; } diff --git a/core/tests/iter/traits/iterator.rs b/core/tests/iter/traits/iterator.rs index 76f1e3319d42e..e31d2e15b6d7e 100644 --- a/core/tests/iter/traits/iterator.rs +++ b/core/tests/iter/traits/iterator.rs @@ -630,6 +630,18 @@ fn test_collect_into_tuples() { assert!(e.2 == d); } +#[test] +fn test_collect_for_tuples() { + let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; + let b = vec![1, 4, 7]; + let c = vec![2, 5, 8]; + let d = vec![3, 6, 9]; + let e: (Vec<_>, Vec<_>, Vec<_>) = a.into_iter().collect(); + assert!(e.0 == b); + assert!(e.1 == c); + assert!(e.2 == d); +} + // just tests by whether or not this compiles fn _empty_impl_all_auto_traits() { use std::panic::{RefUnwindSafe, UnwindSafe}; From 88e1eb0f327fff3878485e53d260cce456902d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Mon, 16 Dec 2024 10:42:26 +0100 Subject: [PATCH 198/481] Add 'into_array' conversion destructors for 'Box', 'Rc', and 'Arc'; --- alloc/src/boxed.rs | 20 ++++++++++++++++++++ alloc/src/rc.rs | 20 ++++++++++++++++++++ alloc/src/sync.rs | 20 ++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 23b85fbd4ebc3..ca3bd24a42031 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -761,6 +761,26 @@ impl Box<[T]> { }; unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } + + /// Converts the boxed slice into a boxed array. + /// + /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub fn into_array(self) -> Option> { + if self.len() == N { + let ptr = Self::into_raw(self) as *mut [T; N]; + + // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. + let me = unsafe { Box::from_raw(ptr) }; + Some(me) + } else { + None + } + } } impl Box<[T], A> { diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index b7ec3af9818a0..e014404eff35b 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -1084,6 +1084,26 @@ impl Rc<[T]> { )) } } + + /// Converts the reference-counted slice into a reference-counted array. + /// + /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub fn into_array(self) -> Option> { + if self.len() == N { + let ptr = Self::into_raw(self) as *const [T; N]; + + // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. + let me = unsafe { Rc::from_raw(ptr) }; + Some(me) + } else { + None + } + } } impl Rc<[T], A> { diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 9be0b3e3e8801..b34a6d3f660c8 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -1203,6 +1203,26 @@ impl Arc<[T]> { )) } } + + /// Converts the reference-counted slice into a reference-counted array. + /// + /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub fn into_array(self) -> Option> { + if self.len() == N { + let ptr = Self::into_raw(self) as *const [T; N]; + + // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. + let me = unsafe { Arc::from_raw(ptr) }; + Some(me) + } else { + None + } + } } impl Arc<[T], A> { From b221158edf51bc9a8c58ab457b6f508c9bbefc93 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 13 Oct 2021 08:46:34 -0700 Subject: [PATCH 199/481] Document collection `From` and `FromIterator` impls that drop duplicate keys. This behavior is worth documenting because there are other plausible alternatives, such as panicking when a duplicate is encountered, and it reminds the programmer to consider whether they should, for example, coalesce duplicate keys first. --- alloc/src/collections/btree/map.rs | 9 ++++++++- alloc/src/collections/btree/set.rs | 4 ++++ std/src/collections/hash/map.rs | 9 +++++++++ std/src/collections/hash/set.rs | 4 ++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/alloc/src/collections/btree/map.rs b/alloc/src/collections/btree/map.rs index d1ce4e215ed9c..56679eaa11894 100644 --- a/alloc/src/collections/btree/map.rs +++ b/alloc/src/collections/btree/map.rs @@ -2289,6 +2289,10 @@ impl FusedIterator for RangeMut<'_, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator<(K, V)> for BTreeMap { + /// Constructs a `BTreeMap` from an iterator of key-value pairs. + /// + /// If the iterator produces any pairs with equal keys, + /// all but the last value for each such key are discarded. fn from_iter>(iter: T) -> BTreeMap { let mut inputs: Vec<_> = iter.into_iter().collect(); @@ -2403,7 +2407,10 @@ where #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl From<[(K, V); N]> for BTreeMap { - /// Converts a `[(K, V); N]` into a `BTreeMap<(K, V)>`. + /// Converts a `[(K, V); N]` into a `BTreeMap`. + /// + /// If any entries in the array have equal keys, all but the last entry for each such key + /// are discarded. /// /// ``` /// use std::collections::BTreeMap; diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 6f8c3b2d152b8..9f5a42b5f6d2d 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -1491,6 +1491,10 @@ impl BTreeSet { impl From<[T; N]> for BTreeSet { /// Converts a `[T; N]` into a `BTreeSet`. /// + /// If the array contains any equal values, all but the last instance of each are discarded. + /// + /// # Examples + /// /// ``` /// use std::collections::BTreeSet; /// diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 109bc3946346f..5b2cd53763b90 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -1446,6 +1446,11 @@ impl From<[(K, V); N]> for HashMap where K: Eq + Hash, { + /// Converts a `[(K, V); N]` into a `HashMap`. + /// + /// If any entries in the array have equal keys, all but the last entry for each such key + /// are discarded. + /// /// # Examples /// /// ``` @@ -3219,6 +3224,10 @@ where K: Eq + Hash, S: BuildHasher + Default, { + /// Constructs a `HashMap` from an iterator of key-value pairs. + /// + /// If the iterator produces any pairs with equal keys, + /// all but the last value for each such key are discarded. fn from_iter>(iter: T) -> HashMap { let mut map = HashMap::with_hasher(Default::default()); map.extend(iter); diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index 4c81aaff45886..8e840aaa07f92 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -1091,6 +1091,10 @@ impl From<[T; N]> for HashSet where T: Eq + Hash, { + /// Converts a `[T; N]` into a `HashSet`. + /// + /// If the array contains any equal values, all but the last instance of each are discarded. + /// /// # Examples /// /// ``` From 3cc63c3152f6e980ca5e5d7d251b910772725f9b Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 22 Dec 2024 08:13:00 -0800 Subject: [PATCH 200/481] Specify only that duplicates are discarded, not the order. --- alloc/src/collections/btree/map.rs | 6 +++--- alloc/src/collections/btree/set.rs | 3 ++- std/src/collections/hash/map.rs | 6 +++--- std/src/collections/hash/set.rs | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/alloc/src/collections/btree/map.rs b/alloc/src/collections/btree/map.rs index 56679eaa11894..6d305386dbfa0 100644 --- a/alloc/src/collections/btree/map.rs +++ b/alloc/src/collections/btree/map.rs @@ -2292,7 +2292,7 @@ impl FromIterator<(K, V)> for BTreeMap { /// Constructs a `BTreeMap` from an iterator of key-value pairs. /// /// If the iterator produces any pairs with equal keys, - /// all but the last value for each such key are discarded. + /// all but one of the corresponding values will be dropped. fn from_iter>(iter: T) -> BTreeMap { let mut inputs: Vec<_> = iter.into_iter().collect(); @@ -2409,8 +2409,8 @@ where impl From<[(K, V); N]> for BTreeMap { /// Converts a `[(K, V); N]` into a `BTreeMap`. /// - /// If any entries in the array have equal keys, all but the last entry for each such key - /// are discarded. + /// If any entries in the array have equal keys, + /// all but one of the corresponding values will be dropped. /// /// ``` /// use std::collections::BTreeMap; diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 9f5a42b5f6d2d..9660023d6945e 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -1491,7 +1491,8 @@ impl BTreeSet { impl From<[T; N]> for BTreeSet { /// Converts a `[T; N]` into a `BTreeSet`. /// - /// If the array contains any equal values, all but the last instance of each are discarded. + /// If the array contains any equal values, + /// all but one will be dropped. /// /// # Examples /// diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 5b2cd53763b90..56d734ba2fbfb 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -1448,8 +1448,8 @@ where { /// Converts a `[(K, V); N]` into a `HashMap`. /// - /// If any entries in the array have equal keys, all but the last entry for each such key - /// are discarded. + /// If any entries in the array have equal keys, + /// all but one of the corresponding values will be dropped. /// /// # Examples /// @@ -3227,7 +3227,7 @@ where /// Constructs a `HashMap` from an iterator of key-value pairs. /// /// If the iterator produces any pairs with equal keys, - /// all but the last value for each such key are discarded. + /// all but one of the corresponding values will be dropped. fn from_iter>(iter: T) -> HashMap { let mut map = HashMap::with_hasher(Default::default()); map.extend(iter); diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index 8e840aaa07f92..bcf6d6b4ccf3a 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -1093,7 +1093,8 @@ where { /// Converts a `[T; N]` into a `HashSet`. /// - /// If the array contains any equal values, all but the last instance of each are discarded. + /// If the array contains any equal values, + /// all but one will be dropped. /// /// # Examples /// From 73bb4f5b65922a6961202134e02bfad430365485 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 21 Dec 2024 22:45:04 -0800 Subject: [PATCH 201/481] Fix forgetting to save statx availability on success Signed-off-by: Alex Saveau --- std/src/sys/pal/unix/fs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 37029bcd36e30..408f8020c5657 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -168,7 +168,8 @@ cfg_has_statx! {{ ) -> c_int } - if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Unavailable as u8 { + let statx_availability = STATX_SAVED_STATE.load(Ordering::Relaxed); + if statx_availability == STATX_STATE::Unavailable as u8 { return None; } @@ -200,6 +201,9 @@ cfg_has_statx! {{ return None; } } + if statx_availability == STATX_STATE::Unknown as u8 { + STATX_SAVED_STATE.store(STATX_STATE::Present as u8, Ordering::Relaxed); + } // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); From 49f1e7c899c61ffd0b58ccae2bf57a4f749b60e0 Mon Sep 17 00:00:00 2001 From: deltragon Date: Tue, 24 Dec 2024 14:37:17 +0100 Subject: [PATCH 202/481] Use scoped threads in `std::sync::Barrier` examples This removes boilerplate around `Arc`s and makes the code more clear. --- std/src/sync/barrier.rs | 60 ++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/std/src/sync/barrier.rs b/std/src/sync/barrier.rs index 82cc13a74b7f1..14e4a9abe6f17 100644 --- a/std/src/sync/barrier.rs +++ b/std/src/sync/barrier.rs @@ -10,26 +10,22 @@ use crate::sync::{Condvar, Mutex}; /// # Examples /// /// ``` -/// use std::sync::{Arc, Barrier}; +/// use std::sync::Barrier; /// use std::thread; /// /// let n = 10; -/// let mut handles = Vec::with_capacity(n); -/// let barrier = Arc::new(Barrier::new(n)); -/// for _ in 0..n { -/// let c = Arc::clone(&barrier); -/// // The same messages will be printed together. -/// // You will NOT see any interleaving. -/// handles.push(thread::spawn(move || { -/// println!("before wait"); -/// c.wait(); -/// println!("after wait"); -/// })); -/// } -/// // Wait for other threads to finish. -/// for handle in handles { -/// handle.join().unwrap(); -/// } +/// let barrier = Barrier::new(n); +/// thread::scope(|s| { +/// for _ in 0..n { +/// // The same messages will be printed together. +/// // You will NOT see any interleaving. +/// s.spawn(|| { +/// println!("before wait"); +/// barrier.wait(); +/// println!("after wait"); +/// }); +/// } +/// }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Barrier { @@ -105,26 +101,22 @@ impl Barrier { /// # Examples /// /// ``` - /// use std::sync::{Arc, Barrier}; + /// use std::sync::Barrier; /// use std::thread; /// /// let n = 10; - /// let mut handles = Vec::with_capacity(n); - /// let barrier = Arc::new(Barrier::new(n)); - /// for _ in 0..n { - /// let c = Arc::clone(&barrier); - /// // The same messages will be printed together. - /// // You will NOT see any interleaving. - /// handles.push(thread::spawn(move || { - /// println!("before wait"); - /// c.wait(); - /// println!("after wait"); - /// })); - /// } - /// // Wait for other threads to finish. - /// for handle in handles { - /// handle.join().unwrap(); - /// } + /// let barrier = Barrier::new(n); + /// thread::scope(|s| { + /// for _ in 0..n { + /// // The same messages will be printed together. + /// // You will NOT see any interleaving. + /// s.spawn(|| { + /// println!("before wait"); + /// barrier.wait(); + /// println!("after wait"); + /// }); + /// } + /// }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn wait(&self) -> BarrierWaitResult { From 305eca6d115bbd5db65111771a30069d31d97016 Mon Sep 17 00:00:00 2001 From: wtlin1228 Date: Thu, 26 Dec 2024 13:56:45 +0800 Subject: [PATCH 203/481] docs: update code example for Iterator#rposition --- core/src/iter/traits/iterator.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/iter/traits/iterator.rs b/core/src/iter/traits/iterator.rs index ff39e8ac25f8f..91c3a4b29b539 100644 --- a/core/src/iter/traits/iterator.rs +++ b/core/src/iter/traits/iterator.rs @@ -3051,6 +3051,7 @@ pub trait Iterator { /// /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&-1)); + /// assert_eq!(iter.next_back(), Some(&3)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 23d674ecffe5cfa5b88662303068e1a4753ff4ac Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 26 Dec 2024 16:09:30 +0100 Subject: [PATCH 204/481] unwinding: bump version to fix asm With #80608 the `unwinding` crate no longer builds. The upstream crate has been updated to build by manually adding directives to the naked_asm stream. Bump the dependency in Rust to get this newer version. This fixes the build for Xous, and closes #134403. Signed-off-by: Sean Cross --- Cargo.lock | 4 ++-- unwind/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22f6e1edf21ff..15ca4cbff7b79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c6cb20f236dae10c69b0b45d82ef50af8b7e45c10e429e7901d26b49b4dbf3" +checksum = "51f06a05848f650946acef3bf525fe96612226b61f74ae23ffa4e98bfbb8ab3c" dependencies = [ "compiler_builtins", "gimli 0.31.1", diff --git a/unwind/Cargo.toml b/unwind/Cargo.toml index 96ddae16f0ab3..e13c9a06c05d1 100644 --- a/unwind/Cargo.toml +++ b/unwind/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.3", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.5", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features] From b20e10be65a492b38c1857333b9e827062c550ac Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 26 Dec 2024 08:58:17 -0700 Subject: [PATCH 205/481] docs: inline `std::ffi::c_str` types to `std::ffi` Rustdoc has no way to show that an item is stable, but only at a different path. `std::ffi::c_str::NulError` is not stable, but `std::ffi::NulError` is. To avoid marking these types as unstable when someone just wants to follow a link from `CString`, inline them into their stable paths. --- std/src/ffi/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/std/src/ffi/mod.rs b/std/src/ffi/mod.rs index 469136be8838a..7d7cce09a3f09 100644 --- a/std/src/ffi/mod.rs +++ b/std/src/ffi/mod.rs @@ -179,19 +179,19 @@ pub use core::ffi::{ c_ulong, c_ulonglong, c_ushort, }; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub use self::c_str::FromBytesUntilNulError; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub use self::c_str::FromBytesWithNulError; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub use self::c_str::FromVecWithNulError; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "cstring_into", since = "1.7.0")] pub use self::c_str::IntoStringError; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use self::c_str::NulError; #[doc(inline)] From 797f8f5dcd913413f79e141a101ee24beb2922bd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 26 Dec 2024 15:51:45 -0700 Subject: [PATCH 206/481] docs: inline `core::ffi::c_str` types to `core::ffi` --- core/src/ffi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 7a161f595f41b..5f32775822be6 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -12,10 +12,10 @@ #[doc(inline)] #[stable(feature = "core_c_str", since = "1.64.0")] pub use self::c_str::CStr; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub use self::c_str::FromBytesUntilNulError; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "core_c_str", since = "1.64.0")] pub use self::c_str::FromBytesWithNulError; use crate::fmt; From fe5577ee830a2e958dfadaaf2c232f9e3abe17cf Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 26 Dec 2024 12:03:37 +0000 Subject: [PATCH 207/481] Fix renaming symlinks on Windows Previously we only detected mount points and not other types of links when determining reparse point behaviour. --- std/src/fs/tests.rs | 29 +++++++++++++++++++++++++++++ std/src/sys/pal/windows/fs.rs | 17 ++++++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 0308a5f433a99..28f16da1ed8d2 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -1953,3 +1953,32 @@ fn test_rename_directory_to_non_empty_directory() { error!(fs::rename(source_path, target_path), 145); // ERROR_DIR_NOT_EMPTY } + +#[test] +fn test_rename_symlink() { + let tmpdir = tmpdir(); + let original = tmpdir.join("original"); + let dest = tmpdir.join("dest"); + let not_exist = Path::new("does not exist"); + + symlink_file(not_exist, &original).unwrap(); + fs::rename(&original, &dest).unwrap(); + // Make sure that renaming `original` to `dest` preserves the symlink. + assert_eq!(fs::read_link(&dest).unwrap().as_path(), not_exist); +} + +#[test] +#[cfg(windows)] +fn test_rename_junction() { + let tmpdir = tmpdir(); + let original = tmpdir.join("original"); + let dest = tmpdir.join("dest"); + let not_exist = Path::new("does not exist"); + + junction_point(¬_exist, &original).unwrap(); + fs::rename(&original, &dest).unwrap(); + + // Make sure that renaming `original` to `dest` preserves the junction point. + // Junction links are always absolute so we just check the file name is correct. + assert_eq!(fs::read_link(&dest).unwrap().file_name(), Some(not_exist.as_os_str())); +} diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index dda4259919b6d..2f300e32d7c84 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -1295,15 +1295,18 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { } else { // SAFETY: The struct has been initialized by GetFileInformationByHandleEx let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() }; + let file_type = FileType::new( + file_attribute_tag_info.FileAttributes, + file_attribute_tag_info.ReparseTag, + ); - if file_attribute_tag_info.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 - && file_attribute_tag_info.ReparseTag != c::IO_REPARSE_TAG_MOUNT_POINT - { - // The file is not a mount point: Reopen the file without inhibiting reparse point behavior. - None - } else { - // The file is a mount point: Don't reopen the file so that the mount point gets renamed. + if file_type.is_symlink() { + // The file is a mount point, junction point or symlink so + // don't reopen the file so that the link gets renamed. Some(Ok(handle)) + } else { + // Otherwise reopen the file without inhibiting reparse point behavior. + None } } } From f074cdee4fb72d6d50cc71add312fabad165bb3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Dec 2024 08:32:47 +0100 Subject: [PATCH 208/481] ptr::copy: fix docs for the overlapping case --- core/src/intrinsics/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 42b8eb33a1a95..5e523c554d9cb 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -4364,13 +4364,11 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes, and must remain valid even -/// when `dst` is written for `count * size_of::()` bytes. (This means if the memory ranges -/// overlap, the two pointers must not be subject to aliasing restrictions relative to each -/// other.) +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. /// /// * `dst` must be [valid] for writes of `count * size_of::()` bytes, and must remain valid even -/// when `src` is read for `count * size_of::()` bytes. +/// when `src` is read for `count * size_of::()` bytes. (This means if the memory ranges +/// overlap, the `dst` pointer must not be invalidated by `src` reads.) /// /// * Both `src` and `dst` must be properly aligned. /// From 9e6e37790fd4929add8da46b6a94a1466634e6c9 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 13 Dec 2024 17:31:46 +0000 Subject: [PATCH 209/481] Windows: Use WriteFile to write to a UTF-8 console --- std/src/sys/pal/windows/c/bindings.txt | 1 + std/src/sys/pal/windows/c/windows_sys.rs | 2 ++ std/src/sys/pal/windows/stdio.rs | 24 +++++++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/std/src/sys/pal/windows/c/bindings.txt b/std/src/sys/pal/windows/c/bindings.txt index d98e90eedfec8..c06f274685c24 100644 --- a/std/src/sys/pal/windows/c/bindings.txt +++ b/std/src/sys/pal/windows/c/bindings.txt @@ -2426,6 +2426,7 @@ Windows.Win32.System.Console.ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows.Win32.System.Console.ENABLE_WINDOW_INPUT Windows.Win32.System.Console.ENABLE_WRAP_AT_EOL_OUTPUT Windows.Win32.System.Console.GetConsoleMode +Windows.Win32.System.Console.GetConsoleOutputCP Windows.Win32.System.Console.GetStdHandle Windows.Win32.System.Console.ReadConsoleW Windows.Win32.System.Console.STD_ERROR_HANDLE diff --git a/std/src/sys/pal/windows/c/windows_sys.rs b/std/src/sys/pal/windows/c/windows_sys.rs index ed29f3d264ca4..79513d33a1ac7 100644 --- a/std/src/sys/pal/windows/c/windows_sys.rs +++ b/std/src/sys/pal/windows/c/windows_sys.rs @@ -34,6 +34,7 @@ windows_targets::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv : windows_targets::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR); windows_targets::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetConsoleOutputCP() -> u32); windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32); @@ -3333,6 +3334,7 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } + #[cfg(target_arch = "arm")] #[repr(C)] pub struct WSADATA { diff --git a/std/src/sys/pal/windows/stdio.rs b/std/src/sys/pal/windows/stdio.rs index 642c8bc4df7d1..1b735e7f0cb2e 100644 --- a/std/src/sys/pal/windows/stdio.rs +++ b/std/src/sys/pal/windows/stdio.rs @@ -84,21 +84,43 @@ fn is_console(handle: c::HANDLE) -> bool { unsafe { c::GetConsoleMode(handle, &mut mode) != 0 } } +/// Returns true if the attached console's code page is currently UTF-8. +#[cfg(not(target_vendor = "win7"))] +fn is_utf8_console() -> bool { + unsafe { c::GetConsoleOutputCP() == c::CP_UTF8 } +} + +#[cfg(target_vendor = "win7")] +fn is_utf8_console() -> bool { + // Windows 7 has a fun "feature" where WriteFile on a console handle will return + // the number of UTF-16 code units written and not the number of bytes from the input string. + // So we always claim the console isn't UTF-8 to trigger the WriteConsole fallback code. + false +} + fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> io::Result { if data.is_empty() { return Ok(0); } let handle = get_handle(handle_id)?; - if !is_console(handle) { + if !is_console(handle) || is_utf8_console() { unsafe { let handle = Handle::from_raw_handle(handle); let ret = handle.write(data); let _ = handle.into_raw_handle(); // Don't close the handle return ret; } + } else { + write_console_utf16(data, incomplete_utf8, handle) } +} +fn write_console_utf16( + data: &[u8], + incomplete_utf8: &mut IncompleteUtf8, + handle: c::HANDLE, +) -> io::Result { if incomplete_utf8.len > 0 { assert!( incomplete_utf8.len < 4, From 85aed355992312c0ea01e63fd6e190bffb19855c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 24 Dec 2024 11:04:12 +0000 Subject: [PATCH 210/481] Fix mistake in windows file open --- std/src/sys/pal/windows/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 2f300e32d7c84..b3659351b8c11 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -323,7 +323,7 @@ impl File { let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), - c::FileEndOfFileInfo, + c::FileAllocationInfo, (&raw const alloc).cast::(), mem::size_of::() as u32, ); From 4d3e85b21af71d865d486893cf59e4a28fb56c3a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 29 Nov 2024 21:32:03 -0800 Subject: [PATCH 211/481] Move `{widening, carrying}_mul` to an intrinsic with fallback MIR Including implementing it for `u128`, so it can be defined in `uint_impl!`. This way it works for all backends, including CTFE. --- core/src/intrinsics/fallback.rs | 111 ++++++++++++++++++++++++++ core/src/intrinsics/mod.rs | 29 +++++++ core/src/lib.rs | 1 + core/src/num/mod.rs | 135 -------------------------------- core/src/num/uint_macros.rs | 116 +++++++++++++++++++++++++++ core/tests/intrinsics.rs | 58 ++++++++++++++ core/tests/lib.rs | 1 + 7 files changed, 316 insertions(+), 135 deletions(-) create mode 100644 core/src/intrinsics/fallback.rs diff --git a/core/src/intrinsics/fallback.rs b/core/src/intrinsics/fallback.rs new file mode 100644 index 0000000000000..d87331f726208 --- /dev/null +++ b/core/src/intrinsics/fallback.rs @@ -0,0 +1,111 @@ +#![unstable( + feature = "core_intrinsics_fallbacks", + reason = "The fallbacks will never be stable, as they exist only to be called \ + by the fallback MIR, but they're exported so they can be tested on \ + platforms where the fallback MIR isn't actually used", + issue = "none" +)] +#![allow(missing_docs)] + +#[const_trait] +pub trait CarryingMulAdd: Copy + 'static { + type Unsigned: Copy + 'static; + fn carrying_mul_add( + self, + multiplicand: Self, + addend: Self, + carry: Self, + ) -> (Self::Unsigned, Self); +} + +macro_rules! impl_carrying_mul_add_by_widening { + ($($t:ident $u:ident $w:ident,)+) => {$( + #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] + impl const CarryingMulAdd for $t { + type Unsigned = $u; + #[inline] + fn carrying_mul_add(self, a: Self, b: Self, c: Self) -> ($u, $t) { + let wide = (self as $w) * (a as $w) + (b as $w) + (c as $w); + (wide as _, (wide >> Self::BITS) as _) + } + } + )+}; +} +impl_carrying_mul_add_by_widening! { + u8 u8 u16, + u16 u16 u32, + u32 u32 u64, + u64 u64 u128, + usize usize UDoubleSize, + i8 u8 i16, + i16 u16 i32, + i32 u32 i64, + i64 u64 i128, + isize usize UDoubleSize, +} + +#[cfg(target_pointer_width = "16")] +type UDoubleSize = u32; +#[cfg(target_pointer_width = "32")] +type UDoubleSize = u64; +#[cfg(target_pointer_width = "64")] +type UDoubleSize = u128; + +#[inline] +const fn wide_mul_u128(a: u128, b: u128) -> (u128, u128) { + #[inline] + const fn to_low_high(x: u128) -> [u128; 2] { + const MASK: u128 = u64::MAX as _; + [x & MASK, x >> 64] + } + #[inline] + const fn from_low_high(x: [u128; 2]) -> u128 { + x[0] | (x[1] << 64) + } + #[inline] + const fn scalar_mul(low_high: [u128; 2], k: u128) -> [u128; 3] { + let [x, c] = to_low_high(k * low_high[0]); + let [y, z] = to_low_high(k * low_high[1] + c); + [x, y, z] + } + let a = to_low_high(a); + let b = to_low_high(b); + let low = scalar_mul(a, b[0]); + let high = scalar_mul(a, b[1]); + let r0 = low[0]; + let [r1, c] = to_low_high(low[1] + high[0]); + let [r2, c] = to_low_high(low[2] + high[1] + c); + let r3 = high[2] + c; + (from_low_high([r0, r1]), from_low_high([r2, r3])) +} + +#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] +impl const CarryingMulAdd for u128 { + type Unsigned = u128; + #[inline] + fn carrying_mul_add(self, b: u128, c: u128, d: u128) -> (u128, u128) { + let (low, mut high) = wide_mul_u128(self, b); + let (low, carry) = u128::overflowing_add(low, c); + high += carry as u128; + let (low, carry) = u128::overflowing_add(low, d); + high += carry as u128; + (low, high) + } +} + +#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] +impl const CarryingMulAdd for i128 { + type Unsigned = u128; + #[inline] + fn carrying_mul_add(self, b: i128, c: i128, d: i128) -> (u128, i128) { + let (low, high) = wide_mul_u128(self as u128, b as u128); + let mut high = high as i128; + high = high.wrapping_add((self >> 127) * b); + high = high.wrapping_add(self * (b >> 127)); + let (low, carry) = u128::overflowing_add(low, c as u128); + high = high.wrapping_add((carry as i128) + (c >> 127)); + let (low, carry) = u128::overflowing_add(low, d as u128); + high = high.wrapping_add((carry as i128) + (d >> 127)); + (low, high) + } +} diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 5e523c554d9cb..65e2dcbc7cc31 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -68,6 +68,7 @@ use crate::marker::{DiscriminantKind, Tuple}; use crate::mem::SizedTypeProperties; use crate::{ptr, ub_checks}; +pub mod fallback; pub mod mir; pub mod simd; @@ -3305,6 +3306,34 @@ pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { unimplemented!() } +/// Performs full-width multiplication and addition with a carry: +/// `multiplier * multiplicand + addend + carry`. +/// +/// This is possible without any overflow. For `uN`: +/// MAX * MAX + MAX + MAX +/// => (2ⁿ-1) × (2ⁿ-1) + (2ⁿ-1) + (2ⁿ-1) +/// => (2²ⁿ - 2ⁿ⁺¹ + 1) + (2ⁿ⁺¹ - 2) +/// => 2²ⁿ - 1 +/// +/// For `iN`, the upper bound is MIN * MIN + MAX + MAX => 2²ⁿ⁻² + 2ⁿ - 2, +/// and the lower bound is MAX * MIN + MIN + MIN => -2²ⁿ⁻² - 2ⁿ + 2ⁿ⁺¹. +/// +/// This currently supports unsigned integers *only*, no signed ones. +/// The stabilized versions of this intrinsic are available on integers. +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_carrying_mul_add", issue = "85532")] +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)] +pub const fn carrying_mul_add, U>( + multiplier: T, + multiplicand: T, + addend: T, + carry: T, +) -> (U, T) { + multiplier.carrying_mul_add(multiplicand, addend, carry) +} + /// Performs an exact division, resulting in undefined behavior where /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// diff --git a/core/src/lib.rs b/core/src/lib.rs index a7f741a940896..82d7d045bf571 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -110,6 +110,7 @@ #![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] +#![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(const_typed_swap)] #![feature(core_intrinsics)] diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 357a85ae843cd..1f5b8ce6c6e22 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -228,134 +228,6 @@ macro_rules! midpoint_impl { }; } -macro_rules! widening_impl { - ($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => { - /// Calculates the complete product `self * rhs` without the possibility to overflow. - /// - /// This returns the low-order (wrapping) bits and the high-order (overflow) bits - /// of the result as two separate values, in that order. - /// - /// If you also need to add a carry to the wide result, then you want - /// [`Self::carrying_mul`] instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!(5u32.widening_mul(2), (10, 0)); - /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); - /// ``` - #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { - // note: longer-term this should be done via an intrinsic, - // but for now we can deal without an impl for u128/i128 - // SAFETY: overflow will be contained within the wider types - let wide = unsafe { (self as $WideT).unchecked_mul(rhs as $WideT) }; - (wide as $SelfT, (wide >> $BITS) as $SelfT) - } - - /// Calculates the "full multiplication" `self * rhs + carry` - /// without the possibility to overflow. - /// - /// This returns the low-order (wrapping) bits and the high-order (overflow) bits - /// of the result as two separate values, in that order. - /// - /// Performs "long multiplication" which takes in an extra amount to add, and may return an - /// additional amount of overflow. This allows for chaining together multiple - /// multiplications to create "big integers" which represent larger values. - /// - /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); - /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); - /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); - /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); - #[doc = concat!("assert_eq!(", - stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", - "(0, ", stringify!($SelfT), "::MAX));" - )] - /// ``` - /// - /// This is the core operation needed for scalar multiplication when - /// implementing it for wider-than-native types. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// fn scalar_mul_eq(little_endian_digits: &mut Vec, multiplicand: u16) { - /// let mut carry = 0; - /// for d in little_endian_digits.iter_mut() { - /// (*d, carry) = d.carrying_mul(multiplicand, carry); - /// } - /// if carry != 0 { - /// little_endian_digits.push(carry); - /// } - /// } - /// - /// let mut v = vec![10, 20]; - /// scalar_mul_eq(&mut v, 3); - /// assert_eq!(v, [30, 60]); - /// - /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); - /// let mut v = vec![0x4321, 0x8765]; - /// scalar_mul_eq(&mut v, 0xFEED); - /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]); - /// ``` - /// - /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), - /// except that it gives the value of the overflow instead of just whether one happened: - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// let r = u8::carrying_mul(7, 13, 0); - /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); - /// let r = u8::carrying_mul(13, 42, 0); - /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); - /// ``` - /// - /// The value of the first field in the returned tuple matches what you'd get - /// by combining the [`wrapping_mul`](Self::wrapping_mul) and - /// [`wrapping_add`](Self::wrapping_add) methods: - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!( - /// 789_u16.carrying_mul(456, 123).0, - /// 789_u16.wrapping_mul(456).wrapping_add(123), - /// ); - /// ``` - #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { - // note: longer-term this should be done via an intrinsic, - // but for now we can deal without an impl for u128/i128 - // SAFETY: overflow will be contained within the wider types - let wide = unsafe { - (self as $WideT).unchecked_mul(rhs as $WideT).unchecked_add(carry as $WideT) - }; - (wide as $SelfT, (wide >> $BITS) as $SelfT) - } - }; -} - impl i8 { int_impl! { Self = i8, @@ -576,7 +448,6 @@ impl u8 { from_xe_bytes_doc = u8_xe_bytes_doc!(), bound_condition = "", } - widening_impl! { u8, u16, 8, unsigned } midpoint_impl! { u8, u16, unsigned } /// Checks if the value is within the ASCII range. @@ -1192,7 +1063,6 @@ impl u16 { from_xe_bytes_doc = "", bound_condition = "", } - widening_impl! { u16, u32, 16, unsigned } midpoint_impl! { u16, u32, unsigned } /// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`]. @@ -1240,7 +1110,6 @@ impl u32 { from_xe_bytes_doc = "", bound_condition = "", } - widening_impl! { u32, u64, 32, unsigned } midpoint_impl! { u32, u64, unsigned } } @@ -1264,7 +1133,6 @@ impl u64 { from_xe_bytes_doc = "", bound_condition = "", } - widening_impl! { u64, u128, 64, unsigned } midpoint_impl! { u64, u128, unsigned } } @@ -1314,7 +1182,6 @@ impl usize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 16-bit targets", } - widening_impl! { usize, u32, 16, unsigned } midpoint_impl! { usize, u32, unsigned } } @@ -1339,7 +1206,6 @@ impl usize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 32-bit targets", } - widening_impl! { usize, u64, 32, unsigned } midpoint_impl! { usize, u64, unsigned } } @@ -1364,7 +1230,6 @@ impl usize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 64-bit targets", } - widening_impl! { usize, u128, 64, unsigned } midpoint_impl! { usize, u128, unsigned } } diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 151d879fabeed..4a5fdbfb0ea2c 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -3347,6 +3347,122 @@ macro_rules! uint_impl { unsafe { mem::transmute(bytes) } } + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// If you also need to add a carry to the wide result, then you want + /// [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.widening_mul(2), (10, 0)); + /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { + Self::carrying_mul(self, rhs, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); + /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(0, ", stringify!($SelfT), "::MAX));" + )] + /// ``` + /// + /// This is the core operation needed for scalar multiplication when + /// implementing it for wider-than-native types. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// fn scalar_mul_eq(little_endian_digits: &mut Vec, multiplicand: u16) { + /// let mut carry = 0; + /// for d in little_endian_digits.iter_mut() { + /// (*d, carry) = d.carrying_mul(multiplicand, carry); + /// } + /// if carry != 0 { + /// little_endian_digits.push(carry); + /// } + /// } + /// + /// let mut v = vec![10, 20]; + /// scalar_mul_eq(&mut v, 3); + /// assert_eq!(v, [30, 60]); + /// + /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); + /// let mut v = vec![0x4321, 0x8765]; + /// scalar_mul_eq(&mut v, 0xFEED); + /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]); + /// ``` + /// + /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), + /// except that it gives the value of the overflow instead of just whether one happened: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// let r = u8::carrying_mul(7, 13, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); + /// let r = u8::carrying_mul(13, 42, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); + /// ``` + /// + /// The value of the first field in the returned tuple matches what you'd get + /// by combining the [`wrapping_mul`](Self::wrapping_mul) and + /// [`wrapping_add`](Self::wrapping_add) methods: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!( + /// 789_u16.carrying_mul(456, 123).0, + /// 789_u16.wrapping_mul(456).wrapping_add(123), + /// ); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { + intrinsics::carrying_mul_add(self, rhs, 0, carry) + } + /// New code should prefer to use #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")] /// diff --git a/core/tests/intrinsics.rs b/core/tests/intrinsics.rs index 8b731cf5b25d1..76f4259409120 100644 --- a/core/tests/intrinsics.rs +++ b/core/tests/intrinsics.rs @@ -125,3 +125,61 @@ fn test_three_way_compare_in_const_contexts() { assert_eq!(SIGNED_EQUAL, Equal); assert_eq!(SIGNED_GREATER, Greater); } + +fn fallback_cma( + a: T, + b: T, + c: T, + d: T, +) -> (T::Unsigned, T) { + a.carrying_mul_add(b, c, d) +} + +#[test] +fn carrying_mul_add_fallback_u32() { + let r = fallback_cma::(0x9e37_79b9, 0x7f4a_7c15, 0xf39c_c060, 0x5ced_c834); + assert_eq!(r, (0x2087_20c1, 0x4eab_8e1d)); + let r = fallback_cma::(0x1082_276b, 0xf3a2_7251, 0xf86c_6a11, 0xd0c1_8e95); + assert_eq!(r, (0x7aa0_1781, 0x0fb6_0528)); +} + +#[test] +fn carrying_mul_add_fallback_i32() { + let r = fallback_cma::(-1, -1, -1, -1); + assert_eq!(r, (u32::MAX, -1)); + let r = fallback_cma::(1, -1, 1, 1); + assert_eq!(r, (1, 0)); +} + +#[test] +fn carrying_mul_add_fallback_u128() { + assert_eq!(fallback_cma::(1, 1, 1, 1), (3, 0)); + assert_eq!(fallback_cma::(0, 0, u128::MAX, u128::MAX), (u128::MAX - 1, 1)); + assert_eq!( + fallback_cma::(u128::MAX, u128::MAX, u128::MAX, u128::MAX), + (u128::MAX, u128::MAX), + ); + + let r = fallback_cma::( + 0x243f6a8885a308d313198a2e03707344, + 0xa4093822299f31d0082efa98ec4e6c89, + 0x452821e638d01377be5466cf34e90c6c, + 0xc0ac29b7c97c50dd3f84d5b5b5470917, + ); + assert_eq!(r, (0x8050ec20ed554e40338d277e00b674e7, 0x1739ee6cea07da409182d003859b59d8)); + let r = fallback_cma::( + 0x9216d5d98979fb1bd1310ba698dfb5ac, + 0x2ffd72dbd01adfb7b8e1afed6a267e96, + 0xba7c9045f12c7f9924a19947b3916cf7, + 0x0801f2e2858efc16636920d871574e69, + ); + assert_eq!(r, (0x185525545fdb2fefb502a3a602efd628, 0x1b62d35fe3bff6b566f99667ef7ebfd6)); +} + +#[test] +fn carrying_mul_add_fallback_i128() { + let r = fallback_cma::(-1, -1, -1, -1); + assert_eq!(r, (u128::MAX, -1)); + let r = fallback_cma::(1, -1, 1, 1); + assert_eq!(r, (1, 0)); +} diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 9f0ab7b3f2977..8716c09492834 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -19,6 +19,7 @@ #![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] +#![feature(core_intrinsics_fallbacks)] #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] From 2fe04b1b277bae802a0009130179fd0a70296022 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 29 Nov 2024 22:51:46 -0800 Subject: [PATCH 212/481] Override `carrying_mul_add` in cg_llvm --- core/src/intrinsics/fallback.rs | 4 ++-- core/tests/intrinsics.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/src/intrinsics/fallback.rs b/core/src/intrinsics/fallback.rs index d87331f726208..1779126b180ea 100644 --- a/core/src/intrinsics/fallback.rs +++ b/core/src/intrinsics/fallback.rs @@ -100,8 +100,8 @@ impl const CarryingMulAdd for i128 { fn carrying_mul_add(self, b: i128, c: i128, d: i128) -> (u128, i128) { let (low, high) = wide_mul_u128(self as u128, b as u128); let mut high = high as i128; - high = high.wrapping_add((self >> 127) * b); - high = high.wrapping_add(self * (b >> 127)); + high = high.wrapping_add(i128::wrapping_mul(self >> 127, b)); + high = high.wrapping_add(i128::wrapping_mul(self, b >> 127)); let (low, carry) = u128::overflowing_add(low, c as u128); high = high.wrapping_add((carry as i128) + (c >> 127)); let (low, carry) = u128::overflowing_add(low, d as u128); diff --git a/core/tests/intrinsics.rs b/core/tests/intrinsics.rs index 76f4259409120..744a6a0d2dd8f 100644 --- a/core/tests/intrinsics.rs +++ b/core/tests/intrinsics.rs @@ -153,6 +153,7 @@ fn carrying_mul_add_fallback_i32() { #[test] fn carrying_mul_add_fallback_u128() { + assert_eq!(fallback_cma::(u128::MAX, u128::MAX, 0, 0), (1, u128::MAX - 1)); assert_eq!(fallback_cma::(1, 1, 1, 1), (3, 0)); assert_eq!(fallback_cma::(0, 0, u128::MAX, u128::MAX), (u128::MAX - 1, 1)); assert_eq!( @@ -178,8 +179,17 @@ fn carrying_mul_add_fallback_u128() { #[test] fn carrying_mul_add_fallback_i128() { + assert_eq!(fallback_cma::(-1, -1, 0, 0), (1, 0)); let r = fallback_cma::(-1, -1, -1, -1); assert_eq!(r, (u128::MAX, -1)); let r = fallback_cma::(1, -1, 1, 1); assert_eq!(r, (1, 0)); + assert_eq!( + fallback_cma::(i128::MAX, i128::MAX, i128::MAX, i128::MAX), + (u128::MAX, i128::MAX / 2), + ); + assert_eq!( + fallback_cma::(i128::MIN, i128::MIN, i128::MAX, i128::MAX), + (u128::MAX - 1, -(i128::MIN / 2)), + ); } From 133b5e60e52ce9b9293e59821dfc04f068714f29 Mon Sep 17 00:00:00 2001 From: chloefeal <188809157+chloefeal@users.noreply.github.com> Date: Fri, 27 Dec 2024 21:35:57 +0800 Subject: [PATCH 213/481] Fix typos Signed-off-by: chloefeal <188809157+chloefeal@users.noreply.github.com> --- alloc/tests/sort/tests.rs | 2 +- core/benches/num/int_pow/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/alloc/tests/sort/tests.rs b/alloc/tests/sort/tests.rs index 14e6013f965d8..206624e59ea53 100644 --- a/alloc/tests/sort/tests.rs +++ b/alloc/tests/sort/tests.rs @@ -33,7 +33,7 @@ fn check_is_sorted(v: &mut [T]) { known_good_stable_sort::sort(known_good_sorted_vec.as_mut_slice()); if is_small_test { - eprintln!("Orginal: {:?}", v_orig); + eprintln!("Original: {:?}", v_orig); eprintln!("Expected: {:?}", known_good_sorted_vec); eprintln!("Got: {:?}", v); } else { diff --git a/core/benches/num/int_pow/mod.rs b/core/benches/num/int_pow/mod.rs index 6cf9021358283..46f47028d56e6 100644 --- a/core/benches/num/int_pow/mod.rs +++ b/core/benches/num/int_pow/mod.rs @@ -25,7 +25,7 @@ macro_rules! pow_bench_template { let mut exp_iter = black_box(&exp_array).into_iter(); (0..ITERATIONS).fold((0 as IntType, false), |acc, _| { - // Sometimes constants don't propogate all the way to the + // Sometimes constants don't propagate all the way to the // inside of the loop, so we call a custom expression every cycle // rather than iter::repeat(CONST) let base: IntType = $base_macro!(base_iter); From d5ce7a2c775f4ac9625473c842fb83b88e4d2644 Mon Sep 17 00:00:00 2001 From: chloefeal <188809157+chloefeal@users.noreply.github.com> Date: Sat, 28 Dec 2024 10:37:02 +0800 Subject: [PATCH 214/481] Update library/alloc/tests/sort/tests.rs Co-authored-by: David Tolnay --- alloc/tests/sort/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/tests/sort/tests.rs b/alloc/tests/sort/tests.rs index 206624e59ea53..4cc79010e8fed 100644 --- a/alloc/tests/sort/tests.rs +++ b/alloc/tests/sort/tests.rs @@ -33,7 +33,7 @@ fn check_is_sorted(v: &mut [T]) { known_good_stable_sort::sort(known_good_sorted_vec.as_mut_slice()); if is_small_test { - eprintln!("Original: {:?}", v_orig); + eprintln!("Original: {:?}", v_orig); eprintln!("Expected: {:?}", known_good_sorted_vec); eprintln!("Got: {:?}", v); } else { From e5e7d5bb35269e60e1916387634c89afb25a3531 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Dec 2024 21:57:09 +0000 Subject: [PATCH 215/481] Update `compiler-builtins` to 0.1.140 Nothing significant here, just syncing the following small changes: - https://github.com/rust-lang/compiler-builtins/pull/727 - https://github.com/rust-lang/compiler-builtins/pull/730 - https://github.com/rust-lang/compiler-builtins/pull/736 - https://github.com/rust-lang/compiler-builtins/pull/737 --- Cargo.lock | 4 ++-- alloc/Cargo.toml | 2 +- std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15ca4cbff7b79..40edd2c211cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.138" +version = "0.1.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f0ea7fff95b51f84371588f06062557e96bbe363d2b36218ddb806f3ca8611" +checksum = "df14d41c5d172a886df3753d54238eefb0f61c96cbd8b363c33ccc92c457bee3" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index 3464047d4ee9e..07596fa16f982 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.140", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/std/Cargo.toml b/std/Cargo.toml index f43dcc1630c6a..6380c941e6ab5 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.138" } +compiler_builtins = { version = "=0.1.140" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From fb9ac8c397157c71ff99b22c3d4aef434adab429 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Tue, 17 Dec 2024 12:40:39 -0500 Subject: [PATCH 216/481] Unify fs::copy and io::copy --- std/src/sys/pal/unix/fs.rs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 408f8020c5657..1f79827a23d87 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -1984,7 +1984,7 @@ fn open_to_and_set_permissions( Ok((writer, writer_metadata)) } -#[cfg(not(any(target_os = "linux", target_os = "android", target_vendor = "apple")))] +#[cfg(not(target_vendor = "apple"))] pub fn copy(from: &Path, to: &Path) -> io::Result { let (mut reader, reader_metadata) = open_from(from)?; let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; @@ -1992,24 +1992,6 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { io::copy(&mut reader, &mut writer) } -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn copy(from: &Path, to: &Path) -> io::Result { - let (mut reader, reader_metadata) = open_from(from)?; - let max_len = u64::MAX; - let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; - - use super::kernel_copy::{CopyResult, copy_regular_files}; - - match copy_regular_files(reader.as_raw_fd(), writer.as_raw_fd(), max_len) { - CopyResult::Ended(bytes) => Ok(bytes), - CopyResult::Error(e, _) => Err(e), - CopyResult::Fallback(written) => match io::copy::generic_copy(&mut reader, &mut writer) { - Ok(bytes) => Ok(bytes + written), - Err(e) => Err(e), - }, - } -} - #[cfg(target_vendor = "apple")] pub fn copy(from: &Path, to: &Path) -> io::Result { const COPYFILE_ALL: libc::copyfile_flags_t = libc::COPYFILE_METADATA | libc::COPYFILE_DATA; From 26a2736e254fc3f6fb8f27c50bdd3fdf71483517 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 21 Dec 2024 15:10:29 -0800 Subject: [PATCH 217/481] Eliminate redundant statx syscalls Signed-off-by: Alex Saveau --- std/src/sys/pal/unix/fs.rs | 15 +++++--- std/src/sys/pal/unix/kernel_copy.rs | 58 +++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 1f79827a23d87..bb2d132450162 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -1948,7 +1948,7 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> #[cfg(target_os = "espidf")] fn open_to_and_set_permissions( to: &Path, - _reader_metadata: crate::fs::Metadata, + _reader_metadata: &crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; let writer = OpenOptions::new().open(to)?; @@ -1959,7 +1959,7 @@ fn open_to_and_set_permissions( #[cfg(not(target_os = "espidf"))] fn open_to_and_set_permissions( to: &Path, - reader_metadata: crate::fs::Metadata, + reader_metadata: &crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; use crate::os::unix::fs::{OpenOptionsExt, PermissionsExt}; @@ -1986,10 +1986,13 @@ fn open_to_and_set_permissions( #[cfg(not(target_vendor = "apple"))] pub fn copy(from: &Path, to: &Path) -> io::Result { - let (mut reader, reader_metadata) = open_from(from)?; - let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; + let (reader, reader_metadata) = open_from(from)?; + let (writer, writer_metadata) = open_to_and_set_permissions(to, &reader_metadata)?; - io::copy(&mut reader, &mut writer) + io::copy( + &mut crate::sys::kernel_copy::CachedFileMetadata(reader, reader_metadata), + &mut crate::sys::kernel_copy::CachedFileMetadata(writer, writer_metadata), + ) } #[cfg(target_vendor = "apple")] @@ -2026,7 +2029,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } // Fall back to using `fcopyfile` if `fclonefileat` does not succeed. - let (writer, writer_metadata) = open_to_and_set_permissions(to, reader_metadata)?; + let (writer, writer_metadata) = open_to_and_set_permissions(to, &reader_metadata)?; // We ensure that `FreeOnDrop` never contains a null pointer so it is // always safe to call `copyfile_state_free` diff --git a/std/src/sys/pal/unix/kernel_copy.rs b/std/src/sys/pal/unix/kernel_copy.rs index a671383cb7957..bddfe829f43ab 100644 --- a/std/src/sys/pal/unix/kernel_copy.rs +++ b/std/src/sys/pal/unix/kernel_copy.rs @@ -52,8 +52,8 @@ use crate::cmp::min; use crate::fs::{File, Metadata}; use crate::io::copy::generic_copy; use crate::io::{ - BufRead, BufReader, BufWriter, Error, Read, Result, StderrLock, StdinLock, StdoutLock, Take, - Write, + BorrowedCursor, BufRead, BufReader, BufWriter, Error, IoSlice, IoSliceMut, Read, Result, + StderrLock, StdinLock, StdoutLock, Take, Write, }; use crate::mem::ManuallyDrop; use crate::net::TcpStream; @@ -192,7 +192,7 @@ impl SpecCopy for Copier<'_, '_, R, W> { let w_cfg = writer.properties(); // before direct operations on file descriptors ensure that all source and sink buffers are empty - let mut flush = || -> crate::io::Result { + let mut flush = || -> Result { let bytes = reader.drain_to(writer, u64::MAX)?; // BufWriter buffered bytes have already been accounted for in earlier write() calls writer.flush()?; @@ -537,6 +537,58 @@ impl CopyWrite for BufWriter { } } +pub(crate) struct CachedFileMetadata(pub File, pub Metadata); + +impl Read for CachedFileMetadata { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + self.0.read_vectored(bufs) + } + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { + self.0.read_buf(cursor) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + self.0.read_to_end(buf) + } + fn read_to_string(&mut self, buf: &mut String) -> Result { + self.0.read_to_string(buf) + } +} +impl Write for CachedFileMetadata { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + self.0.write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + #[inline] + fn flush(&mut self) -> Result<()> { + self.0.flush() + } +} + +impl CopyRead for CachedFileMetadata { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::Metadata(self.1.clone()), Some(self.0.as_raw_fd())) + } +} + +impl CopyWrite for CachedFileMetadata { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::Metadata(self.1.clone()), Some(self.0.as_raw_fd())) + } +} + fn fd_to_meta(fd: &T) -> FdMeta { let fd = fd.as_raw_fd(); let file: ManuallyDrop = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) }); From 00f9a4053f62042c5e6e3962365ee203bb925a4b Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Tue, 24 Dec 2024 09:59:22 -0800 Subject: [PATCH 218/481] Fix compilation issues on other unixes Signed-off-by: Alex Saveau --- std/src/sys/pal/unix/fs.rs | 52 +++++++++++++++++++++++++++-- std/src/sys/pal/unix/kernel_copy.rs | 45 ++----------------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index bb2d132450162..3307fa47c7f88 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -1984,14 +1984,62 @@ fn open_to_and_set_permissions( Ok((writer, writer_metadata)) } +mod cfm { + use crate::fs::{File, Metadata}; + use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, Read, Result, Write}; + + #[allow(dead_code)] + pub struct CachedFileMetadata(pub File, pub Metadata); + + impl Read for CachedFileMetadata { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + self.0.read_vectored(bufs) + } + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { + self.0.read_buf(cursor) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + self.0.read_to_end(buf) + } + fn read_to_string(&mut self, buf: &mut String) -> Result { + self.0.read_to_string(buf) + } + } + impl Write for CachedFileMetadata { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + self.0.write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + #[inline] + fn flush(&mut self) -> Result<()> { + self.0.flush() + } + } +} +#[cfg(any(target_os = "linux", target_os = "android"))] +pub(crate) use cfm::CachedFileMetadata; + #[cfg(not(target_vendor = "apple"))] pub fn copy(from: &Path, to: &Path) -> io::Result { let (reader, reader_metadata) = open_from(from)?; let (writer, writer_metadata) = open_to_and_set_permissions(to, &reader_metadata)?; io::copy( - &mut crate::sys::kernel_copy::CachedFileMetadata(reader, reader_metadata), - &mut crate::sys::kernel_copy::CachedFileMetadata(writer, writer_metadata), + &mut cfm::CachedFileMetadata(reader, reader_metadata), + &mut cfm::CachedFileMetadata(writer, writer_metadata), ) } diff --git a/std/src/sys/pal/unix/kernel_copy.rs b/std/src/sys/pal/unix/kernel_copy.rs index bddfe829f43ab..36823a503b17c 100644 --- a/std/src/sys/pal/unix/kernel_copy.rs +++ b/std/src/sys/pal/unix/kernel_copy.rs @@ -52,8 +52,8 @@ use crate::cmp::min; use crate::fs::{File, Metadata}; use crate::io::copy::generic_copy; use crate::io::{ - BorrowedCursor, BufRead, BufReader, BufWriter, Error, IoSlice, IoSliceMut, Read, Result, - StderrLock, StdinLock, StdoutLock, Take, Write, + BufRead, BufReader, BufWriter, Error, Read, Result, StderrLock, StdinLock, StdoutLock, Take, + Write, }; use crate::mem::ManuallyDrop; use crate::net::TcpStream; @@ -65,6 +65,7 @@ use crate::process::{ChildStderr, ChildStdin, ChildStdout}; use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; +use crate::sys::fs::CachedFileMetadata; use crate::sys::weak::syscall; #[cfg(test)] @@ -537,46 +538,6 @@ impl CopyWrite for BufWriter { } } -pub(crate) struct CachedFileMetadata(pub File, pub Metadata); - -impl Read for CachedFileMetadata { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(cursor) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> Result { - self.0.read_to_string(buf) - } -} -impl Write for CachedFileMetadata { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - #[inline] - fn flush(&mut self) -> Result<()> { - self.0.flush() - } -} - impl CopyRead for CachedFileMetadata { fn properties(&self) -> CopyParams { CopyParams(FdMeta::Metadata(self.1.clone()), Some(self.0.as_raw_fd())) From 3a8c1ee90b3a42048cdfcc2e716bce239a9a324f Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sat, 28 Dec 2024 15:42:39 +0100 Subject: [PATCH 219/481] docs: inline `alloc::ffi::c_str` types to `alloc::ffi` --- alloc/src/ffi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/src/ffi/mod.rs b/alloc/src/ffi/mod.rs index 4f9dc40a3cfc9..695d7ad07cf76 100644 --- a/alloc/src/ffi/mod.rs +++ b/alloc/src/ffi/mod.rs @@ -83,7 +83,7 @@ #[doc(inline)] #[stable(feature = "alloc_c_string", since = "1.64.0")] pub use self::c_str::CString; -#[doc(no_inline)] +#[doc(inline)] #[stable(feature = "alloc_c_string", since = "1.64.0")] pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError}; From b9840597f5ae2acc5e3a6c3b86f63fd640206e6b Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Sat, 28 Dec 2024 22:21:04 -0500 Subject: [PATCH 220/481] Fix sentence fragment in `pin` module docs Looks like this was inadvertently dropped in af8ab4e7. Restore the words from before that commit. --- core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/pin.rs b/core/src/pin.rs index f18a45083ff7e..83730285636fb 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -595,7 +595,7 @@ //! [drop-impl]: self#implementing-drop-for-types-with-address-sensitive-states //! //! The [`drop`] function takes [`&mut self`], but this is called *even if that `self` has been -//! pinned*! Implementing [`Drop`] for a type with address-sensitive states, because if `self` was +//! pinned*! Implementing [`Drop`] for a type with address-sensitive states requires some care, because if `self` was //! indeed in an address-sensitive state before [`drop`] was called, it is as if the compiler //! automatically called [`Pin::get_unchecked_mut`]. //! From 14919efd468b9b1cd7a19f37fc64731505dc8f56 Mon Sep 17 00:00:00 2001 From: calciumbe <192480234+calciumbe@users.noreply.github.com> Date: Sun, 29 Dec 2024 18:03:37 +0800 Subject: [PATCH 221/481] fix: typos Signed-off-by: calciumbe <192480234+calciumbe@users.noreply.github.com> --- alloc/src/raw_vec.rs | 2 +- std/src/thread/current.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/alloc/src/raw_vec.rs b/alloc/src/raw_vec.rs index 2c7cdcf0cfb4e..e93ff2f902378 100644 --- a/alloc/src/raw_vec.rs +++ b/alloc/src/raw_vec.rs @@ -420,7 +420,7 @@ impl RawVecInner { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { unsafe { - // Make it more obvious that a subsquent Vec::reserve(capacity) will not allocate. + // Make it more obvious that a subsequent Vec::reserve(capacity) will not allocate. hint::assert_unchecked(!this.needs_to_grow(0, capacity, elem_layout)); } this diff --git a/std/src/thread/current.rs b/std/src/thread/current.rs index 1048ef973560e..3d2c288b36085 100644 --- a/std/src/thread/current.rs +++ b/std/src/thread/current.rs @@ -136,7 +136,7 @@ pub(crate) fn set_current(thread: Thread) -> Result<(), Thread> { /// one thread and is guaranteed not to call the global allocator. #[inline] pub(crate) fn current_id() -> ThreadId { - // If accessing the persistant thread ID takes multiple TLS accesses, try + // If accessing the persistent thread ID takes multiple TLS accesses, try // to retrieve it from the current thread handle, which will only take one // TLS access. if !id::CHEAP { From 12a280f9557d788addaefc95806bbc0ab549f778 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Dec 2024 10:36:32 +0100 Subject: [PATCH 222/481] stabilize const_swap --- core/src/intrinsics/mod.rs | 3 ++- core/src/lib.rs | 1 - core/src/mem/mod.rs | 2 +- core/src/ptr/mod.rs | 3 +-- core/src/ptr/mut_ptr.rs | 2 +- core/src/ptr/non_null.rs | 2 +- core/src/slice/mod.rs | 2 +- core/tests/lib.rs | 1 - 8 files changed, 7 insertions(+), 9 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 65e2dcbc7cc31..21782f71da656 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3983,7 +3983,8 @@ pub const fn is_val_statically_known(_arg: T) -> bool { #[inline] #[rustc_intrinsic] // Const-unstable because `swap_nonoverlapping` is const-unstable. -#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")] +#[rustc_intrinsic_const_stable_indirect] +#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind // pointers, so swapping them with `count: 1` is fine. diff --git a/core/src/lib.rs b/core/src/lib.rs index 82d7d045bf571..0d8a3811eded1 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -112,7 +112,6 @@ #![feature(asm_experimental_arch)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] -#![feature(const_typed_swap)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(internal_impls_macro)] diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 57acc9dcd6ee7..1576eb4315294 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -725,7 +725,7 @@ pub unsafe fn uninitialized() -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "mem_swap"] pub const fn swap(x: &mut T, y: &mut T) { // SAFETY: `&mut` guarantees these are typed readable and writable diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index e6e13eaff7b0f..ac074c097d94c 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1009,9 +1009,8 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_swap"] -#[rustc_const_stable_indirect] pub const unsafe fn swap(x: *mut T, y: *mut T) { // Give ourselves some scratch space to work with. // We do not have to worry about drops: `MaybeUninit` does nothing when dropped. diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 34567917b523a..d75d570a969f8 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -1594,7 +1594,7 @@ impl *mut T { /// /// [`ptr::swap`]: crate::ptr::swap() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_swap", issue = "83163")] + #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] pub const unsafe fn swap(self, with: *mut T) where diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index e0ba469272ed1..1058fa42cc1e3 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -1146,7 +1146,7 @@ impl NonNull { /// [`ptr::swap`]: crate::ptr::swap() #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_swap", issue = "83163")] + #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn swap(self, with: NonNull) where T: Sized, diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index ab65f9d6d2fcc..3e8c698a7aba4 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -913,7 +913,7 @@ impl [T] { /// assert!(v == ["a", "b", "e", "d", "c"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_swap", issue = "83163")] + #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] #[inline] #[track_caller] pub const fn swap(&mut self, a: usize, b: usize) { diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 8716c09492834..f18a3f72df349 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(clone_to_uninit)] #![feature(const_black_box)] #![feature(const_eval_select)] -#![feature(const_swap)] #![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] From 4bf3177fbc84fd56432428672beb36fff636b3d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Dec 2024 10:49:23 +0100 Subject: [PATCH 223/481] =?UTF-8?q?rename=20typed=5Fswap=20=E2=86=92=20typ?= =?UTF-8?q?ed=5Fswap=5Fnonoverlapping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/intrinsics/mod.rs | 19 +++++++++++++++++-- core/src/mem/mod.rs | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 21782f71da656..b5c31d824677d 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3969,6 +3969,21 @@ pub const fn is_val_statically_known(_arg: T) -> bool { false } +#[rustc_nounwind] +#[inline] +#[rustc_intrinsic] +#[rustc_intrinsic_const_stable_indirect] +#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic +#[cfg(bootstrap)] +pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { + // SAFETY: The caller provided single non-overlapping items behind + // pointers, so swapping them with `count: 1` is fine. + unsafe { ptr::swap_nonoverlapping(x, y, 1) }; +} + +#[cfg(bootstrap)] +pub use typed_swap as typed_swap_nonoverlapping; + /// Non-overlapping *typed* swap of a single value. /// /// The codegen backends will replace this with a better implementation when @@ -3982,10 +3997,10 @@ pub const fn is_val_statically_known(_arg: T) -> bool { #[rustc_nounwind] #[inline] #[rustc_intrinsic] -// Const-unstable because `swap_nonoverlapping` is const-unstable. #[rustc_intrinsic_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic -pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { +#[cfg(not(bootstrap))] +pub const unsafe fn typed_swap_nonoverlapping(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind // pointers, so swapping them with `count: 1` is fine. unsafe { ptr::swap_nonoverlapping(x, y, 1) }; diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 1576eb4315294..2d66e5c2f2a7a 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -730,7 +730,7 @@ pub unsafe fn uninitialized() -> T { pub const fn swap(x: &mut T, y: &mut T) { // SAFETY: `&mut` guarantees these are typed readable and writable // as well as non-overlapping. - unsafe { intrinsics::typed_swap(x, y) } + unsafe { intrinsics::typed_swap_nonoverlapping(x, y) } } /// Replaces `dest` with the default value of `T`, returning the previous `dest` value. From 7ea343d18d0c7d7b8cce9c796d64b6538b4ba602 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 30 Dec 2024 18:16:28 +0100 Subject: [PATCH 224/481] Make slice::as_flattened_mut unstably const Tracking issue: https://github.com/rust-lang/rust/issues/95629 Unblocked by const_mut_refs being stabilized: https://github.com/rust-lang/rust/pull/129195 --- core/src/slice/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 3e8c698a7aba4..df9720698d32f 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -4821,7 +4821,8 @@ impl [[T; N]] { /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - pub fn as_flattened_mut(&mut self) -> &mut [T] { + #[rustc_const_unstable(feature = "const_slice_flatten", issue = "95629")] + pub const fn as_flattened_mut(&mut self) -> &mut [T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") } else { From 0cdbe0ec2592d89cdd43e83f76d1fcc949a8a651 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Dec 2024 19:28:03 +0100 Subject: [PATCH 225/481] ptr docs: make it clear that we are talking only about memory accesses --- core/src/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index ac074c097d94c..dd61848d6e8be 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -15,8 +15,8 @@ //! The precise rules for validity are not determined yet. The guarantees that are //! provided at this point are very minimal: //! -//! * For operations of [size zero][zst], *every* pointer is valid, including the [null] pointer. -//! The following points are only concerned with non-zero-sized accesses. +//! * For memory accesses of [size zero][zst], *every* pointer is valid, including the [null] +//! pointer. The following points are only concerned with non-zero-sized accesses. //! * A [null] pointer is *never* valid. //! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer be //! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocated From 4fdcdc903223e23aedcee7d7bbbb99cd67278fc7 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 20 Dec 2024 12:13:30 +0000 Subject: [PATCH 226/481] Avoid short writes in LineWriter Also update the tests to avoid testing implementation details. --- std/src/io/buffered/linewritershim.rs | 9 ++++++++- std/src/io/buffered/tests.rs | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/std/src/io/buffered/linewritershim.rs b/std/src/io/buffered/linewritershim.rs index 3d04ccd1c7d81..5ebeada59bb53 100644 --- a/std/src/io/buffered/linewritershim.rs +++ b/std/src/io/buffered/linewritershim.rs @@ -119,7 +119,14 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { // the buffer? // - If not, scan for the last newline that *does* fit in the buffer let tail = if flushed >= newline_idx { - &buf[flushed..] + let tail = &buf[flushed..]; + // Avoid unnecessary short writes by not splitting the remaining + // bytes if they're larger than the buffer. + // They can be written in full by the next call to write. + if tail.len() >= self.buffer.capacity() { + return Ok(flushed); + } + tail } else if newline_idx - flushed <= self.buffer.capacity() { &buf[flushed..newline_idx] } else { diff --git a/std/src/io/buffered/tests.rs b/std/src/io/buffered/tests.rs index bff0f823c4b5a..17f6107aa030c 100644 --- a/std/src/io/buffered/tests.rs +++ b/std/src/io/buffered/tests.rs @@ -847,8 +847,7 @@ fn long_line_flushed() { } /// Test that, given a very long partial line *after* successfully -/// flushing a complete line, the very long partial line is buffered -/// unconditionally, and no additional writes take place. This assures +/// flushing a complete line, no additional writes take place. This assures /// the property that `write` should make at-most-one attempt to write /// new data. #[test] @@ -856,13 +855,22 @@ fn line_long_tail_not_flushed() { let writer = ProgrammableSink::default(); let mut writer = LineWriter::with_capacity(5, writer); - // Assert that Line 1\n is flushed, and 01234 is buffered - assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12); + // Assert that Line 1\n is flushed and the long tail isn't. + let bytes = b"Line 1\n0123456789"; + writer.write(bytes).unwrap(); assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); +} + +// Test that appending to a full buffer emits a single write, flushing the buffer. +#[test] +fn line_full_buffer_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + assert_eq!(writer.write(b"01234").unwrap(), 5); // Because the buffer is full, this subsequent write will flush it assert_eq!(writer.write(b"5").unwrap(), 1); - assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234"); + assert_eq!(&writer.get_ref().buffer, b"01234"); } /// Test that, if an attempt to pre-flush buffered data returns Ok(0), From 111b693f2f4bb58c5a22baab8db61337ad8242c7 Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Tue, 31 Dec 2024 10:59:13 +0800 Subject: [PATCH 227/481] fix doc for read write unaligned in zst operation --- core/src/ptr/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index dd61848d6e8be..a70af793004b2 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1403,8 +1403,6 @@ pub const unsafe fn read(src: *const T) -> T { /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned /// value and the value at `*src` can [violate memory safety][read-ownership]. /// -/// Note that even if `T` has size `0`, the pointer must be non-null. -/// /// [read-ownership]: read#ownership-of-the-returned-value /// [valid]: self#safety /// @@ -1611,8 +1609,6 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// /// * `dst` must be [valid] for writes. /// -/// Note that even if `T` has size `0`, the pointer must be non-null. -/// /// [valid]: self#safety /// /// ## On `packed` structs From 8e2e5e8f8673c9919ed9cb0e19b691425cbc557b Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 26 Oct 2024 14:02:50 -0400 Subject: [PATCH 228/481] Tidy up bigint mul methods --- core/src/lib.rs | 1 + core/src/num/int_macros.rs | 108 ++++++++++++++ core/src/num/uint_macros.rs | 272 +++++++++++++++++++--------------- core/tests/lib.rs | 5 +- core/tests/num/i128.rs | 2 +- core/tests/num/i16.rs | 2 +- core/tests/num/i32.rs | 2 +- core/tests/num/i64.rs | 2 +- core/tests/num/i8.rs | 2 +- core/tests/num/int_macros.rs | 100 ++++++++++++- core/tests/num/uint_macros.rs | 15 ++ 11 files changed, 388 insertions(+), 123 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 0d8a3811eded1..e31957a1fa703 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -110,6 +110,7 @@ #![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] +#![feature(bigint_helper_methods)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 9a202600988c4..96a290ad5a09d 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -2512,6 +2512,114 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// If you also need to add a carry to the wide result, then you want + /// [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5i32.widening_mul(-2), (4294967286, -1)); + /// assert_eq!(1_000_000_000i32.widening_mul(-10), (2884901888, -3)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> ($UnsignedT, Self) { + Self::carrying_mul_add(self, rhs, 0, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5i32.carrying_mul(-2, 0), (4294967286, -1)); + /// assert_eq!(5i32.carrying_mul(-2, 10), (0, 0)); + /// assert_eq!(1_000_000_000i32.carrying_mul(-10, 0), (2884901888, -3)); + /// assert_eq!(1_000_000_000i32.carrying_mul(-10, 10), (2884901898, -3)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(", stringify!($SelfT), "::MAX.unsigned_abs() + 1, ", stringify!($SelfT), "::MAX / 2));" + )] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> ($UnsignedT, Self) { + Self::carrying_mul_add(self, rhs, carry, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry1 + carry2` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need either `carry`, then you can use [`Self::widening_mul`] instead, + /// and if you only need one `carry`, then you can use [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5i32.carrying_mul_add(-2, 0, 0), (4294967286, -1)); + /// assert_eq!(5i32.carrying_mul_add(-2, 10, 10), (10, 0)); + /// assert_eq!(1_000_000_000i32.carrying_mul_add(-10, 0, 0), (2884901888, -3)); + /// assert_eq!(1_000_000_000i32.carrying_mul_add(-10, 10, 10), (2884901908, -3)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul_add(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(", stringify!($UnsignedT), "::MAX, ", stringify!($SelfT), "::MAX / 2));" + )] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> ($UnsignedT, Self) { + intrinsics::carrying_mul_add(self, rhs, carry, add) + } + /// Calculates the divisor when `self` is divided by `rhs`. /// /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 4a5fdbfb0ea2c..404e4bcffd379 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -2530,6 +2530,162 @@ macro_rules! uint_impl { (a as Self, b) } + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// If you also need to add a carry to the wide result, then you want + /// [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.widening_mul(2), (10, 0)); + /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { + Self::carrying_mul_add(self, rhs, 0, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); + /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(0, ", stringify!($SelfT), "::MAX));" + )] + /// ``` + /// + /// This is the core operation needed for scalar multiplication when + /// implementing it for wider-than-native types. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// fn scalar_mul_eq(little_endian_digits: &mut Vec, multiplicand: u16) { + /// let mut carry = 0; + /// for d in little_endian_digits.iter_mut() { + /// (*d, carry) = d.carrying_mul(multiplicand, carry); + /// } + /// if carry != 0 { + /// little_endian_digits.push(carry); + /// } + /// } + /// + /// let mut v = vec![10, 20]; + /// scalar_mul_eq(&mut v, 3); + /// assert_eq!(v, [30, 60]); + /// + /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); + /// let mut v = vec![0x4321, 0x8765]; + /// scalar_mul_eq(&mut v, 0xFEED); + /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]); + /// ``` + /// + /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), + /// except that it gives the value of the overflow instead of just whether one happened: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// let r = u8::carrying_mul(7, 13, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); + /// let r = u8::carrying_mul(13, 42, 0); + /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); + /// ``` + /// + /// The value of the first field in the returned tuple matches what you'd get + /// by combining the [`wrapping_mul`](Self::wrapping_mul) and + /// [`wrapping_add`](Self::wrapping_add) methods: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!( + /// 789_u16.carrying_mul(456, 123).0, + /// 789_u16.wrapping_mul(456).wrapping_add(123), + /// ); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { + Self::carrying_mul_add(self, rhs, carry, 0) + } + + /// Calculates the "full multiplication" `self * rhs + carry1 + carry2` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need either `carry`, then you can use [`Self::widening_mul`] instead, + /// and if you only need one `carry`, then you can use [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.carrying_mul_add(2, 0, 0), (10, 0)); + /// assert_eq!(5u32.carrying_mul_add(2, 10, 10), (30, 0)); + /// assert_eq!(1_000_000_000u32.carrying_mul_add(10, 0, 0), (1410065408, 2)); + /// assert_eq!(1_000_000_000u32.carrying_mul_add(10, 10, 10), (1410065428, 2)); + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_mul_add(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", + "(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX));" + )] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self, Self) { + intrinsics::carrying_mul_add(self, rhs, carry, add) + } + /// Calculates the divisor when `self` is divided by `rhs`. /// /// Returns a tuple of the divisor along with a boolean indicating @@ -3347,122 +3503,6 @@ macro_rules! uint_impl { unsafe { mem::transmute(bytes) } } - /// Calculates the complete product `self * rhs` without the possibility to overflow. - /// - /// This returns the low-order (wrapping) bits and the high-order (overflow) bits - /// of the result as two separate values, in that order. - /// - /// If you also need to add a carry to the wide result, then you want - /// [`Self::carrying_mul`] instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!(5u32.widening_mul(2), (10, 0)); - /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); - /// ``` - #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { - Self::carrying_mul(self, rhs, 0) - } - - /// Calculates the "full multiplication" `self * rhs + carry` - /// without the possibility to overflow. - /// - /// This returns the low-order (wrapping) bits and the high-order (overflow) bits - /// of the result as two separate values, in that order. - /// - /// Performs "long multiplication" which takes in an extra amount to add, and may return an - /// additional amount of overflow. This allows for chaining together multiple - /// multiplications to create "big integers" which represent larger values. - /// - /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); - /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); - /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); - /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); - #[doc = concat!("assert_eq!(", - stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ", - "(0, ", stringify!($SelfT), "::MAX));" - )] - /// ``` - /// - /// This is the core operation needed for scalar multiplication when - /// implementing it for wider-than-native types. - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// fn scalar_mul_eq(little_endian_digits: &mut Vec, multiplicand: u16) { - /// let mut carry = 0; - /// for d in little_endian_digits.iter_mut() { - /// (*d, carry) = d.carrying_mul(multiplicand, carry); - /// } - /// if carry != 0 { - /// little_endian_digits.push(carry); - /// } - /// } - /// - /// let mut v = vec![10, 20]; - /// scalar_mul_eq(&mut v, 3); - /// assert_eq!(v, [30, 60]); - /// - /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D); - /// let mut v = vec![0x4321, 0x8765]; - /// scalar_mul_eq(&mut v, 0xFEED); - /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]); - /// ``` - /// - /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul), - /// except that it gives the value of the overflow instead of just whether one happened: - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// let r = u8::carrying_mul(7, 13, 0); - /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13)); - /// let r = u8::carrying_mul(13, 42, 0); - /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42)); - /// ``` - /// - /// The value of the first field in the returned tuple matches what you'd get - /// by combining the [`wrapping_mul`](Self::wrapping_mul) and - /// [`wrapping_add`](Self::wrapping_add) methods: - /// - /// ``` - /// #![feature(bigint_helper_methods)] - /// assert_eq!( - /// 789_u16.carrying_mul(456, 123).0, - /// 789_u16.wrapping_mul(456).wrapping_add(123), - /// ); - /// ``` - #[unstable(feature = "bigint_helper_methods", issue = "85532")] - #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { - intrinsics::carrying_mul_add(self, rhs, 0, carry) - } - /// New code should prefer to use #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")] /// diff --git a/core/tests/lib.rs b/core/tests/lib.rs index f18a3f72df349..18feee9fb2545 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -98,10 +98,13 @@ /// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. macro_rules! assert_eq_const_safe { + ($left:expr, $right:expr) => { + assert_eq_const_safe!($left, $right, concat!(stringify!($left), " == ", stringify!($right))); + }; ($left:expr, $right:expr$(, $($arg:tt)+)?) => { { fn runtime() { - assert_eq!($left, $right, $($arg)*); + assert_eq!($left, $right, $($($arg)*),*); } const fn compiletime() { assert!(matches!($left, const { $right })); diff --git a/core/tests/num/i128.rs b/core/tests/num/i128.rs index 1ddd20f33d0b1..745fee05164c9 100644 --- a/core/tests/num/i128.rs +++ b/core/tests/num/i128.rs @@ -1 +1 @@ -int_module!(i128); +int_module!(i128, u128); diff --git a/core/tests/num/i16.rs b/core/tests/num/i16.rs index c7aa9fff964ed..6acb8371b87d8 100644 --- a/core/tests/num/i16.rs +++ b/core/tests/num/i16.rs @@ -1 +1 @@ -int_module!(i16); +int_module!(i16, u16); diff --git a/core/tests/num/i32.rs b/core/tests/num/i32.rs index efd5b1596a80d..38d5071f71d6c 100644 --- a/core/tests/num/i32.rs +++ b/core/tests/num/i32.rs @@ -1,4 +1,4 @@ -int_module!(i32); +int_module!(i32, u32); #[test] fn test_arith_operation() { diff --git a/core/tests/num/i64.rs b/core/tests/num/i64.rs index 93d23c10adf7e..f8dd5f9be7fe2 100644 --- a/core/tests/num/i64.rs +++ b/core/tests/num/i64.rs @@ -1 +1 @@ -int_module!(i64); +int_module!(i64, u64); diff --git a/core/tests/num/i8.rs b/core/tests/num/i8.rs index 887d4f17d25ff..a10906618c937 100644 --- a/core/tests/num/i8.rs +++ b/core/tests/num/i8.rs @@ -1 +1 @@ -int_module!(i8); +int_module!(i8, u8); diff --git a/core/tests/num/int_macros.rs b/core/tests/num/int_macros.rs index 474d57049ab65..f13b836378b9e 100644 --- a/core/tests/num/int_macros.rs +++ b/core/tests/num/int_macros.rs @@ -1,8 +1,10 @@ macro_rules! int_module { - ($T:ident) => { + ($T:ident, $U:ident) => { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T::*; + const UMAX: $U = $U::MAX; + use crate::num; #[test] @@ -355,6 +357,102 @@ macro_rules! int_module { assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); } + fn test_widening_mul() { + assert_eq_const_safe!(MAX.widening_mul(MAX), (1, MAX / 2)); + assert_eq_const_safe!(MIN.widening_mul(MAX), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(MIN.widening_mul(MIN), (0, MAX / 2 + 1)); + } + + fn test_carrying_mul() { + assert_eq_const_safe!(MAX.carrying_mul(MAX, 0), (1, MAX / 2)); + assert_eq_const_safe!( + MAX.carrying_mul(MAX, MAX), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul(MAX, MIN), + (UMAX / 2 + 2, MAX / 2 - 1) + ); + assert_eq_const_safe!(MIN.carrying_mul(MAX, 0), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MAX, MAX), (UMAX, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MAX, MIN), (0, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MIN, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!( + MIN.carrying_mul(MIN, MAX), + (UMAX / 2, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul(MIN, MIN), + (UMAX / 2 + 1, MAX / 2) + ); + } + + fn test_carrying_mul_add() { + assert_eq_const_safe!(MAX.carrying_mul_add(MAX, 0, 0), (1, MAX / 2)); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, 0), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MIN, 0), + (UMAX / 2 + 2, MAX / 2 - 1) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, MAX), + (UMAX, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, MIN), + (0, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MIN, MIN), + (1, MAX / 2 - 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, 0, 0), + (MIN as $U, MIN / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, 0), + (UMAX, MIN / 2) + ); + assert_eq_const_safe!(MIN.carrying_mul_add(MAX, MIN, 0), (0, MIN / 2)); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, MAX), + (UMAX / 2 - 1, MIN / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, MIN), + (UMAX / 2, MIN / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MIN, MIN), + (UMAX / 2 + 1, MIN / 2 - 1) + ); + assert_eq_const_safe!(MIN.carrying_mul_add(MIN, 0, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, 0), + (UMAX / 2, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MIN, 0), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, MAX), + (UMAX - 1, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, MIN), + (UMAX, MAX / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MIN, MIN), + (0, MAX / 2) + ); + } + fn test_midpoint() { assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); diff --git a/core/tests/num/uint_macros.rs b/core/tests/num/uint_macros.rs index ad8e48491e829..99a2d4cd462b1 100644 --- a/core/tests/num/uint_macros.rs +++ b/core/tests/num/uint_macros.rs @@ -277,6 +277,21 @@ macro_rules! uint_module { assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); } + fn test_widening_mul() { + assert_eq_const_safe!($T::MAX.widening_mul($T::MAX), (1, $T::MAX - 1)); + } + + fn test_carrying_mul() { + assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, $T::MAX), (0, $T::MAX)); + } + + fn test_carrying_mul_add() { + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, 0, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, 0), (0, $T::MAX)); + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, $T::MAX), ($T::MAX, $T::MAX)); + } + fn test_midpoint() { assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); From 497de1e34659aaa1a95b91029fef49cd5759e90d Mon Sep 17 00:00:00 2001 From: mu001999 Date: Mon, 14 Oct 2024 16:48:27 +0800 Subject: [PATCH 229/481] Remove allowing static_mut_refs lint --- panic_unwind/src/seh.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/panic_unwind/src/seh.rs b/panic_unwind/src/seh.rs index 565a2b8c573b4..5afa0a1975612 100644 --- a/panic_unwind/src/seh.rs +++ b/panic_unwind/src/seh.rs @@ -288,8 +288,6 @@ cfg_if::cfg_if! { } } -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] pub unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store_seqcst; From 03928296301a3ed10a7dd0f738c779e147439235 Mon Sep 17 00:00:00 2001 From: Marcondiro Date: Tue, 31 Dec 2024 15:57:46 +0100 Subject: [PATCH 230/481] char to_digit: avoid unnecessary casts to u64 --- core/src/char/methods.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/char/methods.rs b/core/src/char/methods.rs index 7d33765879f2f..fb8a740aced13 100644 --- a/core/src/char/methods.rs +++ b/core/src/char/methods.rs @@ -394,17 +394,21 @@ impl char { ); // check radix to remove letter handling code when radix is a known constant let value = if self > '9' && radix > 10 { - // convert ASCII letters to lowercase - let lower = self as u32 | 0x20; - // convert an ASCII letter to the corresponding value, - // non-letters convert to values > 36 - lower.wrapping_sub('a' as u32) as u64 + 10 + // mask to convert ASCII letters to uppercase + const TO_UPPERCASE_MASK: u32 = !0b0010_0000; + // Converts an ASCII letter to its corresponding integer value: + // A-Z => 10-35, a-z => 10-35. Other characters produce values >= 36. + // + // Add Overflow Safety: + // By applying the mask after the subtraction, the first addendum is + // constrained such that it never exceeds u32::MAX - 0x20. + ((self as u32).wrapping_sub('A' as u32) & TO_UPPERCASE_MASK) + 10 } else { // convert digit to value, non-digits wrap to values > 36 - (self as u32).wrapping_sub('0' as u32) as u64 + (self as u32).wrapping_sub('0' as u32) }; // FIXME(const-hack): once then_some is const fn, use it here - if value < radix as u64 { Some(value as u32) } else { None } + if value < radix { Some(value) } else { None } } /// Returns an iterator that yields the hexadecimal Unicode escape of a From 1fcb698d4b230b5abfcda4acea541c7a9eac2bc9 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 9 Dec 2024 15:06:31 +0100 Subject: [PATCH 231/481] Avoid use of LFS64 symbols on Emscripten Since Emscripten uses musl libc internally. Non-functional change: all LFS64 symbols were aliased to their non-LFS64 counterparts in rust-lang/libc@7c952dceaad4cdc35e00884fcb12a713d41a87e0. --- std/src/os/emscripten/fs.rs | 2 +- std/src/os/emscripten/raw.rs | 2 -- std/src/sys/pal/unix/fd.rs | 2 -- std/src/sys/pal/unix/fs.rs | 5 +---- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/std/src/os/emscripten/fs.rs b/std/src/os/emscripten/fs.rs index 3282b79ac1c81..81f9ef331a5fa 100644 --- a/std/src/os/emscripten/fs.rs +++ b/std/src/os/emscripten/fs.rs @@ -63,7 +63,7 @@ pub trait MetadataExt { impl MetadataExt for Metadata { #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) } + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 diff --git a/std/src/os/emscripten/raw.rs b/std/src/os/emscripten/raw.rs index d23011c738141..7ae8c45a6f80a 100644 --- a/std/src/os/emscripten/raw.rs +++ b/std/src/os/emscripten/raw.rs @@ -1,6 +1,4 @@ //! Emscripten-specific raw type definitions -//! This is basically exactly the same as the linux definitions, -//! except using the musl-specific stat64 structure in liblibc. #![stable(feature = "raw_ext", since = "1.1.0")] #![deprecated( diff --git a/std/src/sys/pal/unix/fd.rs b/std/src/sys/pal/unix/fd.rs index 6a28799ca55eb..2fc33bdfefbf5 100644 --- a/std/src/sys/pal/unix/fd.rs +++ b/std/src/sys/pal/unix/fd.rs @@ -5,7 +5,6 @@ mod tests; #[cfg(not(any( target_os = "linux", - target_os = "emscripten", target_os = "l4re", target_os = "android", target_os = "hurd", @@ -14,7 +13,6 @@ use libc::off_t as off64_t; #[cfg(any( target_os = "android", target_os = "linux", - target_os = "emscripten", target_os = "l4re", target_os = "hurd", ))] diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 3307fa47c7f88..63c27728ca4b1 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -34,7 +34,6 @@ use libc::readdir as readdir64; #[cfg(not(any( target_os = "android", target_os = "linux", - target_os = "emscripten", target_os = "solaris", target_os = "illumos", target_os = "l4re", @@ -48,7 +47,7 @@ use libc::readdir as readdir64; use libc::readdir_r as readdir64_r; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::readdir64; -#[cfg(any(target_os = "emscripten", target_os = "l4re"))] +#[cfg(target_os = "l4re")] use libc::readdir64_r; use libc::{c_int, mode_t}; #[cfg(target_os = "android")] @@ -58,7 +57,6 @@ use libc::{ }; #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "l4re", target_os = "android", target_os = "hurd", @@ -69,7 +67,6 @@ use libc::{ }; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "l4re", target_os = "hurd" ))] From 790a0c9795f50ae9af4567e881ffb9a9ba7798c1 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 9 Dec 2024 15:09:34 +0100 Subject: [PATCH 232/481] std::fs::DirEntry.metadata(): prefer use of lstat() on Emscripten Align it with musl, which also prefers using lstat() here. --- std/src/sys/pal/unix/fs.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 63c27728ca4b1..54fa31620aced 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -8,16 +8,11 @@ mod tests; use libc::c_char; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "android", target_os = "hurd" ))] use libc::dirfd; -#[cfg(any( - all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", - target_os = "hurd" -))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::fstatat64; #[cfg(any( target_os = "android", @@ -896,7 +891,6 @@ impl DirEntry { #[cfg(all( any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "android", target_os = "hurd" ), @@ -925,7 +919,6 @@ impl DirEntry { #[cfg(any( not(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "android", target_os = "hurd", )), From 0e213f9664618401531ae78e8cad4e6056e55bde Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Tue, 31 Dec 2024 14:29:03 -0700 Subject: [PATCH 233/481] Remove qualification of `std::cmp::Ordering` in `Ord` doc --- core/src/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/cmp.rs b/core/src/cmp.rs index 5a3b9365cd220..97974d195fec6 100644 --- a/core/src/cmp.rs +++ b/core/src/cmp.rs @@ -796,7 +796,7 @@ impl Clone for Reverse { /// } /// /// impl Ord for Character { -/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// fn cmp(&self, other: &Self) -> Ordering { /// self.experience /// .cmp(&other.experience) /// .then(self.health.cmp(&other.health)) From 6693134f14e58914ec470e89b1d0dfef1bc2af14 Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Thu, 2 Jan 2025 11:12:31 +0800 Subject: [PATCH 234/481] fix doc for missing Box allocator consistency --- alloc/src/boxed.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index ca3bd24a42031..05e5d712a2737 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -1045,6 +1045,8 @@ impl Box { /// 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 the global allocator. + /// /// The safety conditions are described in the [memory layout] section. /// /// # Examples @@ -1148,6 +1150,7 @@ impl Box { /// 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 /// From 9203dbbd53f83782a1b618bd62d3892c70bf3dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 15 Mar 2024 19:09:24 +0100 Subject: [PATCH 235/481] Try to write the panic message with a single `write_all` call --- std/src/panicking.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/std/src/panicking.rs b/std/src/panicking.rs index e7ce5bc61401d..3b02254548b1c 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -266,7 +266,23 @@ fn default_hook(info: &PanicHookInfo<'_>) { // Use a lock to prevent mixed output in multithreading context. // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. let mut lock = backtrace::lock(); - let _ = writeln!(err, "thread '{name}' panicked at {location}:\n{msg}"); + // Try to write the panic message to a buffer first to prevent other concurrent outputs + // interleaving with it. + let mut buffer = [0u8; 512]; + let mut cursor = crate::io::Cursor::new(&mut buffer[..]); + + let write_msg = |dst: &mut dyn crate::io::Write| { + // We add a newline to ensure the panic message appears at the start of a line. + writeln!(dst, "\nthread '{name}' panicked at {location}:\n{msg}") + }; + + if write_msg(&mut cursor).is_ok() { + let pos = cursor.position() as usize; + let _ = err.write_all(&buffer[0..pos]); + } else { + // The message did not fit into the buffer, write it directly instead. + let _ = write_msg(err); + }; static FIRST_PANIC: AtomicBool = AtomicBool::new(true); From 0d30927bafda294d867c370be7a646974c999b2f Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 2 Jan 2025 17:06:28 -0800 Subject: [PATCH 236/481] Bump backtrace to rust-lang/backtrace-rs@4d7906b Compare: https://github.com/rust-lang/backtrace-rs/compare/230570f...4d7906b Mostly cleanups and enabling backtraces for the RTEMS target. --- backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtrace b/backtrace index 230570f2dac80..4d7906bb24ae9 160000 --- a/backtrace +++ b/backtrace @@ -1 +1 @@ -Subproject commit 230570f2dac80a601f5c0b30da00cc9480bd35eb +Subproject commit 4d7906bb24ae91ee6587127020d360f5298f9e7e From 57c71d2eb0b491dae2e62ced92e8554f18a2a955 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Mon, 23 Dec 2024 19:36:41 +0300 Subject: [PATCH 237/481] Move some things to `std::sync::poison` and reexport them in `std::sync` --- std/src/sync/barrier.rs | 1 + std/src/sync/lazy_lock.rs | 3 +- std/src/sync/mod.rs | 56 +++++++++----- std/src/sync/once_lock.rs | 1 + std/src/sync/poison.rs | 87 +++++++++++++++++++++- std/src/sync/{ => poison}/condvar.rs | 4 +- std/src/sync/{ => poison}/condvar/tests.rs | 0 std/src/sync/{ => poison}/mutex.rs | 0 std/src/sync/{ => poison}/mutex/tests.rs | 0 std/src/sync/{ => poison}/once.rs | 0 std/src/sync/{ => poison}/once/tests.rs | 0 std/src/sync/{ => poison}/rwlock.rs | 0 std/src/sync/{ => poison}/rwlock/tests.rs | 0 std/src/sys/sync/once/futex.rs | 2 +- std/src/sys/sync/once/no_threads.rs | 2 +- std/src/sys/sync/once/queue.rs | 2 +- 16 files changed, 131 insertions(+), 27 deletions(-) rename std/src/sync/{ => poison}/condvar.rs (99%) rename std/src/sync/{ => poison}/condvar/tests.rs (100%) rename std/src/sync/{ => poison}/mutex.rs (100%) rename std/src/sync/{ => poison}/mutex/tests.rs (100%) rename std/src/sync/{ => poison}/once.rs (100%) rename std/src/sync/{ => poison}/once/tests.rs (100%) rename std/src/sync/{ => poison}/rwlock.rs (100%) rename std/src/sync/{ => poison}/rwlock/tests.rs (100%) diff --git a/std/src/sync/barrier.rs b/std/src/sync/barrier.rs index 14e4a9abe6f17..862753e4765dc 100644 --- a/std/src/sync/barrier.rs +++ b/std/src/sync/barrier.rs @@ -2,6 +2,7 @@ mod tests; use crate::fmt; +// FIXME(nonpoison_mutex,nonpoison_condvar): switch to nonpoison versions once they are available use crate::sync::{Condvar, Mutex}; /// A barrier enables multiple threads to synchronize the beginning diff --git a/std/src/sync/lazy_lock.rs b/std/src/sync/lazy_lock.rs index 40510f5613450..1e4f9b79e0f4a 100644 --- a/std/src/sync/lazy_lock.rs +++ b/std/src/sync/lazy_lock.rs @@ -1,4 +1,4 @@ -use super::once::ExclusiveState; +use super::poison::once::ExclusiveState; use crate::cell::UnsafeCell; use crate::mem::ManuallyDrop; use crate::ops::Deref; @@ -63,6 +63,7 @@ union Data { /// ``` #[stable(feature = "lazy_cell", since = "1.80.0")] pub struct LazyLock T> { + // FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available once: Once, data: UnsafeCell>, } diff --git a/std/src/sync/mod.rs b/std/src/sync/mod.rs index 0fb77331293fe..5b50a3c6ccf90 100644 --- a/std/src/sync/mod.rs +++ b/std/src/sync/mod.rs @@ -167,6 +167,10 @@ #![stable(feature = "rust1", since = "1.0.0")] +// No formatting: this file is just re-exports, and their order is worth preserving. +#![cfg_attr(rustfmt, rustfmt::skip)] + +// These come from `core` & `alloc` and only in one flavor: no poisoning. #[unstable(feature = "exclusive_wrapper", issue = "98407")] pub use core::sync::Exclusive; #[stable(feature = "rust1", since = "1.0.0")] @@ -175,40 +179,54 @@ pub use core::sync::atomic; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::sync::{Arc, Weak}; +// FIXME(sync_nonpoison,sync_poison_mod): remove all `#[doc(inline)]` once the modules are stabilized. + +// These exist only in one flavor: no poisoning. #[stable(feature = "rust1", since = "1.0.0")] pub use self::barrier::{Barrier, BarrierWaitResult}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::condvar::{Condvar, WaitTimeoutResult}; #[stable(feature = "lazy_cell", since = "1.80.0")] pub use self::lazy_lock::LazyLock; -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -pub use self::mutex::MappedMutexGuard; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::mutex::{Mutex, MutexGuard}; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use self::once::{ONCE_INIT, Once, OnceState}; #[stable(feature = "once_cell", since = "1.70.0")] pub use self::once_lock::OnceLock; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult}; #[unstable(feature = "reentrant_lock", issue = "121440")] pub use self::reentrant_lock::{ReentrantLock, ReentrantLockGuard}; -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; + +// These make sense and exist only with poisoning. #[stable(feature = "rust1", since = "1.0.0")] -pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +#[doc(inline)] +pub use self::poison::{LockResult, PoisonError}; + +// These (should) exist in both flavors: with and without poisoning. +// FIXME(sync_nonpoison): implement nonpoison versions: +// * Mutex (nonpoison_mutex) +// * Condvar (nonpoison_condvar) +// * Once (nonpoison_once) +// * RwLock (nonpoison_rwlock) +// The historical default is the version with poisoning. +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] +pub use self::poison::{ + Mutex, MutexGuard, TryLockError, TryLockResult, + Condvar, WaitTimeoutResult, + Once, OnceState, + RwLock, RwLockReadGuard, RwLockWriteGuard, +}; +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] +#[expect(deprecated)] +pub use self::poison::ONCE_INIT; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +#[doc(inline)] +pub use self::poison::{MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard}; #[unstable(feature = "mpmc_channel", issue = "126840")] pub mod mpmc; pub mod mpsc; +#[unstable(feature = "sync_poison_mod", issue = "134646")] +pub mod poison; + mod barrier; -mod condvar; mod lazy_lock; -mod mutex; -pub(crate) mod once; mod once_lock; -mod poison; mod reentrant_lock; -mod rwlock; diff --git a/std/src/sync/once_lock.rs b/std/src/sync/once_lock.rs index 0ae3cf4df3614..49f2dafd8fd9c 100644 --- a/std/src/sync/once_lock.rs +++ b/std/src/sync/once_lock.rs @@ -101,6 +101,7 @@ use crate::sync::Once; /// ``` #[stable(feature = "once_cell", since = "1.70.0")] pub struct OnceLock { + // FIXME(nonpoison_once): switch to nonpoison version once it is available once: Once, // Whether or not the value is initialized is tracked by `once.is_completed()`. value: UnsafeCell>, diff --git a/std/src/sync/poison.rs b/std/src/sync/poison.rs index 9eb900c210350..1b8809734b8a8 100644 --- a/std/src/sync/poison.rs +++ b/std/src/sync/poison.rs @@ -1,3 +1,78 @@ +//! Synchronization objects that employ poisoning. +//! +//! # Poisoning +//! +//! All synchronization objects in this module implement a strategy called "poisoning" +//! where if a thread panics while holding the exclusive access granted by the primitive, +//! the state of the primitive is set to "poisoned". +//! This information is then propagated to all other threads +//! to signify that the data protected by this primitive is likely tainted +//! (some invariant is not being upheld). +//! +//! The specifics of how this "poisoned" state affects other threads +//! depend on the primitive. See [#Overview] bellow. +//! +//! For the alternative implementations that do not employ poisoning, +//! see `std::sys::nonpoisoning`. +//! +//! # Overview +//! +//! Below is a list of synchronization objects provided by this module +//! with a high-level overview for each object and a description +//! of how it employs "poisoning". +//! +//! - [`Condvar`]: Condition Variable, providing the ability to block +//! a thread while waiting for an event to occur. +//! +//! Condition variables are typically associated with +//! a boolean predicate (a condition) and a mutex. +//! This implementation is associated with [`poison::Mutex`](Mutex), +//! which employs poisoning. +//! For this reason, [`Condvar::wait()`] will return a [`LockResult`], +//! just like [`poison::Mutex::lock()`](Mutex::lock) does. +//! +//! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at +//! most one thread at a time is able to access some data. +//! +//! [`Mutex::lock()`] returns a [`LockResult`], +//! providing a way to deal with the poisoned state. +//! See [`Mutex`'s documentation](Mutex#poisoning) for more. +//! +//! - [`Once`]: A thread-safe way to run a piece of code only once. +//! Mostly useful for implementing one-time global initialization. +//! +//! [`Once`] is poisoned if the piece of code passed to +//! [`Once::call_once()`] or [`Once::call_once_force()`] panics. +//! When in poisoned state, subsequent calls to [`Once::call_once()`] will panic too. +//! [`Once::call_once_force()`] can be used to clear the poisoned state. +//! +//! - [`RwLock`]: Provides a mutual exclusion mechanism which allows +//! multiple readers at the same time, while allowing only one +//! writer at a time. In some cases, this can be more efficient than +//! a mutex. +//! +//! This implementation, like [`Mutex`], will become poisoned on a panic. +//! Note, however, that an `RwLock` may only be poisoned if a panic occurs +//! while it is locked exclusively (write mode). If a panic occurs in any reader, +//! then the lock will not be poisoned. + +// FIXME(sync_nonpoison) add links to sync::nonpoison to the doc comment above. + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::condvar::{Condvar, WaitTimeoutResult}; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +pub use self::mutex::MappedMutexGuard; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::mutex::{Mutex, MutexGuard}; +#[stable(feature = "rust1", since = "1.0.0")] +#[expect(deprecated)] +pub use self::once::ONCE_INIT; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::once::{Once, OnceState}; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use crate::error::Error; use crate::fmt; #[cfg(panic = "unwind")] @@ -5,7 +80,13 @@ use crate::sync::atomic::{AtomicBool, Ordering}; #[cfg(panic = "unwind")] use crate::thread; -pub struct Flag { +mod condvar; +#[stable(feature = "rust1", since = "1.0.0")] +mod mutex; +pub(crate) mod once; +mod rwlock; + +pub(crate) struct Flag { #[cfg(panic = "unwind")] failed: AtomicBool, } @@ -78,7 +159,7 @@ impl Flag { } #[derive(Clone)] -pub struct Guard { +pub(crate) struct Guard { #[cfg(panic = "unwind")] panicking: bool, } @@ -316,7 +397,7 @@ impl Error for TryLockError { } } -pub fn map_result(result: LockResult, f: F) -> LockResult +pub(crate) fn map_result(result: LockResult, f: F) -> LockResult where F: FnOnce(T) -> U, { diff --git a/std/src/sync/condvar.rs b/std/src/sync/poison/condvar.rs similarity index 99% rename from std/src/sync/condvar.rs rename to std/src/sync/poison/condvar.rs index 44ffcb528d937..a6e2389c93baf 100644 --- a/std/src/sync/condvar.rs +++ b/std/src/sync/poison/condvar.rs @@ -2,7 +2,7 @@ mod tests; use crate::fmt; -use crate::sync::{LockResult, MutexGuard, PoisonError, mutex, poison}; +use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex}; use crate::sys::sync as sys; use crate::time::{Duration, Instant}; @@ -16,6 +16,8 @@ use crate::time::{Duration, Instant}; #[stable(feature = "wait_timeout", since = "1.5.0")] pub struct WaitTimeoutResult(bool); +// FIXME(sync_nonpoison): `WaitTimeoutResult` is actually poisoning-agnostic, it seems. +// Should we take advantage of this fact? impl WaitTimeoutResult { /// Returns `true` if the wait was known to have timed out. /// diff --git a/std/src/sync/condvar/tests.rs b/std/src/sync/poison/condvar/tests.rs similarity index 100% rename from std/src/sync/condvar/tests.rs rename to std/src/sync/poison/condvar/tests.rs diff --git a/std/src/sync/mutex.rs b/std/src/sync/poison/mutex.rs similarity index 100% rename from std/src/sync/mutex.rs rename to std/src/sync/poison/mutex.rs diff --git a/std/src/sync/mutex/tests.rs b/std/src/sync/poison/mutex/tests.rs similarity index 100% rename from std/src/sync/mutex/tests.rs rename to std/src/sync/poison/mutex/tests.rs diff --git a/std/src/sync/once.rs b/std/src/sync/poison/once.rs similarity index 100% rename from std/src/sync/once.rs rename to std/src/sync/poison/once.rs diff --git a/std/src/sync/once/tests.rs b/std/src/sync/poison/once/tests.rs similarity index 100% rename from std/src/sync/once/tests.rs rename to std/src/sync/poison/once/tests.rs diff --git a/std/src/sync/rwlock.rs b/std/src/sync/poison/rwlock.rs similarity index 100% rename from std/src/sync/rwlock.rs rename to std/src/sync/poison/rwlock.rs diff --git a/std/src/sync/rwlock/tests.rs b/std/src/sync/poison/rwlock/tests.rs similarity index 100% rename from std/src/sync/rwlock/tests.rs rename to std/src/sync/poison/rwlock/tests.rs diff --git a/std/src/sys/sync/once/futex.rs b/std/src/sys/sync/once/futex.rs index 10bfa81a6d72a..539f0fe89eaaa 100644 --- a/std/src/sys/sync/once/futex.rs +++ b/std/src/sys/sync/once/futex.rs @@ -1,7 +1,7 @@ use crate::cell::Cell; use crate::sync as public; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sync::once::ExclusiveState; +use crate::sync::poison::once::ExclusiveState; use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all}; // On some platforms, the OS is very nice and handles the waiter queue for us. diff --git a/std/src/sys/sync/once/no_threads.rs b/std/src/sys/sync/once/no_threads.rs index 88a1d50361ee4..2568059cfe3a8 100644 --- a/std/src/sys/sync/once/no_threads.rs +++ b/std/src/sys/sync/once/no_threads.rs @@ -1,6 +1,6 @@ use crate::cell::Cell; use crate::sync as public; -use crate::sync::once::ExclusiveState; +use crate::sync::poison::once::ExclusiveState; pub struct Once { state: Cell, diff --git a/std/src/sys/sync/once/queue.rs b/std/src/sys/sync/once/queue.rs index 5beff4ce6836c..fde1e0ca51029 100644 --- a/std/src/sys/sync/once/queue.rs +++ b/std/src/sys/sync/once/queue.rs @@ -58,7 +58,7 @@ use crate::cell::Cell; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Release}; use crate::sync::atomic::{AtomicBool, AtomicPtr}; -use crate::sync::once::ExclusiveState; +use crate::sync::poison::once::ExclusiveState; use crate::thread::{self, Thread}; use crate::{fmt, ptr, sync as public}; From 3ceae4d1092bbd4334ed539ab6e64e1169fd3fc3 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Thu, 2 Jan 2025 22:30:56 +0800 Subject: [PATCH 238/481] path in detail --- std/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/lib.rs b/std/src/lib.rs index 1c80694ca8f24..2f8f5c5c58180 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -89,7 +89,7 @@ //! Check out the Rust contribution guidelines [here]( //! https://rustc-dev-guide.rust-lang.org/contributing.html#writing-documentation). //! The source for this documentation can be found on -//! [GitHub](https://github.com/rust-lang/rust). +//! [GitHub](https://github.com/rust-lang/rust) in the 'library/std/' directory. //! To contribute changes, make sure you read the guidelines first, then submit //! pull-requests for your suggested changes. //! From f436a088fe6b6cdb5ee693a36435f4a7399dd3f2 Mon Sep 17 00:00:00 2001 From: Jan Sommer Date: Sat, 23 Nov 2024 23:59:03 +0100 Subject: [PATCH 239/481] Switch rtems target to panic unwind --- panic_unwind/src/lib.rs | 2 +- std/src/sys/personality/mod.rs | 2 +- unwind/src/lib.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/panic_unwind/src/lib.rs b/panic_unwind/src/lib.rs index 1981675f40922..8c28bb5c5b033 100644 --- a/panic_unwind/src/lib.rs +++ b/panic_unwind/src/lib.rs @@ -46,7 +46,7 @@ cfg_if::cfg_if! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems", target_os = "nuttx"))), + all(target_family = "unix", not(any(target_os = "espidf", target_os = "nuttx"))), all(target_vendor = "fortanix", target_env = "sgx"), target_family = "wasm", ))] { diff --git a/std/src/sys/personality/mod.rs b/std/src/sys/personality/mod.rs index 9754e840d151a..2e1d2e53a2979 100644 --- a/std/src/sys/personality/mod.rs +++ b/std/src/sys/personality/mod.rs @@ -31,7 +31,7 @@ cfg_if::cfg_if! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems"), not(target_os = "nuttx")), + all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "nuttx")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod gcc; diff --git a/unwind/src/lib.rs b/unwind/src/lib.rs index 40d409310ffab..7af1882ab73a9 100644 --- a/unwind/src/lib.rs +++ b/unwind/src/lib.rs @@ -20,7 +20,6 @@ cfg_if::cfg_if! { target_os = "l4re", target_os = "none", target_os = "espidf", - target_os = "rtems", target_os = "nuttx", ))] { // These "unix" family members do not have unwinder. From 6dfef549bd802fa0b7b887c3062d81108bbb1e5b Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 6 Dec 2024 15:05:14 +0100 Subject: [PATCH 240/481] core: implement `bool::select_unpredictable` --- core/src/bool.rs | 46 ++++++++++++++++++++++++++++++++++++++ core/src/intrinsics/mod.rs | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/core/src/bool.rs b/core/src/bool.rs index 1590b9f29fcae..d9092cab141fa 100644 --- a/core/src/bool.rs +++ b/core/src/bool.rs @@ -61,4 +61,50 @@ impl bool { pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } } + + /// Returns either `true_val` or `false_val` depending on the value of + /// `condition`, with a hint to the compiler that `condition` is unlikely + /// to be correctly predicted by a CPU’s branch predictor. + /// + /// This method is functionally equivalent to writing + /// ```ignore (this is just for illustrative purposes) + /// if b { true_val } else { false_val } + /// ``` + /// but might generate different assembly. In particular, on platforms with + /// a conditional move or select instruction (like `cmov` on x86 or `csel` + /// on ARM) the optimizer might use these instructions to avoid branches, + /// which can benefit performance if the branch predictor is struggling + /// with predicting `condition`, such as in an implementation of binary + /// search. + /// + /// Note however that this lowering is not guaranteed (on any platform) and + /// should not be relied upon when trying to write constant-time code. Also + /// be aware that this lowering might *decrease* performance if `condition` + /// is well-predictable. It is advisable to perform benchmarks to tell if + /// this function is useful. + /// + /// # Examples + /// + /// Distribute values evenly between two buckets: + /// ``` + /// #![feature(select_unpredictable)] + /// + /// use std::hash::BuildHasher; + /// + /// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { + /// let hash = hasher.hash_one(&v); + /// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two); + /// bucket.push(v); + /// } + /// # let hasher = std::collections::hash_map::RandomState::new(); + /// # let mut bucket_one = Vec::new(); + /// # let mut bucket_two = Vec::new(); + /// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); + /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); + /// ``` + #[inline(always)] + #[unstable(feature = "select_unpredictable", issue = "133962")] + pub fn select_unpredictable(self, true_val: T, false_val: T) -> T { + crate::intrinsics::select_unpredictable(self, true_val, false_val) + } } diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index b5c31d824677d..7d44ea7a66ba5 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1545,7 +1545,7 @@ pub const fn unlikely(b: bool) -> bool { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// This intrinsic does not have a stable counterpart. +/// The public form of this instrinsic is [`bool::select_unpredictable`]. #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] From 90eec010e56b1c4db6853ebc7324625610fa6beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6ttiger?= Date: Mon, 9 Dec 2024 13:22:39 +0100 Subject: [PATCH 241/481] core: improve comments Co-authored-by: Yotam Ofek Co-authored-by: Hanna Kruppe --- core/src/bool.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/bool.rs b/core/src/bool.rs index d9092cab141fa..3c589ca5dfa7e 100644 --- a/core/src/bool.rs +++ b/core/src/bool.rs @@ -63,12 +63,14 @@ impl bool { } /// Returns either `true_val` or `false_val` depending on the value of - /// `condition`, with a hint to the compiler that `condition` is unlikely + /// `self`, with a hint to the compiler that `self` is unlikely /// to be correctly predicted by a CPU’s branch predictor. /// - /// This method is functionally equivalent to writing + /// This method is functionally equivalent to /// ```ignore (this is just for illustrative purposes) - /// if b { true_val } else { false_val } + /// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { + /// if b { true_val } else { false_val } + /// } /// ``` /// but might generate different assembly. In particular, on platforms with /// a conditional move or select instruction (like `cmov` on x86 or `csel` From e4c4671e28e8b50ccfd1ffd4dd44c8595906c15b Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 9 Dec 2024 13:27:06 +0100 Subject: [PATCH 242/481] core: use public method instead of instrinsic --- core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index df9720698d32f..073cca7daef07 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -7,7 +7,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::cmp::Ordering::{self, Equal, Greater, Less}; -use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub}; +use crate::intrinsics::{exact_div, unchecked_sub}; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive}; @@ -2835,7 +2835,7 @@ impl [T] { // Binary search interacts poorly with branch prediction, so force // the compiler to use conditional moves if supported by the target // architecture. - base = select_unpredictable(cmp == Greater, base, mid); + base = (cmp == Greater).select_unpredictable(base, mid); // This is imprecise in the case where `size` is odd and the // comparison returns Greater: the mid element still gets included From 612a517ac44f52b7e81e522e4950fbd0ca7376a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jan 2025 21:22:42 +0100 Subject: [PATCH 243/481] turn rustc_box into an intrinsic --- alloc/src/alloc.rs | 2 +- alloc/src/boxed.rs | 24 ++++++++++++++++++++++-- alloc/src/lib.rs | 1 + alloc/src/macros.rs | 5 ++--- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/alloc/src/alloc.rs b/alloc/src/alloc.rs index ae34fc653260e..e9b7f9856677c 100644 --- a/alloc/src/alloc.rs +++ b/alloc/src/alloc.rs @@ -339,7 +339,7 @@ unsafe impl Allocator for Global { } } -/// The allocator for unique pointers. +/// The allocator for `Box`. #[cfg(all(not(no_global_oom_handling), not(test)))] #[lang = "exchange_malloc"] #[inline] diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 05e5d712a2737..0f66217b5cb33 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -233,6 +233,27 @@ pub struct Box< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, >(Unique, A); +/// Constructs a `Box` by calling the `exchange_malloc` lang item and moving the argument into +/// the newly allocated memory. This is an intrinsic to avoid unnecessary copies. +/// +/// This is the surface syntax for `box ` expressions. +#[cfg(not(bootstrap))] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[unstable(feature = "liballoc_internals", issue = "none")] +pub fn box_new(_x: T) -> Box { + unreachable!() +} + +/// Transition function for the next bootstrap bump. +#[cfg(bootstrap)] +#[unstable(feature = "liballoc_internals", issue = "none")] +#[inline(always)] +pub fn box_new(x: T) -> Box { + #[rustc_box] + Box::new(x) +} + impl Box { /// Allocates memory on the heap and then places `x` into it. /// @@ -250,8 +271,7 @@ impl Box { #[rustc_diagnostic_item = "box_new"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn new(x: T) -> Self { - #[rustc_box] - Box::new(x) + return box_new(x); } /// Constructs a new box with uninitialized contents. diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 40759cb0ba83c..aff90f5abb3a0 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -168,6 +168,7 @@ #![feature(dropck_eyepatch)] #![feature(fundamental)] #![feature(hashmap_internals)] +#![feature(intrinsics)] #![feature(lang_items)] #![feature(min_specialization)] #![feature(multiple_supertrait_upcastable)] diff --git a/alloc/src/macros.rs b/alloc/src/macros.rs index 8c6a367869ce0..6ee3907cc8ea2 100644 --- a/alloc/src/macros.rs +++ b/alloc/src/macros.rs @@ -48,10 +48,9 @@ macro_rules! vec { ); ($($x:expr),+ $(,)?) => ( <[_]>::into_vec( - // This rustc_box is not required, but it produces a dramatic improvement in compile + // Using the intrinsic produces a dramatic improvement in compile // time when constructing arrays with many elements. - #[rustc_box] - $crate::boxed::Box::new([$($x),+]) + $crate::boxed::box_new([$($x),+]) ) ); } From a58c6b06c032628a165ac53df989fdf23d10186c Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 3 Jan 2025 15:26:18 +0300 Subject: [PATCH 244/481] sync to actual dep verions of backtrace --- Cargo.lock | 31 ++++++++++--------------------- std/Cargo.toml | 4 ++-- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40edd2c211cd3..207c744ee2248 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,21 +4,21 @@ version = 4 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "compiler_builtins", - "gimli 0.29.0", + "gimli", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -111,17 +111,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "gimli" version = "0.31.1" @@ -177,11 +166,11 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ - "adler", + "adler2", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -408,7 +397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51f06a05848f650946acef3bf525fe96612226b61f74ae23ffa4e98bfbb8ab3c" dependencies = [ "compiler_builtins", - "gimli 0.31.1", + "gimli", "rustc-std-workspace-core", ] diff --git a/std/Cargo.toml b/std/Cargo.toml index 6380c941e6ab5..e7f7f38cb4154 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -30,8 +30,8 @@ std_detect = { path = "../stdarch/crates/std_detect", default-features = false, rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] -miniz_oxide = { version = "0.7.0", optional = true, default-features = false } -addr2line = { version = "0.22.0", optional = true, default-features = false } +miniz_oxide = { version = "0.8.0", optional = true, default-features = false } +addr2line = { version = "0.24.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.169", default-features = false, features = [ From ea9cd6a287406911b19bda36f35cc9890dab4a58 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 3 Jan 2025 20:12:37 -0800 Subject: [PATCH 245/481] Bump backtrace to 0.3.75 I prefer when we can ship the same version of backtrace on crates.io, and this will be the next published version. Compare: https://github.com/rust-lang/backtrace-rs/compare/4d7906b...0.3.75 Mostly internal-to-backtrace changes, plus a tiny code size win. --- backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtrace b/backtrace index 4d7906bb24ae9..f8cc6ac9acc4e 160000 --- a/backtrace +++ b/backtrace @@ -1 +1 @@ -Subproject commit 4d7906bb24ae91ee6587127020d360f5298f9e7e +Subproject commit f8cc6ac9acc4e663ecd96f9bcf1ff4542636d1b9 From f6c34ae83c372fee21cdab8b223a592c7ac96504 Mon Sep 17 00:00:00 2001 From: bdbai Date: Fri, 3 Jan 2025 11:14:03 +0800 Subject: [PATCH 246/481] Fix UWP build --- std/src/sys/pal/windows/os.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/src/sys/pal/windows/os.rs b/std/src/sys/pal/windows/os.rs index 5231a34469abf..044dc2e8cd8fa 100644 --- a/std/src/sys/pal/windows/os.rs +++ b/std/src/sys/pal/windows/os.rs @@ -5,8 +5,9 @@ #[cfg(test)] mod tests; -use super::api::{self, WinError}; -use super::to_u16s; +#[cfg(not(target_vendor = "uwp"))] +use super::api::WinError; +use super::{api, to_u16s}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::os::windows::ffi::EncodeWide; From f982362de9b829ea79ba75073ce72992a36a9895 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 4 Jan 2025 19:26:58 +0100 Subject: [PATCH 247/481] do not in-place-iterate over flatmap/flatten The implementation is unsound when a partially consumed iterator has some elements buffered in the front/back parts and cloning the Iterator removes the capacity from the backing vec::IntoIter. --- alloc/tests/vec.rs | 25 ++++++----------------- core/src/iter/adapters/flatten.rs | 34 ++----------------------------- 2 files changed, 8 insertions(+), 51 deletions(-) diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index 84679827ba1c0..474ea7fe56b8c 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1204,22 +1204,16 @@ fn test_from_iter_specialization_with_iterator_adapters() { #[test] fn test_in_place_specialization_step_up_down() { fn assert_in_place_trait(_: &T) {} - let src = vec![[0u8; 4]; 256]; + + let src = vec![0u8; 1024]; let srcptr = src.as_ptr(); - let src_cap = src.capacity(); - let iter = src.into_iter().flatten(); + let src_bytes = src.capacity(); + let iter = src.into_iter().array_chunks::<4>(); assert_in_place_trait(&iter); let sink = iter.collect::>(); let sinkptr = sink.as_ptr(); - assert_eq!(srcptr as *const u8, sinkptr); - assert_eq!(src_cap * 4, sink.capacity()); - - let iter = sink.into_iter().array_chunks::<4>(); - assert_in_place_trait(&iter); - let sink = iter.collect::>(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr); - assert_eq!(src_cap, sink.capacity()); + assert_eq!(srcptr.addr(), sinkptr.addr()); + assert_eq!(src_bytes, sink.capacity() * 4); let mut src: Vec = Vec::with_capacity(17); let src_bytes = src.capacity(); @@ -1236,13 +1230,6 @@ fn test_in_place_specialization_step_up_down() { let sink: Vec<[u8; 2]> = iter.collect(); assert_eq!(sink.len(), 8); assert!(sink.capacity() <= 25); - - let src = vec![[0u8; 4]; 256]; - let srcptr = src.as_ptr(); - let iter = src.into_iter().flat_map(|a| a.into_iter().map(|b| b.wrapping_add(1))); - assert_in_place_trait(&iter); - let sink = iter.collect::>(); - assert_eq!(srcptr as *const u8, sink.as_ptr()); } #[test] diff --git a/core/src/iter/adapters/flatten.rs b/core/src/iter/adapters/flatten.rs index 0023b46031f12..9b9353b800a98 100644 --- a/core/src/iter/adapters/flatten.rs +++ b/core/src/iter/adapters/flatten.rs @@ -1,7 +1,7 @@ use crate::iter::adapters::SourceIter; use crate::iter::{ - Cloned, Copied, Empty, Filter, FilterMap, Fuse, FusedIterator, InPlaceIterable, Map, Once, - OnceWith, TrustedFused, TrustedLen, + Cloned, Copied, Empty, Filter, FilterMap, Fuse, FusedIterator, Map, Once, OnceWith, + TrustedFused, TrustedLen, }; use crate::num::NonZero; use crate::ops::{ControlFlow, Try}; @@ -157,21 +157,6 @@ where { } -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for FlatMap -where - I: InPlaceIterable, - U: BoundedSize + IntoIterator, -{ - const EXPAND_BY: Option> = const { - match (I::EXPAND_BY, U::UPPER_BOUND) { - (Some(m), Some(n)) => m.checked_mul(n), - _ => None, - } - }; - const MERGE_BY: Option> = I::MERGE_BY; -} - #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl SourceIter for FlatMap where @@ -386,21 +371,6 @@ where { } -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Flatten -where - I: InPlaceIterable + Iterator, - ::Item: IntoIterator + BoundedSize, -{ - const EXPAND_BY: Option> = const { - match (I::EXPAND_BY, I::Item::UPPER_BOUND) { - (Some(m), Some(n)) => m.checked_mul(n), - _ => None, - } - }; - const MERGE_BY: Option> = I::MERGE_BY; -} - #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl SourceIter for Flatten where From 6a1200d1e5beab358f7ca566c2b020ecfda74ff9 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 4 Jan 2025 19:44:49 +0100 Subject: [PATCH 248/481] add regression test for unsound Flatten/FlatMap specialization --- alloc/tests/vec.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index 474ea7fe56b8c..2e654d3d1ff1e 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1337,6 +1337,20 @@ fn test_collect_after_iterator_clone() { assert_eq!(v, [1, 1, 1, 1, 1]); assert!(v.len() <= v.capacity()); } + +// regression test for #135103, similar to the one above Flatten/FlatMap had an unsound InPlaceIterable +// implementation. +#[test] +fn test_flatten_clone() { + const S: String = String::new(); + + let v = vec![[S, "Hello World!".into()], [S, S]]; + let mut i = v.into_iter().flatten(); + let _ = i.next(); + let result: Vec = i.clone().collect(); + assert_eq!(result, ["Hello World!", "", ""]); +} + #[test] fn test_cow_from() { let borrowed: &[_] = &["borrowed", "(slice)"]; From 54905e2b33cee519762c88df31256776d258451d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 5 Jan 2025 01:40:09 +0100 Subject: [PATCH 249/481] library: fix adler{-> 2}.debug Fixes ``` Checking stage0 library artifacts {alloc, core, panic_abort, panic_unwind, proc_macro, std, sysroot, test, unwind} (x86_64-unknown-linux-gnu) warning: profile package spec `adler` in profile `release` did not match any packages Did you mean `adler2`? ``` --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e744cfe5e0f57..e59aa518804f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ codegen-units = 10000 [profile.release.package] addr2line.debug = 0 addr2line.opt-level = "s" -adler.debug = 0 +adler2.debug = 0 gimli.debug = 0 gimli.opt-level = "s" miniz_oxide.debug = 0 From 56e77ee324841d3a9ec79896f569847dcb652c76 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sun, 5 Jan 2025 17:30:32 +0900 Subject: [PATCH 250/481] Clarified the documentation on core::iter::from_fn and core::iter::successors --- core/src/iter/sources/from_fn.rs | 2 ++ core/src/iter/sources/successors.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/core/src/iter/sources/from_fn.rs b/core/src/iter/sources/from_fn.rs index 3cd3830471cfe..5f3d404d7dca2 100644 --- a/core/src/iter/sources/from_fn.rs +++ b/core/src/iter/sources/from_fn.rs @@ -3,6 +3,8 @@ use crate::fmt; /// Creates a new iterator where each iteration calls the provided closure /// `F: FnMut() -> Option`. /// +/// The iterator will yield the `T`s returned from the closure. +/// /// This allows creating a custom iterator with any behavior /// without using the more verbose syntax of creating a dedicated type /// and implementing the [`Iterator`] trait for it. diff --git a/core/src/iter/sources/successors.rs b/core/src/iter/sources/successors.rs index 36bc4035039e6..e14c9235e5562 100644 --- a/core/src/iter/sources/successors.rs +++ b/core/src/iter/sources/successors.rs @@ -5,6 +5,7 @@ use crate::iter::FusedIterator; /// /// The iterator starts with the given first item (if any) /// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. +/// The iterator will yield the `T`s returned from the closure. /// /// ``` /// use std::iter::successors; From 557bccdb13470b59650f135f4b4799bb15c816b4 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Sat, 4 Jan 2025 06:47:31 -0500 Subject: [PATCH 251/481] Mark `slice::reverse` unstably const --- core/src/slice/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 073cca7daef07..f800e0d391c9f 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -987,8 +987,9 @@ impl [T] { /// assert!(v == [3, 2, 1]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_reverse", issue = "135120")] #[inline] - pub fn reverse(&mut self) { + pub const fn reverse(&mut self) { let half_len = self.len() / 2; let Range { start, end } = self.as_mut_ptr_range(); @@ -1011,7 +1012,7 @@ impl [T] { revswap(front_half, back_half, half_len); #[inline] - fn revswap(a: &mut [T], b: &mut [T], n: usize) { + const fn revswap(a: &mut [T], b: &mut [T], n: usize) { debug_assert!(a.len() == n); debug_assert!(b.len() == n); @@ -1019,7 +1020,8 @@ impl [T] { // this check tells LLVM that the indexing below is // in-bounds. Then after inlining -- once the actual // lengths of the slices are known -- it's removed. - let (a, b) = (&mut a[..n], &mut b[..n]); + let (a, _) = a.split_at_mut(n); + let (b, _) = b.split_at_mut(n); let mut i = 0; while i < n { From 4fc4af6a6c1f6485f159afe727a2ffc41d0d165d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 01:03:32 +0000 Subject: [PATCH 252/481] Add doc aliases for `libm` and IEEE names Searching "fma" in the Rust documentation returns results for `intrinsics::fma*`, but does not point to the user-facing `mul_add`. Add aliases for `fma*` and the IEEE operation name `fusedMultiplyAdd`. Add the IEEE name to `sqrt` as well, `squareRoot`. --- std/src/f128.rs | 2 ++ std/src/f16.rs | 2 ++ std/src/f32.rs | 2 ++ std/src/f64.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/std/src/f128.rs b/std/src/f128.rs index e93e915159e40..4f37e18a8cd76 100644 --- a/std/src/f128.rs +++ b/std/src/f128.rs @@ -227,6 +227,7 @@ impl f128 { /// ``` #[inline] #[rustc_allow_incoherent_impl] + #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn mul_add(self, a: f128, b: f128) -> f128 { @@ -384,6 +385,7 @@ impl f128 { /// # } /// ``` #[inline] + #[doc(alias = "squareRoot")] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/std/src/f16.rs b/std/src/f16.rs index 5b7fcaa28e064..42cd6e3fe2a5f 100644 --- a/std/src/f16.rs +++ b/std/src/f16.rs @@ -228,6 +228,7 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn mul_add(self, a: f16, b: f16) -> f16 { unsafe { intrinsics::fmaf16(self, a, b) } @@ -384,6 +385,7 @@ impl f16 { /// # } /// ``` #[inline] + #[doc(alias = "squareRoot")] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/std/src/f32.rs b/std/src/f32.rs index 7cb285bbff5f7..438d77b1626be 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -210,6 +210,7 @@ impl f32 { /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); /// ``` #[rustc_allow_incoherent_impl] + #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -360,6 +361,7 @@ impl f32 { /// assert!(negative.sqrt().is_nan()); /// assert!(negative_zero.sqrt() == negative_zero); /// ``` + #[doc(alias = "squareRoot")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/std/src/f64.rs b/std/src/f64.rs index 47163c272de32..9bb4bfbab2a0f 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -210,6 +210,7 @@ impl f64 { /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); /// ``` #[rustc_allow_incoherent_impl] + #[doc(alias = "fma", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -360,6 +361,7 @@ impl f64 { /// assert!(negative.sqrt().is_nan()); /// assert!(negative_zero.sqrt() == negative_zero); /// ``` + #[doc(alias = "squareRoot")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] From c90277db8a8ec8c17c5b00d68257b0617760b4f6 Mon Sep 17 00:00:00 2001 From: crystalstall Date: Mon, 6 Jan 2025 15:47:49 +0800 Subject: [PATCH 253/481] chore: remove redundant words in comment Signed-off-by: crystalstall --- std/src/ffi/os_str.rs | 2 +- std/src/pipe.rs | 2 +- std/src/sync/poison/mutex.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index fff140f1564fa..7fb57d410431e 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -550,7 +550,7 @@ impl OsString { OsStr::from_inner_mut(self.inner.leak()) } - /// Truncate the the `OsString` to the specified length. + /// Truncate the `OsString` to the specified length. /// /// # Panics /// Panics if `len` does not lie on a valid `OsStr` boundary diff --git a/std/src/pipe.rs b/std/src/pipe.rs index 06f3fd9fdffe8..913c22588a76c 100644 --- a/std/src/pipe.rs +++ b/std/src/pipe.rs @@ -97,7 +97,7 @@ impl PipeReader { /// let mut jobs = vec![]; /// let (reader, mut writer) = std::pipe::pipe()?; /// - /// // Write NUM_SLOT characters the the pipe. + /// // Write NUM_SLOT characters the pipe. /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; /// /// // Spawn several processes that read a character from the pipe, do some work, then diff --git a/std/src/sync/poison/mutex.rs b/std/src/sync/poison/mutex.rs index e28c2090afed7..01ef71a187fec 100644 --- a/std/src/sync/poison/mutex.rs +++ b/std/src/sync/poison/mutex.rs @@ -534,7 +534,7 @@ impl Mutex { /// # Errors /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error containing the the underlying data + /// this call will return an error containing the underlying data /// instead. /// /// # Examples From 54bfcec020d0c17e1e29f9b9a343456514e1da98 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Thu, 17 Oct 2024 13:00:35 +0200 Subject: [PATCH 254/481] Add support for wasm exception handling to Emscripten target Gated behind an unstable `-Z emscripten-wasm-eh` flag --- panic_unwind/Cargo.toml | 2 +- panic_unwind/src/lib.rs | 3 ++- unwind/Cargo.toml | 2 +- unwind/src/lib.rs | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/panic_unwind/Cargo.toml b/panic_unwind/Cargo.toml index 252f118fecfbb..c2abb79192e9f 100644 --- a/panic_unwind/Cargo.toml +++ b/panic_unwind/Cargo.toml @@ -23,4 +23,4 @@ libc = { version = "0.2", default-features = false } [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [] +check-cfg = ['cfg(emscripten_wasm_eh)'] diff --git a/panic_unwind/src/lib.rs b/panic_unwind/src/lib.rs index 8c28bb5c5b033..dc78be76cb4d5 100644 --- a/panic_unwind/src/lib.rs +++ b/panic_unwind/src/lib.rs @@ -25,13 +25,14 @@ // `real_imp` is unused with Miri, so silence warnings. #![cfg_attr(miri, allow(dead_code))] #![allow(internal_features)] +#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] use alloc::boxed::Box; use core::any::Any; use core::panic::PanicPayload; cfg_if::cfg_if! { - if #[cfg(target_os = "emscripten")] { + if #[cfg(all(target_os = "emscripten", not(emscripten_wasm_eh)))] { #[path = "emcc.rs"] mod imp; } else if #[cfg(target_os = "hermit")] { diff --git a/unwind/Cargo.toml b/unwind/Cargo.toml index e13c9a06c05d1..66e8d1a3ffe5f 100644 --- a/unwind/Cargo.toml +++ b/unwind/Cargo.toml @@ -37,4 +37,4 @@ system-llvm-libunwind = [] [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [] +check-cfg = ['cfg(emscripten_wasm_eh)'] diff --git a/unwind/src/lib.rs b/unwind/src/lib.rs index 7af1882ab73a9..e4ba2bc1ed874 100644 --- a/unwind/src/lib.rs +++ b/unwind/src/lib.rs @@ -4,10 +4,11 @@ #![feature(staged_api)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] #![cfg_attr( - all(target_family = "wasm", not(target_os = "emscripten")), + all(target_family = "wasm", any(not(target_os = "emscripten"), emscripten_wasm_eh)), feature(simd_wasm64, wasm_exception_handling_intrinsics) )] #![allow(internal_features)] +#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] // Force libc to be included even if unused. This is required by many platforms. #[cfg(not(all(windows, target_env = "msvc")))] From 249da440e771b7445789178d175ae52179354639 Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 5 Jan 2025 20:49:04 -0300 Subject: [PATCH 255/481] [generic_assert] Constify methods used by the formatting system --- core/src/fmt/mod.rs | 4 ++-- core/src/fmt/rt.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index c2c78dd9c67eb..a033b8bd30514 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -596,7 +596,7 @@ impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. #[inline] - pub fn new_v1( + pub const fn new_v1( pieces: &'a [&'static str; P], args: &'a [rt::Argument<'a>; A], ) -> Arguments<'a> { @@ -612,7 +612,7 @@ impl<'a> Arguments<'a> { /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. #[inline] - pub fn new_v1_formatted( + pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], fmt: &'a [rt::Placeholder], diff --git a/core/src/fmt/rt.rs b/core/src/fmt/rt.rs index 94341a4da66cd..85d089a079082 100644 --- a/core/src/fmt/rt.rs +++ b/core/src/fmt/rt.rs @@ -96,12 +96,12 @@ pub struct Argument<'a> { #[rustc_diagnostic_item = "ArgumentMethods"] impl Argument<'_> { #[inline] - fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { + const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { Argument { // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { - value: NonNull::from(x).cast(), + value: NonNull::from_ref(x).cast(), // SAFETY: function pointers always have the same layout. formatter: unsafe { mem::transmute(f) }, _lifetime: PhantomData, @@ -150,7 +150,7 @@ impl Argument<'_> { Self::new(x, UpperExp::fmt) } #[inline] - pub fn from_usize(x: &usize) -> Argument<'_> { + pub const fn from_usize(x: &usize) -> Argument<'_> { Argument { ty: ArgumentType::Count(*x) } } @@ -181,7 +181,7 @@ impl Argument<'_> { } #[inline] - pub(super) fn as_usize(&self) -> Option { + pub(super) const fn as_usize(&self) -> Option { match self.ty { ArgumentType::Count(count) => Some(count), ArgumentType::Placeholder { .. } => None, @@ -199,7 +199,7 @@ impl Argument<'_> { /// println!("{f}"); /// ``` #[inline] - pub fn none() -> [Self; 0] { + pub const fn none() -> [Self; 0] { [] } } @@ -216,7 +216,7 @@ impl UnsafeArg { /// See documentation where `UnsafeArg` is required to know when it is safe to /// create and use `UnsafeArg`. #[inline] - pub unsafe fn new() -> Self { + pub const unsafe fn new() -> Self { Self { _private: () } } } From b9e9246c12d7931401088bab7cf33232c639fa01 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 7 Jan 2025 14:12:07 +0200 Subject: [PATCH 256/481] Avoid naming variables `str` This renames variables named `str` to other names, to make sure `str` always refers to a type. It's confusing to read code where `str` (or another standard type name) is used as an identifier. It also produces misleading syntax highlighting. --- std/src/process.rs | 4 ++-- std/src/sys/pal/windows/process.rs | 6 +++--- std/src/sys_common/wtf8.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/std/src/process.rs b/std/src/process.rs index 929d2b57afe5c..4ad31dfd9357d 100644 --- a/std/src/process.rs +++ b/std/src/process.rs @@ -1283,13 +1283,13 @@ impl fmt::Debug for Output { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let stdout_utf8 = str::from_utf8(&self.stdout); let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { - Ok(ref str) => str, + Ok(ref s) => s, Err(_) => &self.stdout, }; let stderr_utf8 = str::from_utf8(&self.stderr); let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { - Ok(ref str) => str, + Ok(ref s) => s, Err(_) => &self.stderr, }; diff --git a/std/src/sys/pal/windows/process.rs b/std/src/sys/pal/windows/process.rs index 2ca20a21dfe51..9332c9b49ffb9 100644 --- a/std/src/sys/pal/windows/process.rs +++ b/std/src/sys/pal/windows/process.rs @@ -142,11 +142,11 @@ impl AsRef for EnvKey { } } -pub(crate) fn ensure_no_nuls>(str: T) -> io::Result { - if str.as_ref().encode_wide().any(|b| b == 0) { +pub(crate) fn ensure_no_nuls>(s: T) -> io::Result { + if s.as_ref().encode_wide().any(|b| b == 0) { Err(io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) } else { - Ok(str) + Ok(s) } } diff --git a/std/src/sys_common/wtf8.rs b/std/src/sys_common/wtf8.rs index 666942bb8a10f..6c60d901ee904 100644 --- a/std/src/sys_common/wtf8.rs +++ b/std/src/sys_common/wtf8.rs @@ -204,8 +204,8 @@ impl Wtf8Buf { /// /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] - pub fn from_str(str: &str) -> Wtf8Buf { - Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()), is_known_utf8: true } + pub fn from_str(s: &str) -> Wtf8Buf { + Wtf8Buf { bytes: <[_]>::to_vec(s.as_bytes()), is_known_utf8: true } } pub fn clear(&mut self) { From f613804c38662e7f1047a8fb774db2c81cdc7442 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 22 Dec 2024 19:48:33 +0800 Subject: [PATCH 257/481] Impl String::into_chars Signed-off-by: tison --- alloc/src/string.rs | 187 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 2 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index 23d060d2158cd..0c9535dfaa628 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -62,10 +62,10 @@ use crate::alloc::Allocator; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, Chars, Utf8Error, from_utf8_unchecked_mut}; +use crate::str::{self, CharIndices, Chars, Utf8Error, from_utf8_unchecked_mut}; #[cfg(not(no_global_oom_handling))] use crate::str::{FromStr, from_boxed_utf8_unchecked}; -use crate::vec::Vec; +use crate::vec::{self, Vec}; /// A UTF-8–encoded, growable string. /// @@ -1952,6 +1952,61 @@ impl String { Drain { start, end, iter: chars_iter, string: self_ptr } } + /// Converts a `String` into an iterator over the [`char`]s of the string. + /// + /// As a string consists of valid UTF-8, we can iterate through a string + /// by [`char`]. This method returns such an iterator. + /// + /// It's important to remember that [`char`] represents a Unicode Scalar + /// Value, and might not match your idea of what a 'character' is. Iteration + /// over grapheme clusters may be what you actually want. That functionality + /// is not provided by Rust's standard library, check crates.io instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let word = String::from("goodbye"); + /// + /// let mut chars = word.into_chars(); + /// + /// assert_eq!(Some('g'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('d'), chars.next()); + /// assert_eq!(Some('b'), chars.next()); + /// assert_eq!(Some('y'), chars.next()); + /// assert_eq!(Some('e'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// Remember, [`char`]s might not match your intuition about characters: + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let y = String::from("y̆"); + /// + /// let mut chars = y.into_chars(); + /// + /// assert_eq!(Some('y'), chars.next()); // not 'y̆' + /// assert_eq!(Some('\u{0306}'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// [`char`]: prim@char + #[inline] + #[must_use = "`self` will be dropped if the result is not used"] + #[unstable(feature = "string_into_chars", issue = "133125")] + pub fn into_chars(self) -> IntoChars { + IntoChars { bytes: self.into_bytes().into_iter() } + } + /// Removes the specified range in the string, /// and replaces it with the given string. /// The given string doesn't need to be the same length as the range. @@ -3090,6 +3145,134 @@ impl fmt::Write for String { } } +/// An iterator over the [`char`]s of a string. +/// +/// This struct is created by the [`into_chars`] method on [`String`]. +/// See its documentation for more. +/// +/// [`char`]: prim@char +/// [`into_chars`]: String::into_chars +#[cfg_attr(not(no_global_oom_handling), derive(Clone))] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "string_into_chars", issue = "133125")] +pub struct IntoChars { + bytes: vec::IntoIter, +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl fmt::Debug for IntoChars { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IntoChars").field(&self.as_str()).finish() + } +} + +impl IntoChars { + /// Views the underlying data as a subslice of the original data. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let mut chars = String::from("abc").into_chars(); + /// + /// assert_eq!(chars.as_str(), "abc"); + /// chars.next(); + /// assert_eq!(chars.as_str(), "bc"); + /// chars.next(); + /// chars.next(); + /// assert_eq!(chars.as_str(), ""); + /// ``` + #[unstable(feature = "string_into_chars", issue = "133125")] + #[must_use] + #[inline] + pub fn as_str(&self) -> &str { + // SAFETY: `bytes` is a valid UTF-8 string. + unsafe { str::from_utf8_unchecked(self.bytes.as_slice()) } + } + + /// Consumes the `IntoChars`, returning the remaining string. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let chars = String::from("abc").into_chars(); + /// assert_eq!(chars.into_string(), "abc"); + /// + /// let mut chars = String::from("def").into_chars(); + /// chars.next(); + /// assert_eq!(chars.into_string(), "ef"); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_into_chars", issue = "133125")] + #[inline] + pub fn into_string(self) -> String { + // Safety: `bytes` are kept in UTF-8 form, only removing whole `char`s at a time. + unsafe { String::from_utf8_unchecked(self.bytes.collect()) } + } + + #[inline] + fn iter(&self) -> CharIndices<'_> { + self.as_str().char_indices() + } +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl Iterator for IntoChars { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + let mut iter = self.iter(); + match iter.next() { + None => None, + Some((_, ch)) => { + let offset = iter.offset(); + // `offset` is a valid index. + let _ = self.bytes.advance_by(offset); + Some(ch) + } + } + } + + #[inline] + fn count(self) -> usize { + self.iter().count() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter().size_hint() + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl DoubleEndedIterator for IntoChars { + #[inline] + fn next_back(&mut self) -> Option { + let len = self.as_str().len(); + let mut iter = self.iter(); + match iter.next_back() { + None => None, + Some((idx, ch)) => { + // `idx` is a valid index. + let _ = self.bytes.advance_back_by(len - idx); + Some(ch) + } + } + } +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl FusedIterator for IntoChars {} + /// A draining iterator for `String`. /// /// This struct is created by the [`drain`] method on [`String`]. See its From c4684f31381ca06133c7f1c57b67c2d7d072f0f7 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Wed, 18 Dec 2024 11:33:15 +0100 Subject: [PATCH 258/481] Implement Condvar::wait_timeout for targets without threads This always falls back to sleeping since there is no way to notify a condvar on a target without threads. --- std/src/sys/sync/condvar/no_threads.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/std/src/sys/sync/condvar/no_threads.rs b/std/src/sys/sync/condvar/no_threads.rs index 88ce39305e1ae..18d97d4b17ab0 100644 --- a/std/src/sys/sync/condvar/no_threads.rs +++ b/std/src/sys/sync/condvar/no_threads.rs @@ -1,4 +1,5 @@ use crate::sys::sync::Mutex; +use crate::thread::sleep; use crate::time::Duration; pub struct Condvar {} @@ -19,7 +20,8 @@ impl Condvar { panic!("condvar wait not supported") } - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - panic!("condvar wait not supported"); + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, dur: Duration) -> bool { + sleep(dur); + false } } From 510eb6d46dae4f6540aed2dedeb607afc5746b0a Mon Sep 17 00:00:00 2001 From: Kornel Date: Mon, 6 Jan 2025 23:39:53 +0000 Subject: [PATCH 259/481] More compelling env_clear() examples --- std/src/process.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/std/src/process.rs b/std/src/process.rs index 4ad31dfd9357d..e0dd2e14817a8 100644 --- a/std/src/process.rs +++ b/std/src/process.rs @@ -868,13 +868,17 @@ impl Command { /// /// # Examples /// + /// Prevent any inherited `GIT_DIR` variable from changing the target of the `git` command, + /// while allowing all other variables, like `GIT_AUTHOR_NAME`. + /// /// ```no_run /// use std::process::Command; /// - /// Command::new("ls") - /// .env_remove("PATH") - /// .spawn() - /// .expect("ls command failed to start"); + /// Command::new("git") + /// .arg("commit") + /// .env_remove("GIT_DIR") + /// .spawn()?; + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn env_remove>(&mut self, key: K) -> &mut Command { @@ -896,13 +900,17 @@ impl Command { /// /// # Examples /// + /// The behavior of `sort` is affected by `LANG` and `LC_*` environment variables. + /// Clearing the environment makes `sort`'s behavior independent of the parent processes' language. + /// /// ```no_run /// use std::process::Command; /// - /// Command::new("ls") + /// Command::new("sort") + /// .arg("file.txt") /// .env_clear() - /// .spawn() - /// .expect("ls command failed to start"); + /// .spawn()?; + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn env_clear(&mut self) -> &mut Command { From f8e4c6e8d2521e4ae54494f8bbaef05f467a7719 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jan 2025 10:40:40 +0100 Subject: [PATCH 260/481] add missing provenance APIs on NonNull --- core/src/ptr/non_null.rs | 48 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 1058fa42cc1e3..8e78a44bddce6 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -85,6 +85,20 @@ impl !Send for NonNull {} impl !Sync for NonNull {} impl NonNull { + /// Creates a pointer with the given address and no [provenance][crate::ptr#provenance]. + /// + /// 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. + #[unstable(feature = "nonnull_provenance", issue = "135243")] + pub const fn without_provenance(addr: NonZero) -> Self { + // SAFETY: we know `addr` is non-zero. + unsafe { + let ptr = crate::ptr::without_provenance_mut(addr.get()); + NonNull::new_unchecked(ptr) + } + } + /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like @@ -116,6 +130,21 @@ impl NonNull { } } + /// Converts an address back to a mutable pointer, picking up some previously 'exposed' + /// [provenance][crate::ptr#provenance]. + /// + /// 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. + #[unstable(feature = "nonnull_provenance", issue = "135243")] + pub fn with_exposed_provenance(addr: NonZero) -> Self { + // SAFETY: we know `addr` is non-zero. + unsafe { + let ptr = crate::ptr::with_exposed_provenance_mut(addr.get()); + NonNull::new_unchecked(ptr) + } + } + /// Returns a shared references to the value. In contrast to [`as_ref`], this does not require /// that the value has to be initialized. /// @@ -282,7 +311,7 @@ impl NonNull { /// Gets the "address" portion of the pointer. /// - /// For more details see the equivalent method on a raw pointer, [`pointer::addr`]. + /// For more details, see the equivalent method on a raw pointer, [`pointer::addr`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] @@ -294,10 +323,23 @@ impl NonNull { unsafe { NonZero::new_unchecked(self.as_ptr().addr()) } } + /// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in + /// [`with_exposed_provenance`][NonNull::with_exposed_provenance] and returns the "address" portion. + /// + /// For more details, see the equivalent method on a raw pointer, [`pointer::expose_provenance`]. + /// + /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. + #[unstable(feature = "nonnull_provenance", issue = "135243")] + 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. + unsafe { NonZero::new_unchecked(self.as_ptr().expose_provenance()) } + } + /// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of /// `self`. /// - /// For more details see the equivalent method on a raw pointer, [`pointer::with_addr`]. + /// For more details, see the equivalent method on a raw pointer, [`pointer::with_addr`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] @@ -311,7 +353,7 @@ impl NonNull { /// Creates a new pointer by mapping `self`'s address to a new one, preserving the /// [provenance][crate::ptr#provenance] of `self`. /// - /// For more details see the equivalent method on a raw pointer, [`pointer::map_addr`]. + /// For more details, see the equivalent method on a raw pointer, [`pointer::map_addr`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] From b40099f7523cbc0950861386d85ff92539e3daf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2025 21:18:46 +0000 Subject: [PATCH 261/481] Remove some unnecessary `.into()` calls --- alloc/src/rc.rs | 2 +- alloc/src/sync.rs | 2 +- std/src/thread/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index e014404eff35b..08a7b32579868 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -1789,7 +1789,7 @@ impl Rc { /// let x: Rc<&str> = Rc::new("Hello, world!"); /// { /// let s = String::from("Oh, no!"); - /// let mut y: Rc<&str> = x.clone().into(); + /// let mut y: Rc<&str> = x.clone(); /// unsafe { /// // this is Undefined Behavior, because x's inner type /// // is &'long str, not &'short str diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index b34a6d3f660c8..30761739dbff2 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -2468,7 +2468,7 @@ impl Arc { /// let x: Arc<&str> = Arc::new("Hello, world!"); /// { /// let s = String::from("Oh, no!"); - /// let mut y: Arc<&str> = x.clone().into(); + /// let mut y: Arc<&str> = x.clone(); /// unsafe { /// // this is Undefined Behavior, because x's inner type /// // is &'long str, not &'short str diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 85ee369ca2b66..b6ee00a253a95 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -502,7 +502,7 @@ impl Builder { let id = ThreadId::new(); let my_thread = match name { - Some(name) => Thread::new(id, name.into()), + Some(name) => Thread::new(id, name), None => Thread::new_unnamed(id), }; From ede045052de149437bac5c4f7d682f94162ff72a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 6 Jan 2025 20:28:08 +0100 Subject: [PATCH 262/481] update version placeholders --- alloc/src/boxed.rs | 6 +++--- core/src/alloc/layout.rs | 10 +++++----- core/src/hash/mod.rs | 4 ++-- core/src/iter/traits/collect.rs | 2 +- core/src/mem/maybe_uninit.rs | 2 +- core/src/mem/mod.rs | 6 +++--- core/src/num/f32.rs | 22 +++++++++++----------- core/src/num/f64.rs | 22 +++++++++++----------- core/src/num/mod.rs | 8 ++++---- core/src/num/nonzero.rs | 4 ++-- core/src/ops/async_function.rs | 16 ++++++++-------- core/src/prelude/mod.rs | 4 ++-- core/src/ptr/mod.rs | 4 ++-- core/src/ptr/mut_ptr.rs | 2 +- core/src/ptr/non_null.rs | 4 ++-- core/src/slice/mod.rs | 2 +- core/src/task/wake.rs | 6 +++--- std/src/collections/hash/map.rs | 2 +- std/src/collections/hash/set.rs | 2 +- std/src/env.rs | 2 +- std/src/io/error.rs | 4 ++-- std/src/prelude/common.rs | 2 +- std/src/prelude/mod.rs | 4 ++-- 23 files changed, 70 insertions(+), 70 deletions(-) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 0f66217b5cb33..dcc1d0234d365 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -2029,7 +2029,7 @@ impl + ?Sized, A: Allocator> Fn for Box { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl + ?Sized, A: Allocator> AsyncFnOnce for Box { type Output = F::Output; type CallOnceFuture = F::CallOnceFuture; @@ -2040,7 +2040,7 @@ impl + ?Sized, A: Allocator> AsyncFnOnce } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl + ?Sized, A: Allocator> AsyncFnMut for Box { type CallRefFuture<'a> = F::CallRefFuture<'a> @@ -2053,7 +2053,7 @@ impl + ?Sized, A: Allocator> AsyncFnMut f } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl + ?Sized, A: Allocator> AsyncFn for Box { extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index e6f39db9dced3..21dfdd926e0af 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -178,7 +178,7 @@ impl Layout { /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { @@ -252,7 +252,7 @@ impl Layout { /// Returns an error if the combination of `self.size()` and the given /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn align_to(&self, align: usize) -> Result { if let Some(align) = Alignment::new(align) { @@ -327,7 +327,7 @@ impl Layout { /// This is equivalent to adding the result of `padding_needed_for` /// to the layout's current size. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[must_use = "this returns a new `Layout`, \ without modifying the original"] #[inline] @@ -426,7 +426,7 @@ impl Layout { /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16]))); /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = Alignment::max(self.align, next.align); @@ -489,7 +489,7 @@ impl Layout { /// On arithmetic overflow or when the total size would exceed /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn array(n: usize) -> Result { // Reduce the amount of code we need to monomorphize per `T`. diff --git a/core/src/hash/mod.rs b/core/src/hash/mod.rs index 84bbf985e8be4..b43cf68421594 100644 --- a/core/src/hash/mod.rs +++ b/core/src/hash/mod.rs @@ -752,10 +752,10 @@ pub struct BuildHasherDefault(marker::PhantomData H>); impl BuildHasherDefault { /// Creates a new BuildHasherDefault for Hasher `H`. - #[stable(feature = "build_hasher_default_const_new", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "build_hasher_default_const_new", since = "1.85.0")] #[rustc_const_stable( feature = "build_hasher_default_const_new", - since = "CURRENT_RUSTC_VERSION" + since = "1.85.0" )] pub const fn new() -> Self { BuildHasherDefault(marker::PhantomData) diff --git a/core/src/iter/traits/collect.rs b/core/src/iter/traits/collect.rs index 73e6d93106096..97bb21c8a36e8 100644 --- a/core/src/iter/traits/collect.rs +++ b/core/src/iter/traits/collect.rs @@ -472,7 +472,7 @@ macro_rules! spec_tuple_impl { #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for \ 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in \ - CURRENT_RUSTC_VERSION."] + 1.85.0."] => ($ty_name, $var_name, $extend_ty_name, $cnt), ); }; diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 58fb5be5812c8..284a58c7278fd 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -507,7 +507,7 @@ impl MaybeUninit { /// ``` #[inline(always)] #[stable(feature = "maybe_uninit_write", since = "1.55.0")] - #[rustc_const_stable(feature = "const_maybe_uninit_write", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_maybe_uninit_write", since = "1.85.0")] pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 2d66e5c2f2a7a..b9bb6d6a13f7f 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -333,7 +333,7 @@ pub const fn size_of() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_size_of_val", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_size_of_val", since = "1.85.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] pub const fn size_of_val(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer @@ -484,7 +484,7 @@ pub const fn align_of() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_align_of_val", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")] #[allow(deprecated)] pub const fn align_of_val(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer @@ -725,7 +725,7 @@ pub unsafe fn uninitialized() -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[rustc_diagnostic_item = "mem_swap"] pub const fn swap(x: &mut T, y: &mut T) { // SAFETY: `&mut` guarantees these are typed readable and writable diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index 4c0d95f95e562..2b6adef65e94a 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -818,7 +818,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn recip(self) -> f32 { 1.0 / self @@ -836,7 +836,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_degrees(self) -> f32 { // Use a constant for better precision. @@ -856,7 +856,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_radians(self) -> f32 { const RADS_PER_DEG: f32 = consts::PI / 180.0; @@ -878,7 +878,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f32) -> f32 { intrinsics::maxnumf32(self, other) @@ -899,7 +899,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f32) -> f32 { intrinsics::minnumf32(self, other) @@ -988,8 +988,8 @@ impl f32 { /// assert_eq!((-5.5f32).midpoint(8.0), 1.25); /// ``` #[inline] - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f32) -> f32 { cfg_if! { // Allow faster implementation that have known good 64-bit float @@ -1396,7 +1396,7 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn clamp(mut self, min: f32, max: f32) -> f32 { const_assert!( @@ -1433,7 +1433,7 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f32 { // SAFETY: this is actually a safe intrinsic @@ -1458,7 +1458,7 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn signum(self) -> f32 { if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) } @@ -1493,7 +1493,7 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[inline] #[stable(feature = "copysign", since = "1.35.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] pub const fn copysign(self, sign: f32) -> f32 { // SAFETY: this is actually a safe intrinsic unsafe { intrinsics::copysignf32(self, sign) } diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 77ca56df06705..037b3afa6c46c 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -835,7 +835,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn recip(self) -> f64 { 1.0 / self @@ -853,7 +853,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_degrees(self) -> f64 { // The division here is correctly rounded with respect to the true @@ -874,7 +874,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_radians(self) -> f64 { const RADS_PER_DEG: f64 = consts::PI / 180.0; @@ -896,7 +896,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f64) -> f64 { intrinsics::maxnumf64(self, other) @@ -917,7 +917,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f64) -> f64 { intrinsics::minnumf64(self, other) @@ -1006,8 +1006,8 @@ impl f64 { /// assert_eq!((-5.5f64).midpoint(8.0), 1.25); /// ``` #[inline] - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f64) -> f64 { const LO: f64 = f64::MIN_POSITIVE * 2.; const HI: f64 = f64::MAX / 2.; @@ -1396,7 +1396,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn clamp(mut self, min: f64, max: f64) -> f64 { const_assert!( @@ -1433,7 +1433,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f64 { // SAFETY: this is actually a safe intrinsic @@ -1458,7 +1458,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn signum(self) -> f64 { if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) } @@ -1492,7 +1492,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "copysign", since = "1.35.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn copysign(self, sign: f64) -> f64 { // SAFETY: this is actually a safe intrinsic diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 1f5b8ce6c6e22..67d219654b969 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -138,8 +138,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -192,8 +192,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index a9294306b1b61..926723b3dbab7 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -1543,8 +1543,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/ops/async_function.rs b/core/src/ops/async_function.rs index 0073afd496070..2ee243ea85eb4 100644 --- a/core/src/ops/async_function.rs +++ b/core/src/ops/async_function.rs @@ -5,7 +5,7 @@ use crate::marker::Tuple; /// /// All `async fn` and functions returning futures implement this trait. #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -20,7 +20,7 @@ pub trait AsyncFn: AsyncFnMut { /// /// All `async fn` and functions returning futures implement this trait. #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -42,7 +42,7 @@ pub trait AsyncFnMut: AsyncFnOnce { /// /// All `async fn` and functions returning futures implement this trait. #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -68,7 +68,7 @@ mod impls { use crate::marker::Tuple; #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl AsyncFn for &F where F: AsyncFn, @@ -79,7 +79,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl AsyncFnMut for &F where F: AsyncFn, @@ -95,7 +95,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F where F: AsyncFn, @@ -109,7 +109,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl AsyncFnMut for &mut F where F: AsyncFnMut, @@ -125,7 +125,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F where F: AsyncFnMut, diff --git a/core/src/prelude/mod.rs b/core/src/prelude/mod.rs index 9b23874bcf7ba..d3fda1cd273f9 100644 --- a/core/src/prelude/mod.rs +++ b/core/src/prelude/mod.rs @@ -71,7 +71,7 @@ pub mod rust_2021 { /// The 2024 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "prelude_2024", since = "1.85.0")] pub mod rust_2024 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; @@ -84,7 +84,7 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::convert::{TryFrom, TryInto}; - #[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "prelude_2024", since = "1.85.0")] #[doc(no_inline)] pub use crate::future::{Future, IntoFuture}; } diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index a70af793004b2..3d9ad0706eb0b 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1009,7 +1009,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[rustc_diagnostic_item = "ptr_swap"] pub const unsafe fn swap(x: *mut T, y: *mut T) { // Give ourselves some scratch space to work with. @@ -2150,7 +2150,7 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// ``` /// /// [subtype]: https://doc.rust-lang.org/reference/subtyping.html -#[stable(feature = "ptr_fn_addr_eq", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "ptr_fn_addr_eq", since = "1.85.0")] #[inline(always)] #[must_use = "function pointer comparison produces a value"] pub fn fn_addr_eq(f: T, g: U) -> bool { diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index d75d570a969f8..5d9d337f101a5 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -1594,7 +1594,7 @@ impl *mut T { /// /// [`ptr::swap`]: crate::ptr::swap() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[inline(always)] pub const unsafe fn swap(self, with: *mut T) where diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 8e78a44bddce6..6287d8816b0fd 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -253,7 +253,7 @@ impl NonNull { /// } /// ``` #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_stable(feature = "const_nonnull_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_nonnull_new", since = "1.85.0")] #[inline] pub const fn new(ptr: *mut T) -> Option { if !ptr.is_null() { @@ -1188,7 +1188,7 @@ impl NonNull { /// [`ptr::swap`]: crate::ptr::swap() #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] pub const unsafe fn swap(self, with: NonNull) where T: Sized, diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index f800e0d391c9f..8939e5072ba32 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -913,7 +913,7 @@ impl [T] { /// assert!(v == ["a", "b", "e", "d", "c"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[inline] #[track_caller] pub const fn swap(&mut self, a: usize, b: usize) { diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index ba429005fab3d..4c51ca0a5e437 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -60,7 +60,7 @@ impl RawWaker { RawWaker { data, vtable } } - #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "noop_waker", since = "1.85.0")] const NOOP: RawWaker = { const VTABLE: RawWakerVTable = RawWakerVTable::new( // Cloning just returns a new no-op raw waker @@ -564,8 +564,8 @@ impl Waker { /// ``` #[inline] #[must_use] - #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "noop_waker", since = "1.85.0")] + #[rustc_const_stable(feature = "noop_waker", since = "1.85.0")] pub const fn noop() -> &'static Waker { const WAKER: &Waker = &Waker { waker: RawWaker::NOOP }; WAKER diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 56d734ba2fbfb..f7d2eec90743c 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -298,7 +298,7 @@ impl HashMap { #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable( feature = "const_collections_with_hasher", - since = "CURRENT_RUSTC_VERSION" + since = "1.85.0" )] pub const fn with_hasher(hash_builder: S) -> HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index bcf6d6b4ccf3a..c1b794c58f120 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -390,7 +390,7 @@ impl HashSet { #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable( feature = "const_collections_with_hasher", - since = "CURRENT_RUSTC_VERSION" + since = "1.85.0" )] pub const fn with_hasher(hasher: S) -> HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } diff --git a/std/src/env.rs b/std/src/env.rs index 535236ff89a37..11a29cdae62e2 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -622,7 +622,7 @@ impl Error for JoinPathsError { /// /// In UWP (Universal Windows Platform) targets this function is unimplemented and always returns `None`. /// -/// Before Rust CURRENT_RUSTC_VERSION, this function used to return the value of the 'HOME' environment variable +/// Before Rust 1.85.0, this function used to return the value of the 'HOME' environment variable /// on Windows, which in Cygwin or Mingw environments could return non-standard paths like `/home/you` /// instead of `C:\Users\you`. /// diff --git a/std/src/io/error.rs b/std/src/io/error.rs index 476c403c21f33..38b723366175f 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -339,7 +339,7 @@ pub enum ErrorKind { #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] NotSeekable, /// Filesystem quota or some other kind of quota was exceeded. - #[stable(feature = "io_error_quota_exceeded", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_quota_exceeded", since = "1.85.0")] QuotaExceeded, /// File larger than allowed or supported. /// @@ -364,7 +364,7 @@ pub enum ErrorKind { #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] Deadlock, /// Cross-device or cross-filesystem (hard) link or rename. - #[stable(feature = "io_error_crosses_devices", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_crosses_devices", since = "1.85.0")] CrossesDevices, /// Too many (hard) links to the same filesystem object. /// diff --git a/std/src/prelude/common.rs b/std/src/prelude/common.rs index 22a364074c52d..713e417e0440c 100644 --- a/std/src/prelude/common.rs +++ b/std/src/prelude/common.rs @@ -13,7 +13,7 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[doc(no_inline)] pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; diff --git a/std/src/prelude/mod.rs b/std/src/prelude/mod.rs index 64349987fcfb8..4ec328208f015 100644 --- a/std/src/prelude/mod.rs +++ b/std/src/prelude/mod.rs @@ -169,12 +169,12 @@ pub mod rust_2021 { /// The 2024 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "prelude_2024", since = "1.85.0")] pub mod rust_2024 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - #[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "prelude_2024", since = "1.85.0")] #[doc(no_inline)] pub use core::prelude::rust_2024::*; } From c64ee3d9ab938d35ffb2f66afa55db05903e3cb6 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 21:26:39 +0100 Subject: [PATCH 263/481] update cfg(bootstrap) --- alloc/src/boxed.rs | 9 +++---- alloc/src/lib.rs | 1 - core/src/arch.rs | 1 - core/src/future/async_drop.rs | 5 ++-- core/src/intrinsics/mod.rs | 32 ++-------------------- core/src/intrinsics/simd.rs | 1 - core/src/lib.rs | 1 - core/src/marker.rs | 36 ++++++++++--------------- core/src/mem/transmutability.rs | 5 ++-- core/src/ops/arith.rs | 14 +--------- core/src/ops/async_function.rs | 24 ++++++----------- core/src/ops/deref.rs | 47 +-------------------------------- core/src/ops/drop.rs | 2 +- core/src/ptr/metadata.rs | 5 ++-- core/src/ptr/non_null.rs | 1 - core/tests/ptr.rs | 2 +- std/src/prelude/common.rs | 3 +-- 17 files changed, 38 insertions(+), 151 deletions(-) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index dcc1d0234d365..1b5e44a913467 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -2028,8 +2028,7 @@ impl + ?Sized, A: Allocator> Fn for Box { } } -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] impl + ?Sized, A: Allocator> AsyncFnOnce for Box { type Output = F::Output; type CallOnceFuture = F::CallOnceFuture; @@ -2039,8 +2038,7 @@ impl + ?Sized, A: Allocator> AsyncFnOnce } } -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] impl + ?Sized, A: Allocator> AsyncFnMut for Box { type CallRefFuture<'a> = F::CallRefFuture<'a> @@ -2052,8 +2050,7 @@ impl + ?Sized, A: Allocator> AsyncFnMut f } } -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] impl + ?Sized, A: Allocator> AsyncFn for Box { extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index aff90f5abb3a0..784af9407692a 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -91,7 +91,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(async_closure))] #![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] diff --git a/core/src/arch.rs b/core/src/arch.rs index 95d88c7f67991..cb130f60cecf1 100644 --- a/core/src/arch.rs +++ b/core/src/arch.rs @@ -65,7 +65,6 @@ pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))? // When stabilizing this, update the comment on `core::intrinsics::breakpoint`. #[unstable(feature = "breakpoint", issue = "133724")] #[inline(always)] -#[cfg(not(bootstrap))] pub fn breakpoint() { core::intrinsics::breakpoint(); } diff --git a/core/src/future/async_drop.rs b/core/src/future/async_drop.rs index ea6d3b800e64d..f1778a4d782af 100644 --- a/core/src/future/async_drop.rs +++ b/core/src/future/async_drop.rs @@ -133,9 +133,8 @@ pub trait AsyncDrop { } #[lang = "async_destruct"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] trait AsyncDestruct { type AsyncDestructor: Future; } diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 7d44ea7a66ba5..7b31bbec7547c 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1382,22 +1382,10 @@ pub unsafe fn prefetch_write_instruction(_data: *const T, _locality: i32) { #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn breakpoint() { unreachable!() } -/// Executes a breakpoint trap, for inspection by a debugger. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -#[cfg(bootstrap)] -pub unsafe fn breakpoint() { - unreachable!() -} - /// Magic intrinsic that derives its meaning from attributes /// attached to the function. /// @@ -3323,8 +3311,8 @@ pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_const_unstable(feature = "const_carrying_mul_add", issue = "85532")] #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] -#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] pub const fn carrying_mul_add, U>( multiplier: T, multiplicand: T, @@ -3969,21 +3957,6 @@ pub const fn is_val_statically_known(_arg: T) -> bool { false } -#[rustc_nounwind] -#[inline] -#[rustc_intrinsic] -#[rustc_intrinsic_const_stable_indirect] -#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic -#[cfg(bootstrap)] -pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { - // SAFETY: The caller provided single non-overlapping items behind - // pointers, so swapping them with `count: 1` is fine. - unsafe { ptr::swap_nonoverlapping(x, y, 1) }; -} - -#[cfg(bootstrap)] -pub use typed_swap as typed_swap_nonoverlapping; - /// Non-overlapping *typed* swap of a single value. /// /// The codegen backends will replace this with a better implementation when @@ -3999,7 +3972,6 @@ pub use typed_swap as typed_swap_nonoverlapping; #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic -#[cfg(not(bootstrap))] pub const unsafe fn typed_swap_nonoverlapping(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind // pointers, so swapping them with `count: 1` is fine. diff --git a/core/src/intrinsics/simd.rs b/core/src/intrinsics/simd.rs index f80a60d471c04..d03d801b93652 100644 --- a/core/src/intrinsics/simd.rs +++ b/core/src/intrinsics/simd.rs @@ -623,7 +623,6 @@ extern "rust-intrinsic" { /// and others do not. /// /// `T` must be a vector of floats. - #[cfg(not(bootstrap))] #[rustc_nounwind] pub fn simd_relaxed_fma(x: T, y: T, z: T) -> T; diff --git a/core/src/lib.rs b/core/src/lib.rs index e31957a1fa703..e845bb34426c4 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -107,7 +107,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] diff --git a/core/src/marker.rs b/core/src/marker.rs index 29fc01d37fe3f..b1e67e4e90017 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -141,9 +141,8 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] #[rustc_coinductive] pub trait Sized { // Empty. @@ -183,9 +182,8 @@ pub trait Sized { /// [^1]: Formerly known as *object safe*. #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait Unsize { // Empty. } @@ -819,9 +817,8 @@ impl StructuralPartialEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -962,10 +959,9 @@ marker_impls! { #[unstable(feature = "const_destruct", issue = "133214")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] -#[cfg_attr(not(bootstrap), const_trait)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] +#[const_trait] pub trait Destruct {} /// A marker for tuple types. @@ -975,9 +971,8 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait Tuple {} /// A marker for pointer-like types. @@ -996,10 +991,9 @@ pub trait Tuple {} message = "`{Self}` needs to have the same ABI as a pointer", label = "`{Self}` needs to be a pointer-like type" )] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_do_not_implement_via_object] pub trait PointerLike {} -#[cfg(not(bootstrap))] marker_impls! { #[unstable(feature = "pointer_like_trait", issue = "none")] PointerLike for @@ -1086,9 +1080,8 @@ marker_impls! { reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait FnPtr: Copy + Clone { /// Returns the address of the function pointer. #[lang = "fn_ptr_addr"] @@ -1099,7 +1092,6 @@ pub trait FnPtr: Copy + Clone { #[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] -#[cfg(not(bootstrap))] pub macro CoercePointee($item:item) { /* compiler built-in */ } diff --git a/core/src/mem/transmutability.rs b/core/src/mem/transmutability.rs index 9cf587650d949..6a4f84c849cb1 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -84,9 +84,8 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// `usize` is stable, but not portable. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] #[rustc_coinductive] pub unsafe trait TransmuteFrom where diff --git a/core/src/ops/arith.rs b/core/src/ops/arith.rs index 565bccf589826..810b906b8715e 100644 --- a/core/src/ops/arith.rs +++ b/core/src/ops/arith.rs @@ -73,7 +73,7 @@ append_const_msg )] #[doc(alias = "+")] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -95,18 +95,6 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(bootstrap)] - impl Add for $t { - type Output = $t; - - #[inline] - #[track_caller] - #[rustc_inherit_overflow_checks] - fn add(self, other: $t) -> $t { self + other } - } - - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(bootstrap))] impl const Add for $t { type Output = $t; diff --git a/core/src/ops/async_function.rs b/core/src/ops/async_function.rs index 2ee243ea85eb4..c90ae7babbd93 100644 --- a/core/src/ops/async_function.rs +++ b/core/src/ops/async_function.rs @@ -4,8 +4,7 @@ use crate::marker::Tuple; /// An async-aware version of the [`Fn`](crate::ops::Fn) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -19,8 +18,7 @@ pub trait AsyncFn: AsyncFnMut { /// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -41,8 +39,7 @@ pub trait AsyncFnMut: AsyncFnOnce { /// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -67,8 +64,7 @@ mod impls { use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; use crate::marker::Tuple; - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl AsyncFn for &F where F: AsyncFn, @@ -78,8 +74,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl AsyncFnMut for &F where F: AsyncFn, @@ -94,8 +89,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F where F: AsyncFn, @@ -108,8 +102,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl AsyncFnMut for &mut F where F: AsyncFnMut, @@ -124,8 +117,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F where F: AsyncFnMut, diff --git a/core/src/ops/deref.rs b/core/src/ops/deref.rs index c36d55fe2a8c1..ed0d30a0f5026 100644 --- a/core/src/ops/deref.rs +++ b/core/src/ops/deref.rs @@ -133,7 +133,7 @@ #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -148,18 +148,6 @@ pub trait Deref { fn deref(&self) -> &Self::Target; } -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for &T { - type Target = T; - - #[rustc_diagnostic_item = "noop_method_deref"] - fn deref(&self) -> &T { - *self - } -} - -#[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl const Deref for &T { type Target = T; @@ -173,17 +161,6 @@ impl const Deref for &T { #[stable(feature = "rust1", since = "1.0.0")] impl !DerefMut for &T {} -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for &mut T { - type Target = T; - - fn deref(&self) -> &T { - *self - } -} - -#[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl const Deref for &mut T { type Target = T; @@ -282,7 +259,6 @@ impl const Deref for &mut T { /// *x = 'b'; /// assert_eq!('b', x.value); /// ``` -#[cfg(not(bootstrap))] #[lang = "deref_mut"] #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] @@ -294,27 +270,6 @@ pub trait DerefMut: ~const Deref { fn deref_mut(&mut self) -> &mut Self::Target; } -/// Bootstrap -#[lang = "deref_mut"] -#[doc(alias = "*")] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg(bootstrap)] -pub trait DerefMut: Deref { - /// Mutably dereferences the value. - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_diagnostic_item = "deref_mut_method"] - fn deref_mut(&mut self) -> &mut Self::Target; -} - -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for &mut T { - fn deref_mut(&mut self) -> &mut T { - *self - } -} - -#[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl const DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { diff --git a/core/src/ops/drop.rs b/core/src/ops/drop.rs index f3314364e5428..78b5252195f82 100644 --- a/core/src/ops/drop.rs +++ b/core/src/ops/drop.rs @@ -203,7 +203,7 @@ /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Drop { /// Executes the destructor for this type. /// diff --git a/core/src/ptr/metadata.rs b/core/src/ptr/metadata.rs index b1d5e1fa3a059..e93b5658e2436 100644 --- a/core/src/ptr/metadata.rs +++ b/core/src/ptr/metadata.rs @@ -53,9 +53,8 @@ use crate::ptr::NonNull; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 6287d8816b0fd..2c9131254f7c4 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -1598,7 +1598,6 @@ impl DispatchFromDyn> for NonNull where T: U unsafe impl PinCoerceUnsized for NonNull {} #[unstable(feature = "pointer_like_trait", issue = "none")] -#[cfg(not(bootstrap))] impl core::marker::PointerLike for NonNull {} #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index e6825d8e39e2c..7cefb615d0371 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -304,7 +304,7 @@ fn test_const_nonnull_new() { #[test] #[cfg(unix)] // printf may not be available on other platforms #[allow(deprecated)] // For SipHasher -#[cfg_attr(not(bootstrap), allow(unpredictable_function_pointer_comparisons))] +#[allow(unpredictable_function_pointer_comparisons)] pub fn test_variadic_fnptr() { use core::ffi; use core::hash::{Hash, SipHasher}; diff --git a/std/src/prelude/common.rs b/std/src/prelude/common.rs index 713e417e0440c..0f2d8334fca79 100644 --- a/std/src/prelude/common.rs +++ b/std/src/prelude/common.rs @@ -12,8 +12,7 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[doc(no_inline)] pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; From 544080ac585aac274128dca89a005882253b4cb9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 22:11:33 +0100 Subject: [PATCH 264/481] fmt --- core/src/hash/mod.rs | 5 +---- std/src/collections/hash/map.rs | 5 +---- std/src/collections/hash/set.rs | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/core/src/hash/mod.rs b/core/src/hash/mod.rs index b43cf68421594..7a6630c82d0da 100644 --- a/core/src/hash/mod.rs +++ b/core/src/hash/mod.rs @@ -753,10 +753,7 @@ pub struct BuildHasherDefault(marker::PhantomData H>); impl BuildHasherDefault { /// Creates a new BuildHasherDefault for Hasher `H`. #[stable(feature = "build_hasher_default_const_new", since = "1.85.0")] - #[rustc_const_stable( - feature = "build_hasher_default_const_new", - since = "1.85.0" - )] + #[rustc_const_stable(feature = "build_hasher_default_const_new", since = "1.85.0")] pub const fn new() -> Self { BuildHasherDefault(marker::PhantomData) } diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index f7d2eec90743c..d2342d8fd5176 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -296,10 +296,7 @@ impl HashMap { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_stable( - feature = "const_collections_with_hasher", - since = "1.85.0" - )] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hash_builder: S) -> HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } } diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index c1b794c58f120..bbb6ca2352136 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -388,10 +388,7 @@ impl HashSet { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_stable( - feature = "const_collections_with_hasher", - since = "1.85.0" - )] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hasher: S) -> HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } } From 04ee9b61c098adcc2f25d80a191b66fabc3d8ce1 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 21 Dec 2024 16:36:18 +0100 Subject: [PATCH 265/481] Improve prose around `as_slice` example of IterMut I've removed the cryptic message about not being able to call `&mut self` methods while retaining a shared borrow of the iterator, such as `as_slice` produces. This is just normal borrowing rules and does not seem especially relevant here. I can whip up a replacement if someone thinks it has value. --- core/src/slice/iter.rs | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index d2842f69008e2..a687ed7129dc8 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -49,7 +49,7 @@ impl<'a, T> IntoIterator for &'a mut [T] { /// // First, we need a slice to call the `iter` method on: /// let slice = &[1, 2, 3]; /// -/// // Then we call `iter` on the slice to get the `Iter` struct, +/// // Then we call `iter` on the slice to get the `Iter` iterator, /// // and iterate over it: /// for element in slice.iter() { /// println!("{element}"); @@ -107,24 +107,20 @@ impl<'a, T> Iter<'a, T> { /// Views the underlying data as a subslice of the original data. /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// /// # Examples /// /// Basic usage: /// /// ``` /// // First, we need a slice to call the `iter` method on: - /// // struct (`&[usize]` here): /// let slice = &[1, 2, 3]; /// - /// // Then we call `iter` on the slice to get the `Iter` struct: + /// // Then we call `iter` on the slice to get the `Iter` iterator: /// let mut iter = slice.iter(); /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]": /// println!("{:?}", iter.as_slice()); /// - /// // Now, we call the `next` method to remove the first element of the iterator: + /// // Now, we call the `next` method to remove the first element from the iterator: /// iter.next(); /// // Here the iterator does not contain the first element of the slice any more, /// // so `as_slice` only returns the last two elements of the slice, @@ -181,7 +177,7 @@ impl AsRef<[T]> for Iter<'_, T> { /// // First, we need a slice to call the `iter_mut` method on: /// let slice = &mut [1, 2, 3]; /// -/// // Then we call `iter_mut` on the slice to get the `IterMut` struct, +/// // Then we call `iter_mut` on the slice to get the `IterMut` iterator, /// // iterate over it and increment each element value: /// for element in slice.iter_mut() { /// *element += 1; @@ -286,25 +282,30 @@ impl<'a, T> IterMut<'a, T> { /// Views the underlying data as a subslice of the original data. /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// /// # Examples /// /// Basic usage: /// /// ``` - /// let mut slice: &mut [usize] = &mut [1, 2, 3]; + /// // First, we need a slice to call the `iter_mut` method on: + /// let slice = &mut [1, 2, 3]; /// - /// // First, we get the iterator: + /// // Then we call `iter_mut` on the slice to get the `IterMut` iterator: /// let mut iter = slice.iter_mut(); - /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": - /// assert_eq!(iter.as_slice(), &[1, 2, 3]); + /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]": + /// println!("{:?}", iter.as_slice()); /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// assert_eq!(iter.as_slice(), &[2, 3]); + /// // Now, we call the `next` method to remove the first element from the iterator + /// // and increment its value: + /// *iter.next().unwrap() += 1; + /// // Here the iterator does not contain the first element of the slice any more, + /// // so `as_slice` only returns the last two elements of the slice, + /// // and so this prints "[2, 3]": + /// println!("{:?}", iter.as_slice()); + /// + /// // The underlying slice still contains three elements, but its first element + /// // was increased by 1, so this prints "[2, 2, 3]": + /// println!("{:?}", slice); /// ``` #[must_use] #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] @@ -315,9 +316,6 @@ impl<'a, T> IterMut<'a, T> { /// Views the underlying data as a mutable subslice of the original data. /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// /// # Examples /// /// Basic usage: From e1555d0679c431e61d45aa3711b99fee80d3a276 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 30 Dec 2024 00:26:47 +0100 Subject: [PATCH 266/481] Fix ptr::from_ref documentation example comment The comment says that the expression involves no function call, but that was only true for the example above, the example here _does_ contain a function call. --- core/src/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index 3d9ad0706eb0b..f58c0e1241142 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -777,7 +777,7 @@ pub fn with_exposed_provenance_mut(addr: usize) -> *mut T { /// # type T = i32; /// # fn foo() -> T { 42 } /// // The temporary holding the return value of `foo` does *not* have its lifetime extended, -/// // because the surrounding expression involves no function call. +/// // because the surrounding expression involves a function call. /// let p = ptr::from_ref(&foo()); /// unsafe { p.read() }; // UB! Reading from a dangling pointer ⚠️ /// ``` @@ -828,7 +828,7 @@ pub const fn from_ref(r: &T) -> *const T { /// # type T = i32; /// # fn foo() -> T { 42 } /// // The temporary holding the return value of `foo` does *not* have its lifetime extended, -/// // because the surrounding expression involves no function call. +/// // because the surrounding expression involves a function call. /// let p = ptr::from_mut(&mut foo()); /// unsafe { p.write(T::default()) }; // UB! Writing to a dangling pointer ⚠️ /// ``` From c55d5c5678b1cccc0a2db41aded38400d061fda1 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Mon, 4 Nov 2024 20:59:22 +0300 Subject: [PATCH 267/481] Used pthread name functions returning result for FreeBSD and DragonFly --- std/src/sys/pal/unix/thread.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/std/src/sys/pal/unix/thread.rs b/std/src/sys/pal/unix/thread.rs index e360ba0f6d7d8..f657f82e6e368 100644 --- a/std/src/sys/pal/unix/thread.rs +++ b/std/src/sys/pal/unix/thread.rs @@ -130,25 +130,27 @@ impl Thread { } } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"))] pub fn set_name(name: &CStr) { - const TASK_COMM_LEN: usize = 16; - unsafe { - // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. - let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + // Linux limits the allowed length of the name. + const TASK_COMM_LEN: usize = 16; + let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + } else { + // FreeBSD and DragonFly BSD do not enforce length limits. + } + }; + // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux, + // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0. let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. debug_assert_eq!(res, 0); } } - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "nuttx" - ))] + #[cfg(any(target_os = "openbsd", target_os = "nuttx"))] pub fn set_name(name: &CStr) { unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); From 4f73954d900881a852dbde2caa7a8ee059fa0529 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 1 Jan 2025 18:51:39 +0100 Subject: [PATCH 268/481] Rename the internal simpler `quote` macro to `minimal_quote` --- proc_macro/src/quote.rs | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/proc_macro/src/quote.rs b/proc_macro/src/quote.rs index 04fa696d5e6be..6faa41b297005 100644 --- a/proc_macro/src/quote.rs +++ b/proc_macro/src/quote.rs @@ -6,10 +6,10 @@ use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; +macro_rules! minimal_quote_tt { + (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) }; + ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, minimal_quote!($($t)*)) }; + ({$($t:tt)*}) => { Group::new(Delimiter::Brace, minimal_quote!($($t)*)) }; (,) => { Punct::new(',', Spacing::Alone) }; (.) => { Punct::new('.', Spacing::Alone) }; (;) => { Punct::new(';', Spacing::Alone) }; @@ -21,7 +21,7 @@ macro_rules! quote_tt { ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; } -macro_rules! quote_ts { +macro_rules! minimal_quote_ts { ((@ $($t:tt)*)) => { $($t)* }; (::) => { [ @@ -35,7 +35,7 @@ macro_rules! quote_ts { }) .collect::() }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; + ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) }; } /// Simpler version of the real `quote!` macro, implemented solely @@ -46,11 +46,11 @@ macro_rules! quote_ts { /// /// Note: supported tokens are a subset of the real `quote!`, but /// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { +macro_rules! minimal_quote { () => { TokenStream::new() }; ($($t:tt)*) => { [ - $(TokenStream::from(quote_ts!($t)),)* + $(TokenStream::from(minimal_quote_ts!($t)),)* ].iter().cloned().collect::() }; } @@ -62,9 +62,9 @@ macro_rules! quote { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote(stream: TokenStream) -> TokenStream { if stream.is_empty() { - return quote!(crate::TokenStream::new()); + return minimal_quote!(crate::TokenStream::new()); } - let proc_macro_crate = quote!(crate); + let proc_macro_crate = minimal_quote!(crate); let mut after_dollar = false; let tokens = stream .into_iter() @@ -73,7 +73,7 @@ pub fn quote(stream: TokenStream) -> TokenStream { after_dollar = false; match tree { TokenTree::Ident(_) => { - return Some(quote!(Into::::into( + return Some(minimal_quote!(Into::::into( Clone::clone(&(@ tree))),)); } TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} @@ -86,28 +86,28 @@ pub fn quote(stream: TokenStream) -> TokenStream { } } - Some(quote!(crate::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new( + Some(minimal_quote!(crate::TokenStream::from((@ match tree { + TokenTree::Punct(tt) => minimal_quote!(crate::TokenTree::Punct(crate::Punct::new( (@ TokenTree::from(Literal::character(tt.as_char()))), (@ match tt.spacing() { - Spacing::Alone => quote!(crate::Spacing::Alone), - Spacing::Joint => quote!(crate::Spacing::Joint), + Spacing::Alone => minimal_quote!(crate::Spacing::Alone), + Spacing::Joint => minimal_quote!(crate::Spacing::Joint), }), ))), - TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new( + TokenTree::Group(tt) => minimal_quote!(crate::TokenTree::Group(crate::Group::new( (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis), - Delimiter::Brace => quote!(crate::Delimiter::Brace), - Delimiter::Bracket => quote!(crate::Delimiter::Bracket), - Delimiter::None => quote!(crate::Delimiter::None), + Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis), + Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace), + Delimiter::Bracket => minimal_quote!(crate::Delimiter::Bracket), + Delimiter::None => minimal_quote!(crate::Delimiter::None), }), (@ quote(tt.stream())), ))), - TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new( + TokenTree::Ident(tt) => minimal_quote!(crate::TokenTree::Ident(crate::Ident::new( (@ TokenTree::from(Literal::string(&tt.to_string()))), (@ quote_span(proc_macro_crate.clone(), tt.span())), ))), - TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({ + TokenTree::Literal(tt) => minimal_quote!(crate::TokenTree::Literal({ let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) .parse::() .unwrap() @@ -129,7 +129,7 @@ pub fn quote(stream: TokenStream) -> TokenStream { panic!("unexpected trailing `$` in `quote!`"); } - quote!([(@ tokens)].iter().cloned().collect::()) + minimal_quote!([(@ tokens)].iter().cloned().collect::()) } /// Quote a `Span` into a `TokenStream`. @@ -137,5 +137,5 @@ pub fn quote(stream: TokenStream) -> TokenStream { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) + minimal_quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) } From a16317639c2c27af8b6b00ac346a3e680bcbf5aa Mon Sep 17 00:00:00 2001 From: Asuna Date: Sun, 5 Jan 2025 23:47:32 +0100 Subject: [PATCH 269/481] Append `TokenTree` with `ToTokens` in `proc_macro::quote!` --- proc_macro/src/lib.rs | 2 +- proc_macro/src/quote.rs | 109 +++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index 26a09f0daca02..b19c9cee75a0b 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -419,7 +419,7 @@ pub mod token_stream { /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. #[unstable(feature = "proc_macro_quote", issue = "54722")] -#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)] +#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals, proc_macro_totokens)] #[rustc_builtin_macro] pub macro quote($($t:tt)*) { /* compiler built-in */ diff --git a/proc_macro/src/quote.rs b/proc_macro/src/quote.rs index 6faa41b297005..27c8458a351ca 100644 --- a/proc_macro/src/quote.rs +++ b/proc_macro/src/quote.rs @@ -4,7 +4,9 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use crate::{ + Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree, +}; macro_rules! minimal_quote_tt { (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) }; @@ -24,16 +26,15 @@ macro_rules! minimal_quote_tt { macro_rules! minimal_quote_ts { ((@ $($t:tt)*)) => { $($t)* }; (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() + { + let mut c = ( + TokenTree::from(Punct::new(':', Spacing::Joint)), + TokenTree::from(Punct::new(':', Spacing::Alone)) + ); + c.0.set_span(Span::def_site()); + c.1.set_span(Span::def_site()); + [c.0, c.1].into_iter().collect::() + } }; ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) }; } @@ -47,11 +48,13 @@ macro_rules! minimal_quote_ts { /// Note: supported tokens are a subset of the real `quote!`, but /// unquoting is different: instead of `$x`, this uses `(@ expr)`. macro_rules! minimal_quote { - () => { TokenStream::new() }; ($($t:tt)*) => { - [ - $(TokenStream::from(minimal_quote_ts!($t)),)* - ].iter().cloned().collect::() + { + #[allow(unused_mut)] // In case the expansion is empty + let mut ts = TokenStream::new(); + $(ToTokens::to_tokens(&minimal_quote_ts!($t), &mut ts);)* + ts + } }; } @@ -66,35 +69,39 @@ pub fn quote(stream: TokenStream) -> TokenStream { } let proc_macro_crate = minimal_quote!(crate); let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(minimal_quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; + + let mut tokens = crate::TokenStream::new(); + for tree in stream { + if after_dollar { + after_dollar = false; + match tree { + TokenTree::Ident(_) => { + minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);) + .to_tokens(&mut tokens); + continue; } + TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} + _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), } + } else if let TokenTree::Punct(ref tt) = tree { + if tt.as_char() == '$' { + after_dollar = true; + continue; + } + } - Some(minimal_quote!(crate::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => minimal_quote!(crate::TokenTree::Punct(crate::Punct::new( + match tree { + TokenTree::Punct(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new( (@ TokenTree::from(Literal::character(tt.as_char()))), (@ match tt.spacing() { Spacing::Alone => minimal_quote!(crate::Spacing::Alone), Spacing::Joint => minimal_quote!(crate::Spacing::Joint), }), - ))), - TokenTree::Group(tt) => minimal_quote!(crate::TokenTree::Group(crate::Group::new( + )), &mut ts);) + } + TokenTree::Group(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Group(crate::Group::new( (@ match tt.delimiter() { Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis), Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace), @@ -102,12 +109,16 @@ pub fn quote(stream: TokenStream) -> TokenStream { Delimiter::None => minimal_quote!(crate::Delimiter::None), }), (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => minimal_quote!(crate::TokenTree::Ident(crate::Ident::new( + )), &mut ts);) + } + TokenTree::Ident(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new( (@ TokenTree::from(Literal::string(&tt.to_string()))), (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => minimal_quote!(crate::TokenTree::Literal({ + )), &mut ts);) + } + TokenTree::Literal(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) .parse::() .unwrap() @@ -120,16 +131,22 @@ pub fn quote(stream: TokenStream) -> TokenStream { } else { unreachable!() } - })) - })),)) - }) - .collect::(); - + }), &mut ts);) + } + } + .to_tokens(&mut tokens); + } if after_dollar { panic!("unexpected trailing `$` in `quote!`"); } - minimal_quote!([(@ tokens)].iter().cloned().collect::()) + minimal_quote! { + { + let mut ts = crate::TokenStream::new(); + (@ tokens) + ts + } + } } /// Quote a `Span` into a `TokenStream`. From d9484d7c7c37260d5ebb43e26a58a9569ab0a8bb Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 9 Jan 2025 03:02:23 +0100 Subject: [PATCH 270/481] Fix `proc_macro::quote!` for raw ident --- proc_macro/src/quote.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/proc_macro/src/quote.rs b/proc_macro/src/quote.rs index 27c8458a351ca..bcb15912bb65e 100644 --- a/proc_macro/src/quote.rs +++ b/proc_macro/src/quote.rs @@ -112,8 +112,14 @@ pub fn quote(stream: TokenStream) -> TokenStream { )), &mut ts);) } TokenTree::Ident(tt) => { - minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), + let literal = tt.to_string(); + let (literal, ctor) = if let Some(stripped) = literal.strip_prefix("r#") { + (stripped, minimal_quote!(crate::Ident::new_raw)) + } else { + (literal.as_str(), minimal_quote!(crate::Ident::new)) + }; + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident((@ ctor)( + (@ TokenTree::from(Literal::string(literal))), (@ quote_span(proc_macro_crate.clone(), tt.span())), )), &mut ts);) } From 6c42898df3870a9787f531ea04f01ffa7ea290f2 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 10 Jan 2025 18:48:48 +0100 Subject: [PATCH 271/481] alloc: remove unsound `IsZero` for raw pointers Fixes #135338 --- alloc/src/vec/is_zero.rs | 15 ++------------- alloc/tests/vec.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/alloc/src/vec/is_zero.rs b/alloc/src/vec/is_zero.rs index ba57d940d8c99..a3ddd6f6e230e 100644 --- a/alloc/src/vec/is_zero.rs +++ b/alloc/src/vec/is_zero.rs @@ -40,19 +40,8 @@ impl_is_zero!(char, |x| x == '\0'); impl_is_zero!(f32, |x: f32| x.to_bits() == 0); impl_is_zero!(f64, |x: f64| x.to_bits() == 0); -unsafe impl IsZero for *const T { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } -} - -unsafe impl IsZero for *mut T { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } -} +// `IsZero` cannot be soundly implemented for pointers because of provenance +// (see #135338). unsafe impl IsZero for [T; N] { #[inline] diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index 2e654d3d1ff1e..b24daec2968e0 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -2742,3 +2742,13 @@ fn max_swap_remove() { let mut v = vec![0]; v.swap_remove(usize::MAX); } + +// Regression test for #135338 +#[test] +fn vec_null_ptr_roundtrip() { + let ptr = std::ptr::from_ref(&42); + let zero = ptr.with_addr(0); + let roundtripped = vec![zero; 1].pop().unwrap(); + let new = roundtripped.with_addr(ptr.addr()); + unsafe { new.read() }; +} From f8ca79c97b45f14cc1ba451e684d783b9d97f1cf Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 7 Jan 2025 19:35:37 -0800 Subject: [PATCH 272/481] Update a bunch of library types for MCP807 This greatly reduces the number of places that actually use the `rustc_layout_scalar_valid_range_*` attributes down to just 3: ``` library/core\src\ptr\non_null.rs 68:#[rustc_layout_scalar_valid_range_start(1)] library/core\src\num\niche_types.rs 19: #[rustc_layout_scalar_valid_range_start($low)] 20: #[rustc_layout_scalar_valid_range_end($high)] ``` Everything else -- PAL Nanoseconds, alloc's `Cap`, niched FDs, etc -- all just wrap those `niche_types` types. --- alloc/src/lib.rs | 1 + alloc/src/raw_vec.rs | 46 +++++---- core/src/num/mod.rs | 4 + core/src/num/niche_types.rs | 162 ++++++++++++++++++++++++++++++++ core/src/num/nonzero.rs | 31 +----- core/src/time.rs | 96 +++++++++---------- std/src/lib.rs | 1 + std/src/os/fd/owned.rs | 34 +++---- std/src/os/solid/io.rs | 27 +++--- std/src/os/windows/io/socket.rs | 39 +++----- std/src/sys/pal/solid/fs.rs | 14 ++- std/src/sys/pal/unix/time.rs | 33 ++++--- 12 files changed, 296 insertions(+), 192 deletions(-) create mode 100644 core/src/num/niche_types.rs diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 784af9407692a..a4c3b7dd1b1b2 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -142,6 +142,7 @@ #![feature(slice_range)] #![feature(std_internals)] #![feature(str_internals)] +#![feature(temporary_niche_types)] #![feature(trusted_fused)] #![feature(trusted_len)] #![feature(trusted_random_access)] diff --git a/alloc/src/raw_vec.rs b/alloc/src/raw_vec.rs index e93ff2f902378..ad86bf4bf072f 100644 --- a/alloc/src/raw_vec.rs +++ b/alloc/src/raw_vec.rs @@ -33,21 +33,15 @@ enum AllocInit { Zeroed, } -#[repr(transparent)] -#[cfg_attr(target_pointer_width = "16", rustc_layout_scalar_valid_range_end(0x7fff))] -#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0x7fff_ffff))] -#[cfg_attr(target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0x7fff_ffff_ffff_ffff))] -struct Cap(usize); +type Cap = core::num::niche_types::UsizeNoHighBit; -impl Cap { - const ZERO: Cap = unsafe { Cap(0) }; +const ZERO_CAP: Cap = unsafe { Cap::new_unchecked(0) }; - /// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`. - /// - /// # Safety: cap must be <= `isize::MAX`. - unsafe fn new(cap: usize) -> Self { - if T::IS_ZST { Cap::ZERO } else { unsafe { Self(cap) } } - } +/// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`. +/// +/// # Safety: cap must be <= `isize::MAX`. +unsafe fn new_cap(cap: usize) -> Cap { + if T::IS_ZST { ZERO_CAP } else { unsafe { Cap::new_unchecked(cap) } } } /// A low-level utility for more ergonomically allocating, reallocating, and deallocating @@ -257,7 +251,7 @@ impl RawVec { // SAFETY: Precondition passed to the caller unsafe { let ptr = ptr.cast(); - let capacity = Cap::new::(capacity); + let capacity = new_cap::(capacity); Self { inner: RawVecInner::from_raw_parts_in(ptr, capacity, alloc), _marker: PhantomData, @@ -275,7 +269,7 @@ impl RawVec { // SAFETY: Precondition passed to the caller unsafe { let ptr = ptr.cast(); - let capacity = Cap::new::(capacity); + let capacity = new_cap::(capacity); Self { inner: RawVecInner::from_nonnull_in(ptr, capacity, alloc), _marker: PhantomData } } } @@ -410,7 +404,7 @@ impl RawVecInner { const fn new_in(alloc: A, align: usize) -> Self { let ptr = unsafe { core::mem::transmute(align) }; // `cap: 0` means "unallocated". zero-sized types are ignored. - Self { ptr, cap: Cap::ZERO, alloc } + Self { ptr, cap: ZERO_CAP, alloc } } #[cfg(not(no_global_oom_handling))] @@ -483,7 +477,11 @@ impl RawVecInner { // Allocators currently return a `NonNull<[u8]>` whose length // matches the size requested. If that ever changes, the capacity // here should change to `ptr.len() / mem::size_of::()`. - Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc }) + Ok(Self { + ptr: Unique::from(ptr.cast()), + cap: unsafe { Cap::new_unchecked(capacity) }, + alloc, + }) } #[inline] @@ -508,7 +506,7 @@ impl RawVecInner { #[inline] const fn capacity(&self, elem_size: usize) -> usize { - if elem_size == 0 { usize::MAX } else { self.cap.0 } + if elem_size == 0 { usize::MAX } else { self.cap.as_inner() } } #[inline] @@ -518,7 +516,7 @@ impl RawVecInner { #[inline] fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { - if elem_layout.size() == 0 || self.cap.0 == 0 { + if elem_layout.size() == 0 || self.cap.as_inner() == 0 { None } else { // We could use Layout::array here which ensures the absence of isize and usize overflows @@ -526,7 +524,7 @@ impl RawVecInner { // has already been allocated so we know it can't overflow and currently Rust does not // support such types. So we can do better by skipping some checks and avoid an unwrap. unsafe { - let alloc_size = elem_layout.size().unchecked_mul(self.cap.0); + let alloc_size = elem_layout.size().unchecked_mul(self.cap.as_inner()); let layout = Layout::from_size_align_unchecked(alloc_size, elem_layout.align()); Some((self.ptr.into(), layout)) } @@ -562,7 +560,7 @@ impl RawVecInner { #[inline] #[track_caller] fn grow_one(&mut self, elem_layout: Layout) { - if let Err(err) = self.grow_amortized(self.cap.0, 1, elem_layout) { + if let Err(err) = self.grow_amortized(self.cap.as_inner(), 1, elem_layout) { handle_error(err); } } @@ -627,7 +625,7 @@ impl RawVecInner { // the size requested. If that ever changes, the capacity here should // change to `ptr.len() / mem::size_of::()`. self.ptr = Unique::from(ptr.cast()); - self.cap = unsafe { Cap(cap) }; + self.cap = unsafe { Cap::new_unchecked(cap) }; } fn grow_amortized( @@ -650,7 +648,7 @@ impl RawVecInner { // This guarantees exponential growth. The doubling cannot overflow // because `cap <= isize::MAX` and the type of `cap` is `usize`. - let cap = cmp::max(self.cap.0 * 2, required_cap); + let cap = cmp::max(self.cap.as_inner() * 2, required_cap); let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); let new_layout = layout_array(cap, elem_layout)?; @@ -719,7 +717,7 @@ impl RawVecInner { unsafe { self.alloc.deallocate(ptr, layout) }; self.ptr = unsafe { Unique::new_unchecked(ptr::without_provenance_mut(elem_layout.align())) }; - self.cap = Cap::ZERO; + self.cap = ZERO_CAP; } else { let ptr = unsafe { // Layout cannot overflow here because it would have diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 67d219654b969..6c1b568e231d0 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -51,6 +51,10 @@ mod overflow_panic; mod saturating; mod wrapping; +/// 100% perma-unstable +#[doc(hidden)] +pub mod niche_types; + #[stable(feature = "rust1", since = "1.0.0")] #[cfg(not(no_fp_fmt_parse))] pub use dec2flt::ParseFloatError; diff --git a/core/src/num/niche_types.rs b/core/src/num/niche_types.rs new file mode 100644 index 0000000000000..e4caf8a104cb6 --- /dev/null +++ b/core/src/num/niche_types.rs @@ -0,0 +1,162 @@ +#![unstable( + feature = "temporary_niche_types", + issue = "none", + reason = "for core, alloc, and std internals until pattern types are further along" +)] + +use crate::cmp::Ordering; +use crate::fmt; +use crate::hash::{Hash, Hasher}; +use crate::marker::StructuralPartialEq; + +macro_rules! define_valid_range_type { + ($( + $(#[$m:meta])* + $vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal); + )+) => {$( + #[derive(Clone, Copy, Eq)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start($low)] + #[rustc_layout_scalar_valid_range_end($high)] + $(#[$m])* + $vis struct $name($int); + + const _: () = { + // With the `valid_range` attributes, it's always specified as unsigned + assert!(<$uint>::MIN == 0); + let ulow: $uint = $low; + let uhigh: $uint = $high; + assert!(ulow <= uhigh); + + assert!(size_of::<$int>() == size_of::<$uint>()); + }; + + impl $name { + #[inline] + pub const unsafe fn new_unchecked(val: $int) -> Self { + // SAFETY: same precondition + unsafe { $name(val) } + } + + #[inline] + pub const fn as_inner(self) -> $int { + // SAFETY: This is a transparent wrapper, so unwrapping it is sound + // (Not using `.0` due to MCP#807.) + unsafe { crate::mem::transmute(self) } + } + } + + // This is required to allow matching a constant. We don't get it from a derive + // because the derived `PartialEq` would do a field projection, which is banned + // by . + impl StructuralPartialEq for $name {} + + impl PartialEq for $name { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.as_inner() == other.as_inner() + } + } + + impl Ord for $name { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&self.as_inner(), &other.as_inner()) + } + } + + impl PartialOrd for $name { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } + } + + impl Hash for $name { + // Required method + fn hash(&self, state: &mut H) { + Hash::hash(&self.as_inner(), state); + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <$int as fmt::Debug>::fmt(&self.as_inner(), f) + } + } + )+}; +} + +define_valid_range_type! { + pub struct Nanoseconds(u32 as u32 in 0..=999_999_999); +} + +impl Nanoseconds { + // SAFETY: 0 is within the valid range + pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) }; +} + +impl Default for Nanoseconds { + #[inline] + fn default() -> Self { + Self::ZERO + } +} + +define_valid_range_type! { + pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff); + pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff); + pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff); + pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff); + pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff); + + pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff); + pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff); + pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff); + pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff); + pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff); +} + +#[cfg(target_pointer_width = "16")] +define_valid_range_type! { + pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff); + pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff); + pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff); +} +#[cfg(target_pointer_width = "32")] +define_valid_range_type! { + pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff); + pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff); + pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff); +} +#[cfg(target_pointer_width = "64")] +define_valid_range_type! { + pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff); + pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff); + pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff); +} + +define_valid_range_type! { + pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe); + pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe); + + pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe); + pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe); +} + +pub trait NotAllOnesHelper { + type Type; +} +pub type NotAllOnes = ::Type; +impl NotAllOnesHelper for u32 { + type Type = U32NotAllOnes; +} +impl NotAllOnesHelper for i32 { + type Type = I32NotAllOnes; +} +impl NotAllOnesHelper for u64 { + type Type = U64NotAllOnes; +} +impl NotAllOnesHelper for i64 { + type Type = I64NotAllOnes; +} diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 926723b3dbab7..dbce64420ac45 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -37,41 +37,12 @@ pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed { macro_rules! impl_zeroable_primitive { ($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => { mod private { - use super::*; - #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] pub trait Sealed {} - - $( - // This inner type is never shown directly, so intentionally does not have Debug - #[expect(missing_debug_implementations)] - // Since this struct is non-generic and derives Copy, - // the derived Clone is `*self` and thus doesn't field-project. - #[derive(Clone, Copy)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - pub struct $NonZeroInner($primitive); - - // This is required to allow matching a constant. We don't get it from a derive - // because the derived `PartialEq` would do a field projection, which is banned - // by . - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - impl StructuralPartialEq for $NonZeroInner {} - )+ } $( @@ -88,7 +59,7 @@ macro_rules! impl_zeroable_primitive { issue = "none" )] unsafe impl ZeroablePrimitive for $primitive { - type NonZeroInner = private::$NonZeroInner; + type NonZeroInner = super::niche_types::$NonZeroInner; } )+ }; diff --git a/core/src/time.rs b/core/src/time.rs index 2d93148bac09f..22bd46c567eaa 100644 --- a/core/src/time.rs +++ b/core/src/time.rs @@ -21,6 +21,7 @@ use crate::fmt; use crate::iter::Sum; +use crate::num::niche_types::Nanoseconds; use crate::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; const NANOS_PER_SEC: u32 = 1_000_000_000; @@ -37,24 +38,6 @@ const HOURS_PER_DAY: u64 = 24; #[unstable(feature = "duration_units", issue = "120301")] const DAYS_PER_WEEK: u64 = 7; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -#[rustc_layout_scalar_valid_range_end(999_999_999)] -struct Nanoseconds(u32); - -impl Nanoseconds { - // SAFETY: 0 is within the valid range - const ZERO: Self = unsafe { Nanoseconds(0) }; -} - -impl Default for Nanoseconds { - #[inline] - fn default() -> Self { - Self::ZERO - } -} - /// A `Duration` type to represent a span of time, typically used for system /// timeouts. /// @@ -211,14 +194,14 @@ impl Duration { pub const fn new(secs: u64, nanos: u32) -> Duration { if nanos < NANOS_PER_SEC { // SAFETY: nanos < NANOS_PER_SEC, therefore nanos is within the valid range - Duration { secs, nanos: unsafe { Nanoseconds(nanos) } } + Duration { secs, nanos: unsafe { Nanoseconds::new_unchecked(nanos) } } } else { let secs = secs .checked_add((nanos / NANOS_PER_SEC) as u64) .expect("overflow in Duration::new"); let nanos = nanos % NANOS_PER_SEC; // SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range - Duration { secs, nanos: unsafe { Nanoseconds(nanos) } } + Duration { secs, nanos: unsafe { Nanoseconds::new_unchecked(nanos) } } } } @@ -263,7 +246,7 @@ impl Duration { let subsec_millis = (millis % MILLIS_PER_SEC) as u32; // SAFETY: (x % 1_000) * 1_000_000 < 1_000_000_000 // => x % 1_000 < 1_000 - let subsec_nanos = unsafe { Nanoseconds(subsec_millis * NANOS_PER_MILLI) }; + let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_millis * NANOS_PER_MILLI) }; Duration { secs, nanos: subsec_nanos } } @@ -289,7 +272,7 @@ impl Duration { let subsec_micros = (micros % MICROS_PER_SEC) as u32; // SAFETY: (x % 1_000_000) * 1_000 < 1_000_000_000 // => x % 1_000_000 < 1_000_000 - let subsec_nanos = unsafe { Nanoseconds(subsec_micros * NANOS_PER_MICRO) }; + let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_micros * NANOS_PER_MICRO) }; Duration { secs, nanos: subsec_nanos } } @@ -320,7 +303,7 @@ impl Duration { let secs = nanos / NANOS_PER_SEC; let subsec_nanos = (nanos % NANOS_PER_SEC) as u32; // SAFETY: x % 1_000_000_000 < 1_000_000_000 - let subsec_nanos = unsafe { Nanoseconds(subsec_nanos) }; + let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_nanos) }; Duration { secs, nanos: subsec_nanos } } @@ -458,7 +441,7 @@ impl Duration { #[rustc_const_stable(feature = "duration_zero", since = "1.53.0")] #[inline] pub const fn is_zero(&self) -> bool { - self.secs == 0 && self.nanos.0 == 0 + self.secs == 0 && self.nanos.as_inner() == 0 } /// Returns the number of _whole_ seconds contained by this `Duration`. @@ -509,7 +492,7 @@ impl Duration { #[must_use] #[inline] pub const fn subsec_millis(&self) -> u32 { - self.nanos.0 / NANOS_PER_MILLI + self.nanos.as_inner() / NANOS_PER_MILLI } /// Returns the fractional part of this `Duration`, in whole microseconds. @@ -532,7 +515,7 @@ impl Duration { #[must_use] #[inline] pub const fn subsec_micros(&self) -> u32 { - self.nanos.0 / NANOS_PER_MICRO + self.nanos.as_inner() / NANOS_PER_MICRO } /// Returns the fractional part of this `Duration`, in nanoseconds. @@ -555,7 +538,7 @@ impl Duration { #[must_use] #[inline] pub const fn subsec_nanos(&self) -> u32 { - self.nanos.0 + self.nanos.as_inner() } /// Returns the total number of whole milliseconds contained by this `Duration`. @@ -573,7 +556,8 @@ impl Duration { #[must_use] #[inline] pub const fn as_millis(&self) -> u128 { - self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MILLI) as u128 + self.secs as u128 * MILLIS_PER_SEC as u128 + + (self.nanos.as_inner() / NANOS_PER_MILLI) as u128 } /// Returns the total number of whole microseconds contained by this `Duration`. @@ -591,7 +575,8 @@ impl Duration { #[must_use] #[inline] pub const fn as_micros(&self) -> u128 { - self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MICRO) as u128 + self.secs as u128 * MICROS_PER_SEC as u128 + + (self.nanos.as_inner() / NANOS_PER_MICRO) as u128 } /// Returns the total number of nanoseconds contained by this `Duration`. @@ -609,7 +594,7 @@ impl Duration { #[must_use] #[inline] pub const fn as_nanos(&self) -> u128 { - self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.0 as u128 + self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.as_inner() as u128 } /// Computes the absolute difference between `self` and `other`. @@ -649,7 +634,7 @@ impl Duration { #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")] pub const fn checked_add(self, rhs: Duration) -> Option { if let Some(mut secs) = self.secs.checked_add(rhs.secs) { - let mut nanos = self.nanos.0 + rhs.nanos.0; + let mut nanos = self.nanos.as_inner() + rhs.nanos.as_inner(); if nanos >= NANOS_PER_SEC { nanos -= NANOS_PER_SEC; if let Some(new_secs) = secs.checked_add(1) { @@ -707,11 +692,11 @@ impl Duration { #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")] pub const fn checked_sub(self, rhs: Duration) -> Option { if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { - let nanos = if self.nanos.0 >= rhs.nanos.0 { - self.nanos.0 - rhs.nanos.0 + let nanos = if self.nanos.as_inner() >= rhs.nanos.as_inner() { + self.nanos.as_inner() - rhs.nanos.as_inner() } else if let Some(sub_secs) = secs.checked_sub(1) { secs = sub_secs; - self.nanos.0 + NANOS_PER_SEC - rhs.nanos.0 + self.nanos.as_inner() + NANOS_PER_SEC - rhs.nanos.as_inner() } else { return None; }; @@ -763,7 +748,7 @@ impl Duration { #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")] pub const fn checked_mul(self, rhs: u32) -> Option { // Multiply nanoseconds as u64, because it cannot overflow that way. - let total_nanos = self.nanos.0 as u64 * rhs as u64; + let total_nanos = self.nanos.as_inner() as u64 * rhs as u64; let extra_secs = total_nanos / (NANOS_PER_SEC as u64); let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; // FIXME(const-hack): use `and_then` once that is possible. @@ -820,7 +805,8 @@ impl Duration { pub const fn checked_div(self, rhs: u32) -> Option { if rhs != 0 { let (secs, extra_secs) = (self.secs / (rhs as u64), self.secs % (rhs as u64)); - let (mut nanos, extra_nanos) = (self.nanos.0 / rhs, self.nanos.0 % rhs); + let (mut nanos, extra_nanos) = + (self.nanos.as_inner() / rhs, self.nanos.as_inner() % rhs); nanos += ((extra_secs * (NANOS_PER_SEC as u64) + extra_nanos as u64) / (rhs as u64)) as u32; debug_assert!(nanos < NANOS_PER_SEC); @@ -846,7 +832,7 @@ impl Duration { #[inline] #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")] pub const fn as_secs_f64(&self) -> f64 { - (self.secs as f64) + (self.nanos.0 as f64) / (NANOS_PER_SEC as f64) + (self.secs as f64) + (self.nanos.as_inner() as f64) / (NANOS_PER_SEC as f64) } /// Returns the number of seconds contained by this `Duration` as `f32`. @@ -865,7 +851,7 @@ impl Duration { #[inline] #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")] pub const fn as_secs_f32(&self) -> f32 { - (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32) + (self.secs as f32) + (self.nanos.as_inner() as f32) / (NANOS_PER_SEC as f32) } /// Returns the number of milliseconds contained by this `Duration` as `f64`. @@ -885,7 +871,7 @@ impl Duration { #[inline] pub const fn as_millis_f64(&self) -> f64 { (self.secs as f64) * (MILLIS_PER_SEC as f64) - + (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64) + + (self.nanos.as_inner() as f64) / (NANOS_PER_MILLI as f64) } /// Returns the number of milliseconds contained by this `Duration` as `f32`. @@ -905,7 +891,7 @@ impl Duration { #[inline] pub const fn as_millis_f32(&self) -> f32 { (self.secs as f32) * (MILLIS_PER_SEC as f32) - + (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32) + + (self.nanos.as_inner() as f32) / (NANOS_PER_MILLI as f32) } /// Creates a new `Duration` from the specified number of seconds represented @@ -1084,8 +1070,9 @@ impl Duration { #[inline] #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")] pub const fn div_duration_f64(self, rhs: Duration) -> f64 { - let self_nanos = (self.secs as f64) * (NANOS_PER_SEC as f64) + (self.nanos.0 as f64); - let rhs_nanos = (rhs.secs as f64) * (NANOS_PER_SEC as f64) + (rhs.nanos.0 as f64); + let self_nanos = + (self.secs as f64) * (NANOS_PER_SEC as f64) + (self.nanos.as_inner() as f64); + let rhs_nanos = (rhs.secs as f64) * (NANOS_PER_SEC as f64) + (rhs.nanos.as_inner() as f64); self_nanos / rhs_nanos } @@ -1105,8 +1092,9 @@ impl Duration { #[inline] #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")] pub const fn div_duration_f32(self, rhs: Duration) -> f32 { - let self_nanos = (self.secs as f32) * (NANOS_PER_SEC as f32) + (self.nanos.0 as f32); - let rhs_nanos = (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos.0 as f32); + let self_nanos = + (self.secs as f32) * (NANOS_PER_SEC as f32) + (self.nanos.as_inner() as f32); + let rhs_nanos = (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos.as_inner() as f32); self_nanos / rhs_nanos } } @@ -1201,13 +1189,13 @@ macro_rules! sum_durations { for entry in $iter { total_secs = total_secs.checked_add(entry.secs).expect("overflow in iter::sum over durations"); - total_nanos = match total_nanos.checked_add(entry.nanos.0 as u64) { + total_nanos = match total_nanos.checked_add(entry.nanos.as_inner() as u64) { Some(n) => n, None => { total_secs = total_secs .checked_add(total_nanos / NANOS_PER_SEC as u64) .expect("overflow in iter::sum over durations"); - (total_nanos % NANOS_PER_SEC as u64) + entry.nanos.0 as u64 + (total_nanos % NANOS_PER_SEC as u64) + entry.nanos.as_inner() as u64 } }; } @@ -1399,27 +1387,27 @@ impl fmt::Debug for Duration { let prefix = if f.sign_plus() { "+" } else { "" }; if self.secs > 0 { - fmt_decimal(f, self.secs, self.nanos.0, NANOS_PER_SEC / 10, prefix, "s") - } else if self.nanos.0 >= NANOS_PER_MILLI { + fmt_decimal(f, self.secs, self.nanos.as_inner(), NANOS_PER_SEC / 10, prefix, "s") + } else if self.nanos.as_inner() >= NANOS_PER_MILLI { fmt_decimal( f, - (self.nanos.0 / NANOS_PER_MILLI) as u64, - self.nanos.0 % NANOS_PER_MILLI, + (self.nanos.as_inner() / NANOS_PER_MILLI) as u64, + self.nanos.as_inner() % NANOS_PER_MILLI, NANOS_PER_MILLI / 10, prefix, "ms", ) - } else if self.nanos.0 >= NANOS_PER_MICRO { + } else if self.nanos.as_inner() >= NANOS_PER_MICRO { fmt_decimal( f, - (self.nanos.0 / NANOS_PER_MICRO) as u64, - self.nanos.0 % NANOS_PER_MICRO, + (self.nanos.as_inner() / NANOS_PER_MICRO) as u64, + self.nanos.as_inner() % NANOS_PER_MICRO, NANOS_PER_MICRO / 10, prefix, "µs", ) } else { - fmt_decimal(f, self.nanos.0 as u64, 0, 1, prefix, "ns") + fmt_decimal(f, self.nanos.as_inner() as u64, 0, 1, prefix, "ns") } } } diff --git a/std/src/lib.rs b/std/src/lib.rs index 2f8f5c5c58180..022bbab1012dd 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -357,6 +357,7 @@ #![feature(str_internals)] #![feature(strict_provenance_atomic_ptr)] #![feature(sync_unsafe_cell)] +#![feature(temporary_niche_types)] #![feature(ub_checks)] #![feature(used_with_arg)] // tidy-alphabetical-end diff --git a/std/src/os/fd/owned.rs b/std/src/os/fd/owned.rs index abb13b75f5087..1e814eca3c1a5 100644 --- a/std/src/os/fd/owned.rs +++ b/std/src/os/fd/owned.rs @@ -11,6 +11,8 @@ use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, fs, io}; +type ValidRawFd = core::num::niche_types::NotAllOnes; + /// A borrowed file descriptor. /// /// This has a lifetime parameter to tie it to the lifetime of something that owns the file @@ -32,15 +34,10 @@ use crate::{fmt, fs, io}; /// instead, but this is not supported on all platforms. #[derive(Copy, Clone)] #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct BorrowedFd<'fd> { - fd: RawFd, + fd: ValidRawFd, _phantom: PhantomData<&'fd OwnedFd>, } @@ -56,15 +53,10 @@ pub struct BorrowedFd<'fd> { /// /// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`]. #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct OwnedFd { - fd: RawFd, + fd: ValidRawFd, } impl BorrowedFd<'_> { @@ -80,7 +72,8 @@ impl BorrowedFd<'_> { pub const unsafe fn borrow_raw(fd: RawFd) -> Self { assert!(fd != u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd, _phantom: PhantomData } } + let fd = unsafe { ValidRawFd::new_unchecked(fd) }; + Self { fd, _phantom: PhantomData } } } @@ -130,7 +123,7 @@ impl BorrowedFd<'_> { impl AsRawFd for BorrowedFd<'_> { #[inline] fn as_raw_fd(&self) -> RawFd { - self.fd + self.fd.as_inner() } } @@ -138,7 +131,7 @@ impl AsRawFd for BorrowedFd<'_> { impl AsRawFd for OwnedFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.fd + self.fd.as_inner() } } @@ -146,7 +139,7 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - ManuallyDrop::new(self).fd + ManuallyDrop::new(self).fd.as_inner() } } @@ -164,7 +157,8 @@ impl FromRawFd for OwnedFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { assert_ne!(fd, u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd } } + let fd = unsafe { ValidRawFd::new_unchecked(fd) }; + Self { fd } } } @@ -187,12 +181,12 @@ impl Drop for OwnedFd { #[cfg(not(target_os = "hermit"))] { #[cfg(unix)] - crate::sys::fs::debug_assert_fd_is_open(self.fd); + crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner()); - let _ = libc::close(self.fd); + let _ = libc::close(self.fd.as_inner()); } #[cfg(target_os = "hermit")] - let _ = hermit_abi::close(self.fd); + let _ = hermit_abi::close(self.fd.as_inner()); } } } diff --git a/std/src/os/solid/io.rs b/std/src/os/solid/io.rs index 2d18f33961506..b8601b533fe0d 100644 --- a/std/src/os/solid/io.rs +++ b/std/src/os/solid/io.rs @@ -54,6 +54,9 @@ use crate::{fmt, net, sys}; /// Raw file descriptors. pub type RawFd = i32; +// The max of this is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`. +type ValidRawFd = core::num::niche_types::NotAllOnes; + /// A borrowed SOLID Sockets file descriptor. /// /// This has a lifetime parameter to tie it to the lifetime of something that @@ -69,12 +72,9 @@ pub type RawFd = i32; /// socket, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[rustc_nonnull_optimization_guaranteed] pub struct BorrowedFd<'socket> { - fd: RawFd, + fd: ValidRawFd, _phantom: PhantomData<&'socket OwnedFd>, } @@ -87,12 +87,9 @@ pub struct BorrowedFd<'socket> { /// an argument, it is not captured or consumed, and it never has the value /// `SOLID_NET_INVALID_FD`. #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[rustc_nonnull_optimization_guaranteed] pub struct OwnedFd { - fd: RawFd, + fd: ValidRawFd, } impl BorrowedFd<'_> { @@ -108,7 +105,8 @@ impl BorrowedFd<'_> { assert!(fd != -1 as RawFd); // SAFETY: we just asserted that the value is in the valid range and // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd, _phantom: PhantomData } } + let fd = unsafe { ValidRawFd::new_unchecked(fd) }; + Self { fd, _phantom: PhantomData } } } @@ -132,21 +130,21 @@ impl BorrowedFd<'_> { impl AsRawFd for BorrowedFd<'_> { #[inline] fn as_raw_fd(&self) -> RawFd { - self.fd + self.fd.as_inner() } } impl AsRawFd for OwnedFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.fd + self.fd.as_inner() } } impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - ManuallyDrop::new(self).fd + ManuallyDrop::new(self).fd.as_inner() } } @@ -162,14 +160,15 @@ impl FromRawFd for OwnedFd { assert_ne!(fd, -1 as RawFd); // SAFETY: we just asserted that the value is in the valid range and // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd } } + let fd = unsafe { ValidRawFd::new_unchecked(fd) }; + Self { fd } } } impl Drop for OwnedFd { #[inline] fn drop(&mut self) { - unsafe { sys::net::netc::close(self.fd) }; + unsafe { sys::net::netc::close(self.fd.as_inner()) }; } } diff --git a/std/src/os/windows/io/socket.rs b/std/src/os/windows/io/socket.rs index c6d7bad944093..6e13a8b502a73 100644 --- a/std/src/os/windows/io/socket.rs +++ b/std/src/os/windows/io/socket.rs @@ -9,6 +9,9 @@ use crate::mem::{self, ManuallyDrop}; use crate::sys::cvt; use crate::{fmt, io, sys}; +// The max here is -2, in two's complement. -1 is `INVALID_SOCKET`. +type ValidRawSocket = core::num::niche_types::NotAllOnes; + /// A borrowed socket. /// /// This has a lifetime parameter to tie it to the lifetime of something that @@ -24,17 +27,10 @@ use crate::{fmt, io, sys}; /// socket, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// This is -2, in two's complement. -1 is `INVALID_SOCKET`. -#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] -#[cfg_attr( - target_pointer_width = "64", - rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) -)] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct BorrowedSocket<'socket> { - socket: RawSocket, + socket: ValidRawSocket, _phantom: PhantomData<&'socket OwnedSocket>, } @@ -47,17 +43,10 @@ pub struct BorrowedSocket<'socket> { /// argument or returned as an owned value, and it never has the value /// `INVALID_SOCKET`. #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// This is -2, in two's complement. -1 is `INVALID_SOCKET`. -#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] -#[cfg_attr( - target_pointer_width = "64", - rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) -)] #[rustc_nonnull_optimization_guaranteed] #[stable(feature = "io_safety", since = "1.63.0")] pub struct OwnedSocket { - socket: RawSocket, + socket: ValidRawSocket, } impl BorrowedSocket<'_> { @@ -73,7 +62,8 @@ impl BorrowedSocket<'_> { #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(socket: RawSocket) -> Self { assert!(socket != sys::c::INVALID_SOCKET as RawSocket); - unsafe { Self { socket, _phantom: PhantomData } } + let socket = unsafe { ValidRawSocket::new_unchecked(socket) }; + Self { socket, _phantom: PhantomData } } } @@ -172,7 +162,7 @@ fn last_error() -> io::Error { impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.socket + self.socket.as_inner() } } @@ -180,7 +170,7 @@ impl AsRawSocket for BorrowedSocket<'_> { impl AsRawSocket for OwnedSocket { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.socket + self.socket.as_inner() } } @@ -188,7 +178,7 @@ impl AsRawSocket for OwnedSocket { impl IntoRawSocket for OwnedSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - ManuallyDrop::new(self).socket + ManuallyDrop::new(self).socket.as_inner() } } @@ -196,10 +186,9 @@ impl IntoRawSocket for OwnedSocket { impl FromRawSocket for OwnedSocket { #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { - unsafe { - debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket); - Self { socket } - } + debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket); + let socket = unsafe { ValidRawSocket::new_unchecked(socket) }; + Self { socket } } } @@ -208,7 +197,7 @@ impl Drop for OwnedSocket { #[inline] fn drop(&mut self) { unsafe { - let _ = sys::c::closesocket(self.socket as sys::c::SOCKET); + let _ = sys::c::closesocket(self.socket.as_inner() as sys::c::SOCKET); } } } diff --git a/std/src/sys/pal/solid/fs.rs b/std/src/sys/pal/solid/fs.rs index 04dd10ad806d3..fa2e470d6b601 100644 --- a/std/src/sys/pal/solid/fs.rs +++ b/std/src/sys/pal/solid/fs.rs @@ -12,15 +12,12 @@ use crate::sys::unsupported; pub use crate::sys_common::fs::exists; use crate::sys_common::ignore_notfound; +type CIntNotMinusOne = core::num::niche_types::NotAllOnes; + /// A file descriptor. #[derive(Clone, Copy)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] struct FileDesc { - fd: c_int, + fd: CIntNotMinusOne, } impl FileDesc { @@ -29,12 +26,13 @@ impl FileDesc { assert_ne!(fd, -1i32); // Safety: we just asserted that the value is in the valid range and // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { FileDesc { fd } } + let fd = unsafe { CIntNotMinusOne::new_unchecked(fd) }; + FileDesc { fd } } #[inline] fn raw(&self) -> c_int { - self.fd + self.fd.as_inner() } } diff --git a/std/src/sys/pal/unix/time.rs b/std/src/sys/pal/unix/time.rs index 343864d0b3fd2..e224980e95f31 100644 --- a/std/src/sys/pal/unix/time.rs +++ b/std/src/sys/pal/unix/time.rs @@ -1,3 +1,5 @@ +use core::num::niche_types::Nanoseconds; + use crate::time::Duration; use crate::{fmt, io}; @@ -15,12 +17,6 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec { tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -#[rustc_layout_scalar_valid_range_end(999_999_999)] -struct Nanoseconds(u32); - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SystemTime { pub(crate) t: Timespec, @@ -59,14 +55,14 @@ impl fmt::Debug for SystemTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SystemTime") .field("tv_sec", &self.t.tv_sec) - .field("tv_nsec", &self.t.tv_nsec.0) + .field("tv_nsec", &self.t.tv_nsec) .finish() } } impl Timespec { const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { - Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } } + Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } } pub const fn zero() -> Timespec { @@ -147,12 +143,15 @@ impl Timespec { // // Ideally this code could be rearranged such that it more // directly expresses the lower-cost behavior we want from it. - let (secs, nsec) = if self.tv_nsec.0 >= other.tv_nsec.0 { - ((self.tv_sec - other.tv_sec) as u64, self.tv_nsec.0 - other.tv_nsec.0) + let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() { + ( + (self.tv_sec - other.tv_sec) as u64, + self.tv_nsec.as_inner() - other.tv_nsec.as_inner(), + ) } else { ( (self.tv_sec - other.tv_sec - 1) as u64, - self.tv_nsec.0 + (NSEC_PER_SEC as u32) - other.tv_nsec.0, + self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(), ) }; @@ -170,7 +169,7 @@ impl Timespec { // Nano calculations can't overflow because nanos are <1B which fit // in a u32. - let mut nsec = other.subsec_nanos() + self.tv_nsec.0; + let mut nsec = other.subsec_nanos() + self.tv_nsec.as_inner(); if nsec >= NSEC_PER_SEC as u32 { nsec -= NSEC_PER_SEC as u32; secs = secs.checked_add(1)?; @@ -182,7 +181,7 @@ impl Timespec { let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?; // Similar to above, nanos can't overflow. - let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32; + let mut nsec = self.tv_nsec.as_inner() as i32 - other.subsec_nanos() as i32; if nsec < 0 { nsec += NSEC_PER_SEC as i32; secs = secs.checked_sub(1)?; @@ -194,7 +193,7 @@ impl Timespec { pub fn to_timespec(&self) -> Option { Some(libc::timespec { tv_sec: self.tv_sec.try_into().ok()?, - tv_nsec: self.tv_nsec.0.try_into().ok()?, + tv_nsec: self.tv_nsec.as_inner().try_into().ok()?, }) } @@ -203,7 +202,7 @@ impl Timespec { #[cfg(target_os = "nto")] pub(in crate::sys) fn to_timespec_capped(&self) -> Option { // Check if timeout in nanoseconds would fit into an u64 - if (self.tv_nsec.0 as u64) + if (self.tv_nsec.as_inner() as u64) .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?) .is_none() { @@ -219,7 +218,7 @@ impl Timespec { not(target_arch = "riscv32") ))] pub fn to_timespec64(&self) -> __timespec64 { - __timespec64::new(self.tv_sec, self.tv_nsec.0 as _) + __timespec64::new(self.tv_sec, self.tv_nsec.as_inner() as _) } } @@ -293,7 +292,7 @@ impl fmt::Debug for Instant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Instant") .field("tv_sec", &self.t.tv_sec) - .field("tv_nsec", &self.t.tv_nsec.0) + .field("tv_nsec", &self.t.tv_nsec) .finish() } } From db6cb4520eeeac0fda5d57de68ceb84365a41db4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 10 Jan 2025 18:52:22 -0800 Subject: [PATCH 273/481] Improve the safety documentation on new_unchecked --- core/src/num/niche_types.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/num/niche_types.rs b/core/src/num/niche_types.rs index e4caf8a104cb6..096713c318f8d 100644 --- a/core/src/num/niche_types.rs +++ b/core/src/num/niche_types.rs @@ -32,9 +32,15 @@ macro_rules! define_valid_range_type { }; impl $name { + /// Constructs an instance of this type from the underlying integer + /// primitive without checking whether its zero. + /// + /// # Safety + /// Immediate language UB if `val == 0`, as it violates the validity + /// invariant of this type. #[inline] pub const unsafe fn new_unchecked(val: $int) -> Self { - // SAFETY: same precondition + // SAFETY: Caller promised that `val` is non-zero. unsafe { $name(val) } } From 193e27136c9065c96c086b112a28dc53f3cd4830 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 10 Jan 2025 12:25:45 +0530 Subject: [PATCH 274/481] Initial fs module for uefi - Just a copy of unsupported fs right now to reduce the noise from future PRs to allow for easier review. - For the full working version of fs on uefi, see [0] [0]: https://github.com/Ayush1325/rust/tree/uefi-file-full Signed-off-by: Ayush Singh --- std/src/sys/pal/uefi/fs.rs | 344 ++++++++++++++++++++++++++++++++++++ std/src/sys/pal/uefi/mod.rs | 1 - 2 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 std/src/sys/pal/uefi/fs.rs diff --git a/std/src/sys/pal/uefi/fs.rs b/std/src/sys/pal/uefi/fs.rs new file mode 100644 index 0000000000000..9585ec24f687d --- /dev/null +++ b/std/src/sys/pal/uefi/fs.rs @@ -0,0 +1,344 @@ +use crate::ffi::OsString; +use crate::fmt; +use crate::hash::{Hash, Hasher}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::path::{Path, PathBuf}; +use crate::sys::time::SystemTime; +use crate::sys::unsupported; + +pub struct File(!); + +pub struct FileAttr(!); + +pub struct ReadDir(!); + +pub struct DirEntry(!); + +#[derive(Clone, Debug)] +pub struct OpenOptions {} + +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes {} + +pub struct FilePermissions(!); + +pub struct FileType(!); + +#[derive(Debug)] +pub struct DirBuilder {} + +impl FileAttr { + pub fn size(&self) -> u64 { + self.0 + } + + pub fn perm(&self) -> FilePermissions { + self.0 + } + + pub fn file_type(&self) -> FileType { + self.0 + } + + pub fn modified(&self) -> io::Result { + self.0 + } + + pub fn accessed(&self) -> io::Result { + self.0 + } + + pub fn created(&self) -> io::Result { + self.0 + } +} + +impl Clone for FileAttr { + fn clone(&self) -> FileAttr { + self.0 + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + self.0 + } + + pub fn set_readonly(&mut self, _readonly: bool) { + self.0 + } +} + +impl Clone for FilePermissions { + fn clone(&self) -> FilePermissions { + self.0 + } +} + +impl PartialEq for FilePermissions { + fn eq(&self, _other: &FilePermissions) -> bool { + self.0 + } +} + +impl Eq for FilePermissions {} + +impl fmt::Debug for FilePermissions { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl FileTimes { + pub fn set_accessed(&mut self, _t: SystemTime) {} + pub fn set_modified(&mut self, _t: SystemTime) {} +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.0 + } + + pub fn is_file(&self) -> bool { + self.0 + } + + pub fn is_symlink(&self) -> bool { + self.0 + } +} + +impl Clone for FileType { + fn clone(&self) -> FileType { + self.0 + } +} + +impl Copy for FileType {} + +impl PartialEq for FileType { + fn eq(&self, _other: &FileType) -> bool { + self.0 + } +} + +impl Eq for FileType {} + +impl Hash for FileType { + fn hash(&self, _h: &mut H) { + self.0 + } +} + +impl fmt::Debug for FileType { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.0 + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.0 + } + + pub fn file_name(&self) -> OsString { + self.0 + } + + pub fn metadata(&self) -> io::Result { + self.0 + } + + pub fn file_type(&self) -> io::Result { + self.0 + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions {} + } + + pub fn read(&mut self, _read: bool) {} + pub fn write(&mut self, _write: bool) {} + pub fn append(&mut self, _append: bool) {} + pub fn truncate(&mut self, _truncate: bool) {} + pub fn create(&mut self, _create: bool) {} + pub fn create_new(&mut self, _create_new: bool) {} +} + +impl File { + pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { + unsupported() + } + + pub fn file_attr(&self) -> io::Result { + self.0 + } + + pub fn fsync(&self) -> io::Result<()> { + self.0 + } + + pub fn datasync(&self) -> io::Result<()> { + self.0 + } + + pub fn lock(&self) -> io::Result<()> { + self.0 + } + + pub fn lock_shared(&self) -> io::Result<()> { + self.0 + } + + pub fn try_lock(&self) -> io::Result { + self.0 + } + + pub fn try_lock_shared(&self) -> io::Result { + self.0 + } + + pub fn unlock(&self) -> io::Result<()> { + self.0 + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + self.0 + } + + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + self.0 + } + + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0 + } + + pub fn is_read_vectored(&self) -> bool { + self.0 + } + + pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + self.0 + } + + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + self.0 + } + + pub fn is_write_vectored(&self) -> bool { + self.0 + } + + pub fn flush(&self) -> io::Result<()> { + self.0 + } + + pub fn seek(&self, _pos: SeekFrom) -> io::Result { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + self.0 + } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + self.0 + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, _p: &Path) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub fn readdir(_p: &Path) -> io::Result { + unsupported() +} + +pub fn unlink(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { + unsupported() +} + +pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { + match perm.0 {} +} + +pub fn rmdir(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn remove_dir_all(_path: &Path) -> io::Result<()> { + unsupported() +} + +pub fn exists(_path: &Path) -> io::Result { + unsupported() +} + +pub fn readlink(_p: &Path) -> io::Result { + unsupported() +} + +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn stat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn lstat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(_from: &Path, _to: &Path) -> io::Result { + unsupported() +} diff --git a/std/src/sys/pal/uefi/mod.rs b/std/src/sys/pal/uefi/mod.rs index f29c91f3bfe68..111bed7a7eb64 100644 --- a/std/src/sys/pal/uefi/mod.rs +++ b/std/src/sys/pal/uefi/mod.rs @@ -15,7 +15,6 @@ pub mod args; pub mod env; -#[path = "../unsupported/fs.rs"] pub mod fs; pub mod helpers; #[path = "../unsupported/io.rs"] From 4caffa9c2486336f63f1f3b39b0e26f4a6a5272d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 10 Jan 2025 22:41:48 +0100 Subject: [PATCH 275/481] Use `NonNull::without_provenance` within the standard library This API removes the need for several `unsafe` blocks, and leads to clearer code. --- alloc/src/lib.rs | 1 + alloc/src/rc.rs | 15 +++------------ alloc/src/sync.rs | 15 +++------------ core/src/alloc/layout.rs | 3 +-- std/src/io/error/repr_bitpacked.rs | 7 ++++--- std/src/lib.rs | 1 + 6 files changed, 13 insertions(+), 29 deletions(-) diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index a4c3b7dd1b1b2..b4f08debc932a 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -126,6 +126,7 @@ #![feature(local_waker)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] +#![feature(nonnull_provenance)] #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 08a7b32579868..9256cb0703a82 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -252,6 +252,7 @@ use core::intrinsics::abort; use core::iter; use core::marker::{PhantomData, Unsize}; use core::mem::{self, ManuallyDrop, align_of_val_raw}; +use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] @@ -3027,12 +3028,7 @@ impl Weak { #[rustc_const_stable(feature = "const_weak_new", since = "1.73.0")] #[must_use] pub const fn new() -> Weak { - Weak { - ptr: unsafe { - NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) - }, - alloc: Global, - } + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc: Global } } } @@ -3054,12 +3050,7 @@ impl Weak { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub fn new_in(alloc: A) -> Weak { - Weak { - ptr: unsafe { - NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) - }, - alloc, - } + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc } } } diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 30761739dbff2..11e7128e67771 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -18,6 +18,7 @@ use core::intrinsics::abort; use core::iter; use core::marker::{PhantomData, Unsize}; use core::mem::{self, ManuallyDrop, align_of_val_raw}; +use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinCoerceUnsized}; @@ -2687,12 +2688,7 @@ impl Weak { #[rustc_const_stable(feature = "const_weak_new", since = "1.73.0")] #[must_use] pub const fn new() -> Weak { - Weak { - ptr: unsafe { - NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) - }, - alloc: Global, - } + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc: Global } } } @@ -2717,12 +2713,7 @@ impl Weak { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub fn new_in(alloc: A) -> Weak { - Weak { - ptr: unsafe { - NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) - }, - alloc, - } + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc } } } diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index 21dfdd926e0af..17f4d68867e1e 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -233,8 +233,7 @@ impl Layout { #[must_use] #[inline] pub const fn dangling(&self) -> NonNull { - // SAFETY: align is guaranteed to be non-zero - unsafe { NonNull::new_unchecked(crate::ptr::without_provenance_mut::(self.align())) } + NonNull::without_provenance(self.align.as_nonzero()) } /// Creates a layout describing the record that can hold a value diff --git a/std/src/io/error/repr_bitpacked.rs b/std/src/io/error/repr_bitpacked.rs index f958a93864603..716da37168d01 100644 --- a/std/src/io/error/repr_bitpacked.rs +++ b/std/src/io/error/repr_bitpacked.rs @@ -103,7 +103,8 @@ //! the time. use core::marker::PhantomData; -use core::ptr::{self, NonNull}; +use core::num::NonZeroUsize; +use core::ptr::NonNull; use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; @@ -176,7 +177,7 @@ impl Repr { let utagged = ((code as usize) << 32) | TAG_OS; // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0. let res = Self( - unsafe { NonNull::new_unchecked(ptr::without_provenance_mut(utagged)) }, + NonNull::without_provenance(unsafe { NonZeroUsize::new_unchecked(utagged) }), PhantomData, ); // quickly smoke-check we encoded the right thing (This generally will @@ -193,7 +194,7 @@ impl Repr { let utagged = ((kind as usize) << 32) | TAG_SIMPLE; // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0. let res = Self( - unsafe { NonNull::new_unchecked(ptr::without_provenance_mut(utagged)) }, + NonNull::without_provenance(unsafe { NonZeroUsize::new_unchecked(utagged) }), PhantomData, ); // quickly smoke-check we encoded the right thing (This generally will diff --git a/std/src/lib.rs b/std/src/lib.rs index 022bbab1012dd..5c12236617c98 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -342,6 +342,7 @@ #![feature(lazy_get)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_write_slice)] +#![feature(nonnull_provenance)] #![feature(panic_can_unwind)] #![feature(panic_internals)] #![feature(pin_coerce_unsized_trait)] From 2caf93e9807fd5474f3ed47ceaec116b68aae599 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jan 2025 11:00:41 +0100 Subject: [PATCH 276/481] update and clarify StructuralPartialEq docs --- core/src/marker.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index b1e67e4e90017..4af9b666e54fe 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -190,24 +190,19 @@ pub trait Unsize { /// Required trait for constants used in pattern matches. /// -/// Any type that derives `PartialEq` automatically implements this trait, -/// *regardless* of whether its type-parameters implement `PartialEq`. -/// -/// If a `const` item contains some type that does not implement this trait, -/// then that type either (1.) does not implement `PartialEq` (which means the -/// constant will not provide that comparison method, which code generation -/// assumes is available), or (2.) it implements *its own* version of -/// `PartialEq` (which we assume does not conform to a structural-equality -/// comparison). -/// -/// In either of the two scenarios above, we reject usage of such a constant in -/// a pattern match. -/// -/// See also the [structural match RFC][RFC1445], and [issue 63438] which -/// motivated migrating from an attribute-based design to this trait. -/// -/// [RFC1445]: https://github.com/rust-lang/rfcs/blob/master/text/1445-restrict-constants-in-patterns.md -/// [issue 63438]: https://github.com/rust-lang/rust/issues/63438 +/// Constants are only allowed as patterns if (a) their type implements +/// `PartialEq`, and (b) interpreting the value of the constant as a pattern +/// is equialent to calling `PartialEq`. This ensures that constants used as +/// patterns cannot expose implementation details in an unexpected way or +/// cause semver hazards. +/// +/// This trait ensures point (b). +/// Any type that derives `PartialEq` automatically implements this trait. +/// +/// Implementing this trait (which is unstable) is a way for type authors to explicitly allow +/// comparing const values of this type; that operation will recursively compare all fields +/// (including private fields), even if that behavior differs from `PartialEq`. This can make it +/// semver-breaking to add further private fields to a type. #[unstable(feature = "structural_match", issue = "31434")] #[diagnostic::on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] #[lang = "structural_peq"] From a81076da10d02d3a8ebb52add15cf890b8303d61 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sat, 11 Jan 2025 22:18:52 +0100 Subject: [PATCH 277/481] Make UniqueRc invariant for soundness --- alloc/src/rc.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 9256cb0703a82..ae3318b839dd7 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -3708,7 +3708,11 @@ pub struct UniqueRc< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { ptr: NonNull>, - phantom: PhantomData>, + // Define the ownership of `RcInner` for drop-check + _marker: PhantomData>, + // Invariance is necessary for soundness: once other `Weak` + // references exist, we already have a form of shared mutability! + _marker2: PhantomData<*mut T>, alloc: A, } @@ -3994,7 +3998,7 @@ impl UniqueRc { }, alloc, )); - Self { ptr: ptr.into(), phantom: PhantomData, alloc } + Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } } } From b87944941c7b9b3e65b0338312fa3c652720531a Mon Sep 17 00:00:00 2001 From: ltdk Date: Sun, 18 Aug 2024 19:50:41 -0400 Subject: [PATCH 278/481] Add inherent versions of MaybeUninit methods for slices --- alloc/src/collections/btree/node.rs | 4 +- core/src/array/iter.rs | 8 +- core/src/array/mod.rs | 4 +- core/src/io/borrowed_buf.rs | 14 +- core/src/iter/adapters/filter_map.rs | 4 +- core/src/mem/maybe_uninit.rs | 564 ++++++++++++++---------- core/src/net/display_buffer.rs | 4 +- core/src/num/flt2dec/mod.rs | 48 +- core/src/num/flt2dec/strategy/dragon.rs | 10 +- core/src/num/flt2dec/strategy/grisu.rs | 10 +- core/tests/mem.rs | 32 +- proc_macro/src/bridge/arena.rs | 2 +- std/src/ffi/os_str/tests.rs | 2 +- std/src/io/buffered/bufreader/buffer.rs | 2 +- std/src/path/tests.rs | 4 +- std/src/sys/pal/windows/mod.rs | 2 +- std/src/sys/pal/windows/stdio.rs | 6 +- 17 files changed, 411 insertions(+), 309 deletions(-) diff --git a/alloc/src/collections/btree/node.rs b/alloc/src/collections/btree/node.rs index 0c93eff0d20fa..4057657632ba4 100644 --- a/alloc/src/collections/btree/node.rs +++ b/alloc/src/collections/btree/node.rs @@ -383,9 +383,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// Borrows a view into the keys stored in the node. pub fn keys(&self) -> &[K] { let leaf = self.into_leaf(); - unsafe { - MaybeUninit::slice_assume_init_ref(leaf.keys.get_unchecked(..usize::from(leaf.len))) - } + unsafe { leaf.keys.get_unchecked(..usize::from(leaf.len)).assume_init_ref() } } } diff --git a/core/src/array/iter.rs b/core/src/array/iter.rs index 9ce0eb61e0814..1edade41597f7 100644 --- a/core/src/array/iter.rs +++ b/core/src/array/iter.rs @@ -214,7 +214,7 @@ impl IntoIter { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked(self.alive.clone()); - MaybeUninit::slice_assume_init_ref(slice) + slice.assume_init_ref() } } @@ -224,7 +224,7 @@ impl IntoIter { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked_mut(self.alive.clone()); - MaybeUninit::slice_assume_init_mut(slice) + slice.assume_init_mut() } } } @@ -285,7 +285,7 @@ impl Iterator for IntoIter { // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { let slice = self.data.get_unchecked_mut(range_to_drop); - ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); + slice.assume_init_drop(); } NonZero::new(remaining).map_or(Ok(()), Err) @@ -340,7 +340,7 @@ impl DoubleEndedIterator for IntoIter { // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { let slice = self.data.get_unchecked_mut(range_to_drop); - ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); + slice.assume_init_drop(); } NonZero::new(remaining).map_or(Ok(()), Err) diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index 95c1eb460cd94..2ae5ded1fd55b 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -911,9 +911,7 @@ impl Drop for Guard<'_, T> { // SAFETY: this slice will contain only initialized objects. unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( - self.array_mut.get_unchecked_mut(..self.initialized), - )); + self.array_mut.get_unchecked_mut(..self.initialized).assume_init_drop(); } } } diff --git a/core/src/io/borrowed_buf.rs b/core/src/io/borrowed_buf.rs index 4227e503ba7ba..f86abf7f1e91c 100644 --- a/core/src/io/borrowed_buf.rs +++ b/core/src/io/borrowed_buf.rs @@ -94,7 +94,7 @@ impl<'data> BorrowedBuf<'data> { // SAFETY: We only slice the filled part of the buffer, which is always valid unsafe { let buf = self.buf.get_unchecked(..self.filled); - MaybeUninit::slice_assume_init_ref(buf) + buf.assume_init_ref() } } @@ -104,7 +104,7 @@ impl<'data> BorrowedBuf<'data> { // SAFETY: We only slice the filled part of the buffer, which is always valid unsafe { let buf = self.buf.get_unchecked_mut(..self.filled); - MaybeUninit::slice_assume_init_mut(buf) + buf.assume_init_mut() } } @@ -114,7 +114,7 @@ impl<'data> BorrowedBuf<'data> { // SAFETY: We only slice the filled part of the buffer, which is always valid unsafe { let buf = self.buf.get_unchecked(..self.filled); - MaybeUninit::slice_assume_init_ref(buf) + buf.assume_init_ref() } } @@ -124,7 +124,7 @@ impl<'data> BorrowedBuf<'data> { // SAFETY: We only slice the filled part of the buffer, which is always valid unsafe { let buf = self.buf.get_unchecked_mut(..self.filled); - MaybeUninit::slice_assume_init_mut(buf) + buf.assume_init_mut() } } @@ -233,7 +233,7 @@ impl<'a> BorrowedCursor<'a> { // SAFETY: We only slice the initialized part of the buffer, which is always valid unsafe { let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init); - MaybeUninit::slice_assume_init_ref(buf) + buf.assume_init_ref() } } @@ -243,7 +243,7 @@ impl<'a> BorrowedCursor<'a> { // SAFETY: We only slice the initialized part of the buffer, which is always valid unsafe { let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init); - MaybeUninit::slice_assume_init_mut(buf) + buf.assume_init_mut() } } @@ -344,7 +344,7 @@ impl<'a> BorrowedCursor<'a> { // SAFETY: we do not de-initialize any of the elements of the slice unsafe { - MaybeUninit::copy_from_slice(&mut self.as_mut()[..buf.len()], buf); + self.as_mut()[..buf.len()].write_copy_of_slice(buf); } // SAFETY: We just added the entire contents of buf to the filled section. diff --git a/core/src/iter/adapters/filter_map.rs b/core/src/iter/adapters/filter_map.rs index cc64ceb13f766..24ec6b1741ce1 100644 --- a/core/src/iter/adapters/filter_map.rs +++ b/core/src/iter/adapters/filter_map.rs @@ -81,9 +81,7 @@ where if const { crate::mem::needs_drop::() } { // SAFETY: self.initialized is always <= N, which also is the length of the array. unsafe { - core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( - self.array.get_unchecked_mut(..self.initialized), - )); + self.array.get_unchecked_mut(..self.initialized).assume_init_drop(); } } } diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index 284a58c7278fd..ac5307a671d20 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -1,5 +1,5 @@ use crate::any::type_name; -use crate::mem::{self, ManuallyDrop}; +use crate::mem::ManuallyDrop; use crate::{fmt, intrinsics, ptr, slice}; /// A wrapper type to construct uninitialized instances of `T`. @@ -354,7 +354,7 @@ impl MaybeUninit { /// fn read(buf: &mut [MaybeUninit]) -> &[u8] { /// unsafe { /// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); - /// MaybeUninit::slice_assume_init_ref(&buf[..len]) + /// buf[..len].assume_init_ref() /// } /// } /// @@ -740,7 +740,7 @@ impl MaybeUninit { /// /// On top of that, all additional invariants of the type `T` must be /// satisfied, as the `Drop` implementation of `T` (or its members) may - /// rely on this. For example, setting a [`Vec`] to an invalid but + /// rely on this. For example, setting a `Vec` to an invalid but /// non-null address makes it initialized (under the current implementation; /// this does not constitute a stable guarantee), because the only /// requirement the compiler knows about it is that the data pointer must be @@ -748,7 +748,6 @@ impl MaybeUninit { /// behavior. /// /// [`assume_init`]: MaybeUninit::assume_init - /// [`Vec`]: ../../std/vec/struct.Vec.html #[stable(feature = "maybe_uninit_extra", since = "1.60.0")] pub unsafe fn assume_init_drop(&mut self) { // SAFETY: the caller must guarantee that `self` is initialized and @@ -982,44 +981,87 @@ impl MaybeUninit { } } - /// Assuming all the elements are initialized, get a slice to them. + /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. /// - /// # Safety + /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still + /// contain padding bytes which are left uninitialized. /// - /// It is up to the caller to guarantee that the `MaybeUninit` elements - /// really are in an initialized state. - /// Calling this when the content is not yet fully initialized causes undefined behavior. + /// # Examples /// - /// See [`assume_init_ref`] for more details and examples. + /// ``` + /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// use std::mem::MaybeUninit; /// - /// [`assume_init_ref`]: MaybeUninit::assume_init_ref - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[inline(always)] - pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { - // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that - // `slice` is initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`. - // The pointer obtained is valid since it refers to memory owned by `slice` which is a - // reference and thus guaranteed to be valid for reads. - unsafe { &*(slice as *const [Self] as *const [T]) } + /// let val = 0x12345678_i32; + /// let uninit = MaybeUninit::new(val); + /// let uninit_bytes = uninit.as_bytes(); + /// let bytes = unsafe { uninit_bytes.assume_init_ref() }; + /// assert_eq!(bytes, val.to_ne_bytes()); + /// ``` + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + pub const fn as_bytes(&self) -> &[MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { + slice::from_raw_parts(self.as_ptr().cast::>(), super::size_of::()) + } } - /// Assuming all the elements are initialized, get a mutable slice to them. + /// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized + /// bytes. /// - /// # Safety + /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still + /// contain padding bytes which are left uninitialized. /// - /// It is up to the caller to guarantee that the `MaybeUninit` elements - /// really are in an initialized state. - /// Calling this when the content is not yet fully initialized causes undefined behavior. + /// # Examples /// - /// See [`assume_init_mut`] for more details and examples. + /// ``` + /// #![feature(maybe_uninit_as_bytes)] + /// use std::mem::MaybeUninit; /// - /// [`assume_init_mut`]: MaybeUninit::assume_init_mut + /// let val = 0x12345678_i32; + /// let mut uninit = MaybeUninit::new(val); + /// let uninit_bytes = uninit.as_bytes_mut(); + /// if cfg!(target_endian = "little") { + /// uninit_bytes[0].write(0xcd); + /// } else { + /// uninit_bytes[3].write(0xcd); + /// } + /// let val2 = unsafe { uninit.assume_init() }; + /// assert_eq!(val2, 0x123456cd); + /// ``` + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { + slice::from_raw_parts_mut( + self.as_mut_ptr().cast::>(), + super::size_of::(), + ) + } + } + + /// Deprecated version of [`slice::assume_init_ref`]. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[inline(always)] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[deprecated( + note = "replaced by inherent assume_init_ref method; will eventually be removed", + since = "1.83.0" + )] + pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { + // SAFETY: Same for both methods. + unsafe { slice.assume_init_ref() } + } + + /// Deprecated version of [`slice::assume_init_mut`]. + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[deprecated( + note = "replaced by inherent assume_init_mut method; will eventually be removed", + since = "1.83.0" + )] pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { - // SAFETY: similar to safety notes for `slice_get_ref`, but we have a - // mutable reference which is also guaranteed to be valid for writes. - unsafe { &mut *(slice as *mut [Self] as *mut [T]) } + // SAFETY: Same for both methods. + unsafe { slice.assume_init_mut() } } /// Gets a pointer to the first element of the array. @@ -1036,142 +1078,34 @@ impl MaybeUninit { this.as_mut_ptr() as *mut T } - /// Copies the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. - /// - /// If `T` does not implement `Copy`, use [`clone_from_slice`] - /// - /// This is similar to [`slice::copy_from_slice`]. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Examples - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut dst = [MaybeUninit::uninit(); 32]; - /// let src = [0; 32]; - /// - /// let init = MaybeUninit::copy_from_slice(&mut dst, &src); - /// - /// assert_eq!(init, src); - /// ``` - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut vec = Vec::with_capacity(32); - /// let src = [0; 16]; - /// - /// MaybeUninit::copy_from_slice(&mut vec.spare_capacity_mut()[..src.len()], &src); - /// - /// // SAFETY: we have just copied all the elements of len into the spare capacity - /// // the first src.len() elements of the vec are valid now. - /// unsafe { - /// vec.set_len(src.len()); - /// } - /// - /// assert_eq!(vec, src); - /// ``` - /// - /// [`clone_from_slice`]: MaybeUninit::clone_from_slice + /// Deprecated version of [`slice::write_copy_of_slice`]. #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + #[deprecated( + note = "replaced by inherent write_copy_of_slice method; will eventually be removed", + since = "1.83.0" + )] pub fn copy_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] where T: Copy, { - // SAFETY: &[T] and &[MaybeUninit] have the same layout - let uninit_src: &[MaybeUninit] = unsafe { super::transmute(src) }; - - this.copy_from_slice(uninit_src); - - // SAFETY: Valid elements have just been copied into `this` so it is initialized - unsafe { MaybeUninit::slice_assume_init_mut(this) } + this.write_copy_of_slice(src) } - /// Clones the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. - /// Any already initialized elements will not be dropped. - /// - /// If `T` implements `Copy`, use [`copy_from_slice`] - /// - /// This is similar to [`slice::clone_from_slice`] but does not drop existing elements. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics. - /// - /// If there is a panic, the already cloned elements will be dropped. - /// - /// # Examples - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; - /// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()]; - /// - /// let init = MaybeUninit::clone_from_slice(&mut dst, &src); - /// - /// assert_eq!(init, src); - /// # // Prevent leaks for Miri - /// # unsafe { std::ptr::drop_in_place(init); } - /// ``` - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut vec = Vec::with_capacity(32); - /// let src = ["rust", "is", "a", "pretty", "cool", "language"]; - /// - /// MaybeUninit::clone_from_slice(&mut vec.spare_capacity_mut()[..src.len()], &src); - /// - /// // SAFETY: we have just cloned all the elements of len into the spare capacity - /// // the first src.len() elements of the vec are valid now. - /// unsafe { - /// vec.set_len(src.len()); - /// } - /// - /// assert_eq!(vec, src); - /// ``` - /// - /// [`copy_from_slice`]: MaybeUninit::copy_from_slice + /// Deprecated version of [`slice::write_clone_of_slice`]. #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + #[deprecated( + note = "replaced by inherent write_clone_of_slice method; will eventually be removed", + since = "1.83.0" + )] pub fn clone_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] where T: Clone, { - // unlike copy_from_slice this does not call clone_from_slice on the slice - // this is because `MaybeUninit` does not implement Clone. - - assert_eq!(this.len(), src.len(), "destination and source slices have different lengths"); - // NOTE: We need to explicitly slice them to the same length - // for bounds checking to be elided, and the optimizer will - // generate memcpy for simple cases (for example T = u8). - let len = this.len(); - let src = &src[..len]; - - // guard is needed b/c panic might happen during a clone - let mut guard = Guard { slice: this, initialized: 0 }; - - for i in 0..len { - guard.slice[i].write(src[i].clone()); - guard.initialized += 1; - } - - super::forget(guard); - - // SAFETY: Valid elements have just been written into `this` so it is initialized - unsafe { MaybeUninit::slice_assume_init_mut(this) } + this.write_clone_of_slice(src) } - /// Fills `this` with elements by cloning `value`, returning a mutable reference to the now - /// initialized contents of `this`. + /// Fills a slice with elements by cloning `value`, returning a mutable reference to the now + /// initialized contents of the slice. /// Any previously initialized elements will not be dropped. /// /// This is similar to [`slice::fill`]. @@ -1185,27 +1119,26 @@ impl MaybeUninit { /// /// # Examples /// - /// Fill an uninit vec with 1. /// ``` /// #![feature(maybe_uninit_fill)] /// use std::mem::MaybeUninit; /// - /// let mut buf = vec![MaybeUninit::uninit(); 10]; - /// let initialized = MaybeUninit::fill(buf.as_mut_slice(), 1); + /// let mut buf = [const { MaybeUninit::uninit() }; 10]; + /// let initialized = MaybeUninit::fill(&mut buf, 1); /// assert_eq!(initialized, &mut [1; 10]); /// ``` #[doc(alias = "memset")] #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] + pub fn fill(this: &mut [MaybeUninit], value: T) -> &mut [T] where T: Clone, { SpecFill::spec_fill(this, value); // SAFETY: Valid elements have just been filled into `this` so it is initialized - unsafe { MaybeUninit::slice_assume_init_mut(this) } + unsafe { this.assume_init_mut() } } - /// Fills `this` with elements returned by calling a closure repeatedly. + /// Fills a slice with elements returned by calling a closure repeatedly. /// /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can @@ -1220,17 +1153,16 @@ impl MaybeUninit { /// /// # Examples /// - /// Fill an uninit vec with the default value. /// ``` /// #![feature(maybe_uninit_fill)] /// use std::mem::MaybeUninit; /// - /// let mut buf = vec![MaybeUninit::::uninit(); 10]; - /// let initialized = MaybeUninit::fill_with(buf.as_mut_slice(), Default::default); + /// let mut buf = [const { MaybeUninit::::uninit() }; 10]; + /// let initialized = MaybeUninit::fill_with(&mut buf, Default::default); /// assert_eq!(initialized, &mut [0; 10]); /// ``` #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] + pub fn fill_with(this: &mut [MaybeUninit], mut f: F) -> &mut [T] where F: FnMut() -> T, { @@ -1244,13 +1176,13 @@ impl MaybeUninit { super::forget(guard); // SAFETY: Valid elements have just been written into `this` so it is initialized - unsafe { MaybeUninit::slice_assume_init_mut(this) } + unsafe { this.assume_init_mut() } } - /// Fills `this` with elements yielded by an iterator until either all elements have been + /// Fills a slice with elements yielded by an iterator until either all elements have been /// initialized or the iterator is empty. /// - /// Returns two slices. The first slice contains the initialized portion of the original slice. + /// Returns two slices. The first slice contains the initialized portion of the original slice. /// The second slice is the still-uninitialized remainder of the original slice. /// /// # Panics @@ -1262,37 +1194,51 @@ impl MaybeUninit { /// /// # Examples /// - /// Fill an uninit vec with a cycling iterator. + /// Completely filling the slice: + /// /// ``` /// #![feature(maybe_uninit_fill)] /// use std::mem::MaybeUninit; /// - /// let mut buf = vec![MaybeUninit::uninit(); 5]; + /// let mut buf = [const { MaybeUninit::uninit() }; 5]; /// /// let iter = [1, 2, 3].into_iter().cycle(); /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); /// /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]); - /// assert_eq!(0, remainder.len()); + /// assert_eq!(remainder.len(), 0); /// ``` /// - /// Fill an uninit vec, but not completely. + /// Partially filling the slice: + /// /// ``` /// #![feature(maybe_uninit_fill)] /// use std::mem::MaybeUninit; /// - /// let mut buf = vec![MaybeUninit::uninit(); 5]; + /// let mut buf = [const { MaybeUninit::uninit() }; 5]; /// let iter = [1, 2]; /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); /// /// assert_eq!(initialized, &mut [1, 2]); /// assert_eq!(remainder.len(), 3); /// ``` + /// + /// Checking an iterator after filling a slice: + /// + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = [const { MaybeUninit::uninit() }; 3]; + /// let mut iter = [1, 2, 3, 4, 5].into_iter(); + /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter.by_ref()); + /// + /// assert_eq!(initialized, &mut [1, 2, 3]); + /// assert_eq!(remainder.len(), 0); + /// assert_eq!(iter.as_slice(), &[4, 5]); + /// ``` #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - pub fn fill_from<'a, I>( - this: &'a mut [MaybeUninit], - it: I, - ) -> (&'a mut [T], &'a mut [MaybeUninit]) + pub fn fill_from(this: &mut [MaybeUninit], it: I) -> (&mut [T], &mut [MaybeUninit]) where I: IntoIterator, { @@ -1312,70 +1258,169 @@ impl MaybeUninit { // SAFETY: Valid elements have just been written into `init`, so that portion // of `this` is initialized. - (unsafe { MaybeUninit::slice_assume_init_mut(initted) }, remainder) + (unsafe { initted.assume_init_mut() }, remainder) } - /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. + /// Deprecated version of [`slice::as_bytes`]. + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + #[deprecated( + note = "replaced by inherent as_bytes method; will eventually be removed", + since = "1.83.0" + )] + pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { + this.as_bytes() + } + + /// Deprecated version of [`slice::as_bytes_mut`]. + #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] + #[deprecated( + note = "replaced by inherent as_bytes_mut method; will eventually be removed", + since = "1.83.0" + )] + pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { + this.as_bytes_mut() + } +} + +impl [MaybeUninit] { + /// Copies the elements from `src` to `self`, + /// returning a mutable reference to the now initialized contents of `self`. /// - /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still - /// contain padding bytes which are left uninitialized. + /// If `T` does not implement `Copy`, use [`write_clone_of_slice`] instead. + /// + /// This is similar to [`slice::copy_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. /// /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)] + /// #![feature(maybe_uninit_write_slice)] /// use std::mem::MaybeUninit; /// - /// let val = 0x12345678_i32; - /// let uninit = MaybeUninit::new(val); - /// let uninit_bytes = uninit.as_bytes(); - /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) }; - /// assert_eq!(bytes, val.to_ne_bytes()); + /// let mut dst = [MaybeUninit::uninit(); 32]; + /// let src = [0; 32]; + /// + /// let init = dst.write_copy_of_slice(&src); + /// + /// assert_eq!(init, src); /// ``` - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - pub fn as_bytes(&self) -> &[MaybeUninit] { - // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { - slice::from_raw_parts(self.as_ptr() as *const MaybeUninit, mem::size_of::()) - } + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// + /// let mut vec = Vec::with_capacity(32); + /// let src = [0; 16]; + /// + /// vec.spare_capacity_mut()[..src.len()].write_copy_of_slice(&src); + /// + /// // SAFETY: we have just copied all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + /// + /// [`write_clone_of_slice`]: slice::write_clone_of_slice + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + #[rustc_const_unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub const fn write_copy_of_slice(&mut self, src: &[T]) -> &mut [T] + where + T: Copy, + { + // SAFETY: &[T] and &[MaybeUninit] have the same layout + let uninit_src: &[MaybeUninit] = unsafe { super::transmute(src) }; + + self.copy_from_slice(uninit_src); + + // SAFETY: Valid elements have just been copied into `self` so it is initialized + unsafe { self.assume_init_mut() } } - /// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized - /// bytes. + /// Clones the elements from `src` to `self`, + /// returning a mutable reference to the now initialized contents of `self`. + /// Any already initialized elements will not be dropped. /// - /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still - /// contain padding bytes which are left uninitialized. + /// If `T` implements `Copy`, use [`write_copy_of_slice`] instead. + /// + /// This is similar to [`slice::clone_from_slice`] but does not drop existing elements. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics. + /// + /// If there is a panic, the already cloned elements will be dropped. /// /// # Examples /// /// ``` - /// #![feature(maybe_uninit_as_bytes)] + /// #![feature(maybe_uninit_write_slice)] /// use std::mem::MaybeUninit; /// - /// let val = 0x12345678_i32; - /// let mut uninit = MaybeUninit::new(val); - /// let uninit_bytes = uninit.as_bytes_mut(); - /// if cfg!(target_endian = "little") { - /// uninit_bytes[0].write(0xcd); - /// } else { - /// uninit_bytes[3].write(0xcd); + /// let mut dst = [const { MaybeUninit::uninit() }; 5]; + /// let src = ["wibbly", "wobbly", "timey", "wimey", "stuff"].map(|s| s.to_string()); + /// + /// let init = dst.write_clone_of_slice(&src); + /// + /// assert_eq!(init, src); + /// + /// # // Prevent leaks for Miri + /// # unsafe { std::ptr::drop_in_place(init); } + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// + /// let mut vec = Vec::with_capacity(32); + /// let src = ["rust", "is", "a", "pretty", "cool", "language"].map(|s| s.to_string()); + /// + /// vec.spare_capacity_mut()[..src.len()].write_clone_of_slice(&src); + /// + /// // SAFETY: we have just cloned all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); /// } - /// let val2 = unsafe { uninit.assume_init() }; - /// assert_eq!(val2, 0x123456cd); + /// + /// assert_eq!(vec, src); /// ``` - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { - // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { - slice::from_raw_parts_mut( - self.as_mut_ptr() as *mut MaybeUninit, - mem::size_of::(), - ) + /// + /// [`write_copy_of_slice`]: slice::write_copy_of_slice + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_clone_of_slice(&mut self, src: &[T]) -> &mut [T] + where + T: Clone, + { + // unlike copy_from_slice this does not call clone_from_slice on the slice + // this is because `MaybeUninit` does not implement Clone. + + assert_eq!(self.len(), src.len(), "destination and source slices have different lengths"); + + // NOTE: We need to explicitly slice them to the same length + // for bounds checking to be elided, and the optimizer will + // generate memcpy for simple cases (for example T = u8). + let len = self.len(); + let src = &src[..len]; + + // guard is needed b/c panic might happen during a clone + let mut guard = Guard { slice: self, initialized: 0 }; + + for i in 0..len { + guard.slice[i].write(src[i].clone()); + guard.initialized += 1; } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `self` so it is initialized + unsafe { self.assume_init_mut() } } - /// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized - /// bytes. + /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. /// /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still /// contain padding bytes which are left uninitialized. @@ -1387,21 +1432,22 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)]; - /// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit); - /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) }; + /// let uninit_bytes = uninit.as_bytes(); + /// let bytes = unsafe { uninit_bytes.assume_init_ref() }; /// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap()); /// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap()); /// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]); /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { - let bytes = mem::size_of_val(this); + pub const fn as_bytes(&self) -> &[MaybeUninit] { // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { slice::from_raw_parts(this.as_ptr() as *const MaybeUninit, bytes) } + unsafe { + slice::from_raw_parts(self.as_ptr().cast::>(), super::size_of_val(self)) + } } - /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of - /// potentially uninitialized bytes. + /// Returns the contents of this `MaybeUninit` slice as a mutable slice of potentially + /// uninitialized bytes. /// /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still /// contain padding bytes which are left uninitialized. @@ -1414,8 +1460,8 @@ impl MaybeUninit { /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit); - /// MaybeUninit::copy_from_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]); - /// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) }; + /// uninit_bytes.write_copy_of_slice(&[0x12, 0x34, 0x56, 0x78]); + /// let vals = unsafe { uninit.assume_init_ref() }; /// if cfg!(target_endian = "little") { /// assert_eq!(vals, &[0x3412u16, 0x7856u16]); /// } else { @@ -1423,10 +1469,74 @@ impl MaybeUninit { /// } /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { - let bytes = mem::size_of_val(this); + pub const fn as_bytes_mut(&mut self) -> &mut [MaybeUninit] { // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { slice::from_raw_parts_mut(this.as_mut_ptr() as *mut MaybeUninit, bytes) } + unsafe { + slice::from_raw_parts_mut( + self.as_mut_ptr() as *mut MaybeUninit, + super::size_of_val(self), + ) + } + } + + /// Drops the contained values in place. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that every `MaybeUninit` in the slice + /// really is in an initialized state. Calling this when the content is not yet + /// fully initialized causes undefined behavior. + /// + /// On top of that, all additional invariants of the type `T` must be + /// satisfied, as the `Drop` implementation of `T` (or its members) may + /// rely on this. For example, setting a `Vec` to an invalid but + /// non-null address makes it initialized (under the current implementation; + /// this does not constitute a stable guarantee), because the only + /// requirement the compiler knows about it is that the data pointer must be + /// non-null. Dropping such a `Vec` however will cause undefined + /// behaviour. + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[inline(always)] + pub unsafe fn assume_init_drop(&mut self) { + if !self.is_empty() { + // SAFETY: the caller must guarantee that every element of `self` + // is initialized and satisfies all invariants of `T`. + // Dropping the value in place is safe if that is the case. + unsafe { ptr::drop_in_place(self as *mut [MaybeUninit] as *mut [T]) } + } + } + + /// Gets a shared reference to the contained value. + /// + /// # Safety + /// + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in + /// the slice really is in an initialized state. + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[inline(always)] + pub const unsafe fn assume_init_ref(&self) -> &[T] { + // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that + // `slice` is initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`. + // The pointer obtained is valid since it refers to memory owned by `slice` which is a + // reference and thus guaranteed to be valid for reads. + unsafe { &*(self as *const Self as *const [T]) } + } + + /// Gets a mutable (unique) reference to the contained value. + /// + /// # Safety + /// + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that every `MaybeUninit` in the + /// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot + /// be used to initialize a `MaybeUninit` slice. + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[inline(always)] + pub const unsafe fn assume_init_mut(&mut self) -> &mut [T] { + // SAFETY: similar to safety notes for `slice_get_ref`, but we have a + // mutable reference which is also guaranteed to be valid for writes. + unsafe { &mut *(self as *mut Self as *mut [T]) } } } @@ -1479,7 +1589,7 @@ impl<'a, T> Drop for Guard<'a, T> { let initialized_part = &mut self.slice[..self.initialized]; // SAFETY: this raw sub-slice will contain only initialized objects. unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); + initialized_part.assume_init_drop(); } } } diff --git a/core/src/net/display_buffer.rs b/core/src/net/display_buffer.rs index bab84a97308b3..a7d12217081f6 100644 --- a/core/src/net/display_buffer.rs +++ b/core/src/net/display_buffer.rs @@ -18,7 +18,7 @@ impl DisplayBuffer { // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation // which writes a valid UTF-8 string to `buf` and correctly sets `len`. unsafe { - let s = MaybeUninit::slice_assume_init_ref(&self.buf[..self.len]); + let s = self.buf[..self.len].assume_init_ref(); str::from_utf8_unchecked(s) } } @@ -29,7 +29,7 @@ impl fmt::Write for DisplayBuffer { let bytes = s.as_bytes(); if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) { - MaybeUninit::copy_from_slice(buf, bytes); + buf.write_copy_of_slice(bytes); self.len += bytes.len(); Ok(()) } else { diff --git a/core/src/num/flt2dec/mod.rs b/core/src/num/flt2dec/mod.rs index d6413fadc3381..7601e3e2c58a2 100644 --- a/core/src/num/flt2dec/mod.rs +++ b/core/src/num/flt2dec/mod.rs @@ -210,10 +210,10 @@ fn digits_to_dec_str<'a>( if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp { parts[3] = MaybeUninit::new(Part::Zero((frac_digits - buf.len()) - minus_exp)); // SAFETY: we just initialized the elements `..4`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } + unsafe { parts[..4].assume_init_ref() } } else { // SAFETY: we just initialized the elements `..3`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) } + unsafe { parts[..3].assume_init_ref() } } } else { let exp = exp as usize; @@ -225,10 +225,10 @@ fn digits_to_dec_str<'a>( if frac_digits > buf.len() - exp { parts[3] = MaybeUninit::new(Part::Zero(frac_digits - (buf.len() - exp))); // SAFETY: we just initialized the elements `..4`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } + unsafe { parts[..4].assume_init_ref() } } else { // SAFETY: we just initialized the elements `..3`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) } + unsafe { parts[..3].assume_init_ref() } } } else { // the decimal point is after rendered digits: [1234][____0000] or [1234][__][.][__]. @@ -238,10 +238,10 @@ fn digits_to_dec_str<'a>( parts[2] = MaybeUninit::new(Part::Copy(b".")); parts[3] = MaybeUninit::new(Part::Zero(frac_digits)); // SAFETY: we just initialized the elements `..4`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } + unsafe { parts[..4].assume_init_ref() } } else { // SAFETY: we just initialized the elements `..2`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) } + unsafe { parts[..2].assume_init_ref() } } } } @@ -292,7 +292,7 @@ fn digits_to_exp_str<'a>( parts[n + 1] = MaybeUninit::new(Part::Num(exp as u16)); } // SAFETY: we just initialized the elements `..n + 2`. - unsafe { MaybeUninit::slice_assume_init_ref(&parts[..n + 2]) } + unsafe { parts[..n + 2].assume_init_ref() } } /// Sign formatting options. @@ -366,12 +366,12 @@ where FullDecoded::Nan => { parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Infinite => { parts[0] = MaybeUninit::new(Part::Copy(b"inf")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Zero => { if frac_digits > 0 { @@ -381,14 +381,14 @@ where Formatted { sign, // SAFETY: we just initialized the elements `..2`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + parts: unsafe { parts[..2].assume_init_ref() }, } } else { parts[0] = MaybeUninit::new(Part::Copy(b"0")); Formatted { sign, // SAFETY: we just initialized the elements `..1`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + parts: unsafe { parts[..1].assume_init_ref() }, } } } @@ -442,12 +442,12 @@ where FullDecoded::Nan => { parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Infinite => { parts[0] = MaybeUninit::new(Part::Copy(b"inf")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Zero => { parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 { @@ -456,7 +456,7 @@ where MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" })) }; // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Finite(ref decoded) => { let (buf, exp) = format_shortest(decoded, buf); @@ -533,12 +533,12 @@ where FullDecoded::Nan => { parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Infinite => { parts[0] = MaybeUninit::new(Part::Copy(b"inf")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Zero => { if ndigits > 1 { @@ -549,14 +549,14 @@ where Formatted { sign, // SAFETY: we just initialized the elements `..3`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) }, + parts: unsafe { parts[..3].assume_init_ref() }, } } else { parts[0] = MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" })); Formatted { sign, // SAFETY: we just initialized the elements `..1`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + parts: unsafe { parts[..1].assume_init_ref() }, } } } @@ -607,12 +607,12 @@ where FullDecoded::Nan => { parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Infinite => { parts[0] = MaybeUninit::new(Part::Copy(b"inf")); // SAFETY: we just initialized the elements `..1`. - Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } + Formatted { sign, parts: unsafe { parts[..1].assume_init_ref() } } } FullDecoded::Zero => { if frac_digits > 0 { @@ -622,14 +622,14 @@ where Formatted { sign, // SAFETY: we just initialized the elements `..2`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + parts: unsafe { parts[..2].assume_init_ref() }, } } else { parts[0] = MaybeUninit::new(Part::Copy(b"0")); Formatted { sign, // SAFETY: we just initialized the elements `..1`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + parts: unsafe { parts[..1].assume_init_ref() }, } } } @@ -654,14 +654,14 @@ where Formatted { sign, // SAFETY: we just initialized the elements `..2`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + parts: unsafe { parts[..2].assume_init_ref() }, } } else { parts[0] = MaybeUninit::new(Part::Copy(b"0")); Formatted { sign, // SAFETY: we just initialized the elements `..1`. - parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + parts: unsafe { parts[..1].assume_init_ref() }, } } } else { diff --git a/core/src/num/flt2dec/strategy/dragon.rs b/core/src/num/flt2dec/strategy/dragon.rs index e801f07b3bc0e..dd73e4b4846d5 100644 --- a/core/src/num/flt2dec/strategy/dragon.rs +++ b/core/src/num/flt2dec/strategy/dragon.rs @@ -247,7 +247,7 @@ pub fn format_shortest<'a>( // it seems that this condition is very hard to satisfy (possibly impossible), // but we are just being safe and consistent here. // SAFETY: we initialized that memory above. - if let Some(c) = round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }) { + if let Some(c) = round_up(unsafe { buf[..i].assume_init_mut() }) { buf[i] = MaybeUninit::new(c); i += 1; k += 1; @@ -255,7 +255,7 @@ pub fn format_shortest<'a>( } // SAFETY: we initialized that memory above. - (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..i]) }, k) + (unsafe { buf[..i].assume_init_ref() }, k) } /// The exact and fixed mode implementation for Dragon. @@ -333,7 +333,7 @@ pub fn format_exact<'a>( *c = MaybeUninit::new(b'0'); } // SAFETY: we initialized that memory above. - return (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, k); + return (unsafe { buf[..len].assume_init_ref() }, k); } let mut d = 0; @@ -372,7 +372,7 @@ pub fn format_exact<'a>( // if rounding up changes the length, the exponent should also change. // but we've been requested a fixed number of digits, so do not alter the buffer... // SAFETY: we initialized that memory above. - if let Some(c) = round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..len]) }) { + if let Some(c) = round_up(unsafe { buf[..len].assume_init_mut() }) { // ...unless we've been requested the fixed precision instead. // we also need to check that, if the original buffer was empty, // the additional digit can only be added when `k == limit` (edge case). @@ -385,5 +385,5 @@ pub fn format_exact<'a>( } // SAFETY: we initialized that memory above. - (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, k) + (unsafe { buf[..len].assume_init_ref() }, k) } diff --git a/core/src/num/flt2dec/strategy/grisu.rs b/core/src/num/flt2dec/strategy/grisu.rs index bdf544a4133bb..2816de4c63339 100644 --- a/core/src/num/flt2dec/strategy/grisu.rs +++ b/core/src/num/flt2dec/strategy/grisu.rs @@ -275,7 +275,7 @@ pub fn format_shortest_opt<'a>( let ten_kappa = (ten_kappa as u64) << e; // scale 10^kappa back to the shared exponent return round_and_weed( // SAFETY: we initialized that memory above. - unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }, + unsafe { buf[..i].assume_init_mut() }, exp, plus1rem, delta1, @@ -324,7 +324,7 @@ pub fn format_shortest_opt<'a>( let ten_kappa = 1 << e; // implicit divisor return round_and_weed( // SAFETY: we initialized that memory above. - unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }, + unsafe { buf[..i].assume_init_mut() }, exp, r, threshold, @@ -713,7 +713,7 @@ pub fn format_exact_opt<'a>( // `10^kappa` did not overflow after all, the second check is fine. if ten_kappa - remainder > remainder && ten_kappa - 2 * remainder >= 2 * ulp { // SAFETY: our caller initialized that memory. - return Some((unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, exp)); + return Some((unsafe { buf[..len].assume_init_ref() }, exp)); } // :<------- remainder ------>| : @@ -736,7 +736,7 @@ pub fn format_exact_opt<'a>( if remainder > ulp && ten_kappa - (remainder - ulp) <= remainder - ulp { if let Some(c) = // SAFETY: our caller must have initialized that memory. - round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..len]) }) + round_up(unsafe { buf[..len].assume_init_mut() }) { // only add an additional digit when we've been requested the fixed precision. // we also need to check that, if the original buffer was empty, @@ -748,7 +748,7 @@ pub fn format_exact_opt<'a>( } } // SAFETY: we and our caller initialized that memory. - return Some((unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, exp)); + return Some((unsafe { buf[..len].assume_init_ref() }, exp)); } // otherwise we are doomed (i.e., some values between `v - 1 ulp` and `v + 1 ulp` are diff --git a/core/tests/mem.rs b/core/tests/mem.rs index f3b4387f6a898..1b5c5fc82a69d 100644 --- a/core/tests/mem.rs +++ b/core/tests/mem.rs @@ -200,60 +200,60 @@ fn uninit_array_assume_init() { } #[test] -fn uninit_write_slice() { +fn uninit_write_copy_of_slice() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 64]; - assert_eq!(MaybeUninit::copy_from_slice(&mut dst, &src), &src); + assert_eq!(dst.write_copy_of_slice(&src), &src); } #[test] #[should_panic(expected = "source slice length (32) does not match destination slice length (64)")] -fn uninit_write_slice_panic_lt() { +fn uninit_write_copy_of_slice_panic_lt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 32]; - MaybeUninit::copy_from_slice(&mut dst, &src); + dst.write_copy_of_slice(&src); } #[test] #[should_panic(expected = "source slice length (128) does not match destination slice length (64)")] -fn uninit_write_slice_panic_gt() { +fn uninit_write_copy_of_slice_panic_gt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 128]; - MaybeUninit::copy_from_slice(&mut dst, &src); + dst.write_copy_of_slice(&src); } #[test] -fn uninit_clone_from_slice() { +fn uninit_write_clone_of_slice() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 64]; - assert_eq!(MaybeUninit::clone_from_slice(&mut dst, &src), &src); + assert_eq!(dst.write_clone_of_slice(&src), &src); } #[test] #[should_panic(expected = "destination and source slices have different lengths")] -fn uninit_write_slice_cloned_panic_lt() { +fn uninit_write_clone_of_slice_panic_lt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 32]; - MaybeUninit::clone_from_slice(&mut dst, &src); + dst.write_clone_of_slice(&src); } #[test] #[should_panic(expected = "destination and source slices have different lengths")] -fn uninit_write_slice_cloned_panic_gt() { +fn uninit_write_clone_of_slice_panic_gt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 128]; - MaybeUninit::clone_from_slice(&mut dst, &src); + dst.write_clone_of_slice(&src); } #[test] #[cfg(panic = "unwind")] -fn uninit_write_slice_cloned_mid_panic() { +fn uninit_write_clone_of_slice_mid_panic() { use std::panic; enum IncrementOrPanic { @@ -289,7 +289,7 @@ fn uninit_write_slice_cloned_mid_panic() { ]; let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::clone_from_slice(&mut dst, &src); + dst.write_clone_of_slice(&src); })); drop(src); @@ -317,11 +317,11 @@ impl Drop for Bomb { } #[test] -fn uninit_write_slice_cloned_no_drop() { +fn uninit_write_clone_of_slice_no_drop() { let mut dst = [MaybeUninit::uninit()]; let src = [Bomb]; - MaybeUninit::clone_from_slice(&mut dst, &src); + dst.write_clone_of_slice(&src); forget(src); } diff --git a/proc_macro/src/bridge/arena.rs b/proc_macro/src/bridge/arena.rs index 1d5986093c8a4..29636e793f614 100644 --- a/proc_macro/src/bridge/arena.rs +++ b/proc_macro/src/bridge/arena.rs @@ -102,7 +102,7 @@ impl Arena { #[allow(clippy::mut_from_ref)] // arena allocator pub(crate) fn alloc_str<'a>(&'a self, string: &str) -> &'a mut str { let alloc = self.alloc_raw(string.len()); - let bytes = MaybeUninit::copy_from_slice(alloc, string.as_bytes()); + let bytes = alloc.write_copy_of_slice(string.as_bytes()); // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, // and immediately convert the clone back to `&str`. diff --git a/std/src/ffi/os_str/tests.rs b/std/src/ffi/os_str/tests.rs index cbec44c862646..2572b71fd9ac6 100644 --- a/std/src/ffi/os_str/tests.rs +++ b/std/src/ffi/os_str/tests.rs @@ -295,7 +295,7 @@ fn clone_to_uninit() { let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; - assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) }); + assert_eq!(a.as_encoded_bytes(), unsafe { storage.assume_init_ref() }); let mut b: Box = OsStr::new("world.exe").into(); assert_eq!(size_of_val::(a), size_of_val::(&b)); diff --git a/std/src/io/buffered/bufreader/buffer.rs b/std/src/io/buffered/bufreader/buffer.rs index 17721090db5de..5251cc302cb49 100644 --- a/std/src/io/buffered/bufreader/buffer.rs +++ b/std/src/io/buffered/bufreader/buffer.rs @@ -50,7 +50,7 @@ impl Buffer { pub fn buffer(&self) -> &[u8] { // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and // that region is initialized because those are all invariants of this type. - unsafe { MaybeUninit::slice_assume_init_ref(self.buf.get_unchecked(self.pos..self.filled)) } + unsafe { self.buf.get_unchecked(self.pos..self.filled).assume_init_ref() } } #[inline] diff --git a/std/src/path/tests.rs b/std/src/path/tests.rs index ff3f7151bb834..3f96ac4672aff 100644 --- a/std/src/path/tests.rs +++ b/std/src/path/tests.rs @@ -2069,9 +2069,7 @@ fn clone_to_uninit() { let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; - assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe { - MaybeUninit::slice_assume_init_ref(&storage) - }); + assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe { storage.assume_init_ref() }); let mut b: Box = Path::new("world.exe").into(); assert_eq!(size_of_val::(a), size_of_val::(&b)); diff --git a/std/src/sys/pal/windows/mod.rs b/std/src/sys/pal/windows/mod.rs index 88e6def7a7577..4282dbb54934f 100644 --- a/std/src/sys/pal/windows/mod.rs +++ b/std/src/sys/pal/windows/mod.rs @@ -272,7 +272,7 @@ where unreachable!(); } else { // Safety: First `k` values are initialized. - let slice: &[u16] = MaybeUninit::slice_assume_init_ref(&buf[..k]); + let slice: &[u16] = buf[..k].assume_init_ref(); return Ok(f2(slice)); } } diff --git a/std/src/sys/pal/windows/stdio.rs b/std/src/sys/pal/windows/stdio.rs index 1b735e7f0cb2e..fd3f559ba1901 100644 --- a/std/src/sys/pal/windows/stdio.rs +++ b/std/src/sys/pal/windows/stdio.rs @@ -207,7 +207,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result return Ok(bytes_copied + value), Err(e) => return Err(e), From d9388a842bd1bdcceb5435c7f32c3659c30fa0cb Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 11 Jan 2025 18:00:44 -0500 Subject: [PATCH 279/481] Add #[inline] to copy_from_slice --- core/src/slice/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 8939e5072ba32..5a22110880cc5 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3703,6 +3703,7 @@ impl [T] { /// [`clone_from_slice`]: slice::clone_from_slice /// [`split_at_mut`]: slice::split_at_mut #[doc(alias = "memcpy")] + #[inline] #[stable(feature = "copy_from_slice", since = "1.9.0")] #[rustc_const_unstable(feature = "const_copy_from_slice", issue = "131415")] #[track_caller] From 0168ec06246680c0089893e097584a951038c332 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 11 Jan 2025 08:26:57 -0500 Subject: [PATCH 280/481] Update the explanation for why we use box_new in vec! --- alloc/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alloc/src/macros.rs b/alloc/src/macros.rs index 6ee3907cc8ea2..c000fd6f4efa7 100644 --- a/alloc/src/macros.rs +++ b/alloc/src/macros.rs @@ -48,8 +48,8 @@ macro_rules! vec { ); ($($x:expr),+ $(,)?) => ( <[_]>::into_vec( - // Using the intrinsic produces a dramatic improvement in compile - // time when constructing arrays with many elements. + // Using the intrinsic produces a dramatic improvement in stack usage for + // unoptimized programs using this code path to construct large Vecs. $crate::boxed::box_new([$($x),+]) ) ); From aa9797a72f7d5cce30453c2b9ecb75f277348ec1 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 12 Jan 2025 18:13:02 +0530 Subject: [PATCH 281/481] path: Move is_absolute check to sys::path I am working on fs support for UEFI [0], which similar to windows has prefix components, but is not quite same as Windows. It also seems that Prefix is tied closely to Windows and cannot really be extended [1]. This PR just tries to remove coupling between Prefix and absolute path checking to allow platforms to provide there own implementation to check if a path is absolute or not. I am not sure if any platform other than windows currently uses Prefix, so I have kept the path.prefix().is_some() check in most cases. [0]: https://github.com/rust-lang/rust/pull/135368 [1]: https://github.com/rust-lang/rust/issues/52331#issuecomment-2492796137 Signed-off-by: Ayush Singh --- std/src/path.rs | 15 ++++----------- std/src/sys/path/sgx.rs | 4 ++++ std/src/sys/path/unix.rs | 11 +++++++++++ std/src/sys/path/unsupported_backslash.rs | 4 ++++ std/src/sys/path/windows.rs | 4 ++++ 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/std/src/path.rs b/std/src/path.rs index 35e920ab34476..7fd08a97f1f20 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -298,7 +298,7 @@ where } // Detect scheme on Redox -fn has_redox_scheme(s: &[u8]) -> bool { +pub(crate) fn has_redox_scheme(s: &[u8]) -> bool { cfg!(target_os = "redox") && s.contains(&b':') } @@ -2155,7 +2155,7 @@ impl Path { unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. - fn as_u8_slice(&self) -> &[u8] { + pub(crate) fn as_u8_slice(&self) -> &[u8] { self.inner.as_encoded_bytes() } @@ -2323,14 +2323,7 @@ impl Path { #[must_use] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { - if cfg!(target_os = "redox") { - // FIXME: Allow Redox prefixes - self.has_root() || has_redox_scheme(self.as_u8_slice()) - } else { - self.has_root() - && (cfg!(any(unix, target_os = "hermit", target_os = "wasi")) - || self.prefix().is_some()) - } + sys::path::is_absolute(self) } /// Returns `true` if the `Path` is relative, i.e., not absolute. @@ -2353,7 +2346,7 @@ impl Path { !self.is_absolute() } - fn prefix(&self) -> Option> { + pub(crate) fn prefix(&self) -> Option> { self.components().prefix } diff --git a/std/src/sys/path/sgx.rs b/std/src/sys/path/sgx.rs index c805c15e70245..32c7752f605d9 100644 --- a/std/src/sys/path/sgx.rs +++ b/std/src/sys/path/sgx.rs @@ -23,3 +23,7 @@ pub const MAIN_SEP: char = '/'; pub(crate) fn absolute(_path: &Path) -> io::Result { unsupported() } + +pub(crate) fn is_absolute(path: &Path) -> bool { + path.has_root() && path.prefix().is_some() +} diff --git a/std/src/sys/path/unix.rs b/std/src/sys/path/unix.rs index 2a7c025c3c46a..361e99964f18c 100644 --- a/std/src/sys/path/unix.rs +++ b/std/src/sys/path/unix.rs @@ -60,3 +60,14 @@ pub(crate) fn absolute(path: &Path) -> io::Result { Ok(normalized) } + +pub(crate) fn is_absolute(path: &Path) -> bool { + if cfg!(target_os = "redox") { + // FIXME: Allow Redox prefixes + path.has_root() || crate::path::has_redox_scheme(path.as_u8_slice()) + } else if cfg!(any(unix, target_os = "hermit", target_os = "wasi")) { + path.has_root() + } else { + path.has_root() && path.prefix().is_some() + } +} diff --git a/std/src/sys/path/unsupported_backslash.rs b/std/src/sys/path/unsupported_backslash.rs index 855f443678c6c..30b06c132c98d 100644 --- a/std/src/sys/path/unsupported_backslash.rs +++ b/std/src/sys/path/unsupported_backslash.rs @@ -24,3 +24,7 @@ pub const MAIN_SEP: char = '\\'; pub(crate) fn absolute(_path: &Path) -> io::Result { unsupported() } + +pub(crate) fn is_absolute(path: &Path) -> bool { + path.has_root() && path.prefix().is_some() +} diff --git a/std/src/sys/path/windows.rs b/std/src/sys/path/windows.rs index de042fa3f82ab..1c53472191699 100644 --- a/std/src/sys/path/windows.rs +++ b/std/src/sys/path/windows.rs @@ -346,3 +346,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { os2path, ) } + +pub(crate) fn is_absolute(path: &Path) -> bool { + path.has_root() && path.prefix().is_some() +} From c7bfb6f570c1142b9c3bf5e8e55443b1ed63ee55 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 12 Jan 2025 10:01:45 +0530 Subject: [PATCH 282/481] uefi: helpers: Introduce OwnedDevicePath This PR is split off from #135368 to reduce noise. Rename DevicePath to OwnedDevicePath. This is to allow a non-owning version of DevicePath in the future to work with UEFI shell APIs which provide const pointers to device paths for UEFI shell fs mapping. Also implement Debug for OwnedDevicePath for some quality of life improvements. Signed-off-by: Ayush Singh --- std/src/sys/pal/uefi/helpers.rs | 21 +++++++++++++++------ std/src/sys/pal/uefi/process.rs | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/std/src/sys/pal/uefi/helpers.rs b/std/src/sys/pal/uefi/helpers.rs index 47d9add72b5f0..7504a0f7ad7f5 100644 --- a/std/src/sys/pal/uefi/helpers.rs +++ b/std/src/sys/pal/uefi/helpers.rs @@ -222,14 +222,14 @@ pub(crate) fn runtime_services() -> Option> NonNull::new(runtime_services) } -pub(crate) struct DevicePath(NonNull); +pub(crate) struct OwnedDevicePath(NonNull); -impl DevicePath { +impl OwnedDevicePath { pub(crate) fn from_text(p: &OsStr) -> io::Result { fn inner( p: &OsStr, protocol: NonNull, - ) -> io::Result { + ) -> io::Result { let path_vec = p.encode_wide().chain(Some(0)).collect::>(); if path_vec[..path_vec.len() - 1].contains(&0) { return Err(const_error!( @@ -242,7 +242,7 @@ impl DevicePath { unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) }; NonNull::new(path) - .map(DevicePath) + .map(OwnedDevicePath) .ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")) } @@ -275,12 +275,12 @@ impl DevicePath { )) } - pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol { + pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol { self.0.as_ptr() } } -impl Drop for DevicePath { +impl Drop for OwnedDevicePath { fn drop(&mut self) { if let Some(bt) = boot_services() { let bt: NonNull = bt.cast(); @@ -291,6 +291,15 @@ impl Drop for DevicePath { } } +impl crate::fmt::Debug for OwnedDevicePath { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + match device_path_to_text(self.0) { + Ok(p) => p.fmt(f), + Err(_) => f.debug_struct("OwnedDevicePath").finish_non_exhaustive(), + } + } +} + pub(crate) struct OwnedProtocol { guid: r_efi::efi::Guid, handle: NonNull, diff --git a/std/src/sys/pal/uefi/process.rs b/std/src/sys/pal/uefi/process.rs index 95707ebb7f023..1a0754134dfb8 100644 --- a/std/src/sys/pal/uefi/process.rs +++ b/std/src/sys/pal/uefi/process.rs @@ -326,7 +326,7 @@ mod uefi_command_internal { impl Image { pub fn load_image(p: &OsStr) -> io::Result { - let path = helpers::DevicePath::from_text(p)?; + let path = helpers::OwnedDevicePath::from_text(p)?; let boot_services: NonNull = boot_services() .ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); From 210bfa31ef50eff4e2d2c8817ea158f3e9a09e2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jan 2025 10:35:00 +0100 Subject: [PATCH 283/481] use a single large catch_unwind in lang_start --- std/src/rt.rs | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/std/src/rt.rs b/std/src/rt.rs index b2492238bd37b..334a57d372e0b 100644 --- a/std/src/rt.rs +++ b/std/src/rt.rs @@ -67,7 +67,7 @@ macro_rules! rtunwrap { }; } -fn handle_rt_panic(e: Box) { +fn handle_rt_panic(e: Box) -> T { mem::forget(e); rtabort!("initialization or cleanup bug"); } @@ -168,19 +168,27 @@ fn lang_start_internal( // panic is a std implementation bug. A quite likely one too, as there isn't any way to // prevent std from accidentally introducing a panic to these functions. Another is from // user code from `main` or, more nefariously, as described in e.g. issue #86030. - // SAFETY: Only called once during runtime initialization. - panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }) - .unwrap_or_else(handle_rt_panic); - let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) - .map_err(move |e| { - mem::forget(e); - rtabort!("drop of the panic payload panicked"); - }); - panic::catch_unwind(cleanup).unwrap_or_else(handle_rt_panic); - // Guard against multiple threads calling `libc::exit` concurrently. - // See the documentation for `unique_thread_exit` for more information. - panic::catch_unwind(crate::sys::exit_guard::unique_thread_exit).unwrap_or_else(handle_rt_panic); - ret_code + // + // We use `catch_unwind` with `handle_rt_panic` instead of `abort_unwind` to make the error in + // case of a panic a bit nicer. + panic::catch_unwind(move || { + // SAFETY: Only called once during runtime initialization. + unsafe { init(argc, argv, sigpipe) }; + let ret_code = + panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize).map_err( + move |e| { + // Print a specific error when we abort due to a panicing payload destructor. + mem::forget(e); + rtabort!("drop of the panic payload panicked"); + }, + ); + cleanup(); + // Guard against multiple threads calling `libc::exit` concurrently. + // See the documentation for `unique_thread_exit` for more information. + crate::sys::exit_guard::unique_thread_exit(); + ret_code + }) + .unwrap_or_else(handle_rt_panic) } #[cfg(not(any(test, doctest)))] From 4bf947f4fcec4fe750fa7167a251bda63b095769 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jan 2025 15:43:43 +0100 Subject: [PATCH 284/481] avoid nesting the user-defined main so deeply on the stack --- std/src/rt.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/std/src/rt.rs b/std/src/rt.rs index 334a57d372e0b..24a362072ab61 100644 --- a/std/src/rt.rs +++ b/std/src/rt.rs @@ -157,7 +157,7 @@ fn lang_start_internal( argc: isize, argv: *const *const u8, sigpipe: u8, -) -> Result { +) -> isize { // Guard against the code called by this function from unwinding outside of the Rust-controlled // code, which is UB. This is a requirement imposed by a combination of how the // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking @@ -174,18 +174,24 @@ fn lang_start_internal( panic::catch_unwind(move || { // SAFETY: Only called once during runtime initialization. unsafe { init(argc, argv, sigpipe) }; - let ret_code = - panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize).map_err( - move |e| { - // Print a specific error when we abort due to a panicing payload destructor. - mem::forget(e); - rtabort!("drop of the panic payload panicked"); - }, - ); + + let ret_code = panic::catch_unwind(main).unwrap_or_else(move |payload| { + // Carefully dispose of the panic payload. + let payload = panic::AssertUnwindSafe(payload); + panic::catch_unwind(move || drop({ payload }.0)).unwrap_or_else(move |e| { + mem::forget(e); // do *not* drop the 2nd payload + rtabort!("drop of the panic payload panicked"); + }); + // Return error code for panicking programs. + 101 + }); + let ret_code = ret_code as isize; + cleanup(); // Guard against multiple threads calling `libc::exit` concurrently. // See the documentation for `unique_thread_exit` for more information. crate::sys::exit_guard::unique_thread_exit(); + ret_code }) .unwrap_or_else(handle_rt_panic) @@ -199,11 +205,10 @@ fn lang_start( argv: *const *const u8, sigpipe: u8, ) -> isize { - let Ok(v) = lang_start_internal( + lang_start_internal( &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), argc, argv, sigpipe, - ); - v + ) } From d1fda6368d1bd384bbd3198ea2bbbc4101dff321 Mon Sep 17 00:00:00 2001 From: cod10129 <110200933+cod10129@users.noreply.github.com> Date: Sat, 11 Jan 2025 11:39:40 -0600 Subject: [PATCH 285/481] Add another `Vec::splice` example Add an example for using splice to insert multiple elements efficiently into a vector. --- alloc/src/vec/mod.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 3a706d5f36b7f..cd2afd7a47319 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -3587,7 +3587,7 @@ impl Vec { /// with the given `replace_with` iterator and yields the removed items. /// `replace_with` does not need to be the same length as `range`. /// - /// `range` is removed even if the iterator is not consumed until the end. + /// `range` is removed even if the `Splice` iterator is not consumed before it is dropped. /// /// It is unspecified how many elements are removed from the vector /// if the `Splice` value is leaked. @@ -3613,8 +3613,18 @@ impl Vec { /// let mut v = vec![1, 2, 3, 4]; /// let new = [7, 8, 9]; /// let u: Vec<_> = v.splice(1..3, new).collect(); - /// assert_eq!(v, &[1, 7, 8, 9, 4]); - /// assert_eq!(u, &[2, 3]); + /// assert_eq!(v, [1, 7, 8, 9, 4]); + /// assert_eq!(u, [2, 3]); + /// ``` + /// + /// Using `splice` to insert new items into a vector efficiently at a specific position + /// indicated by an empty range: + /// + /// ``` + /// let mut v = vec![1, 5]; + /// let new = [2, 3, 4]; + /// v.splice(1..1, new); + /// assert_eq!(v, [1, 2, 3, 4, 5]); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] From 9702bad03f823f72ed3c154dbdb20d6a4f5a966a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 02:21:16 +0000 Subject: [PATCH 286/481] Update compiler-builtins to 0.1.141 0.1.141 syncs changes from `libm`. Most of the `libm` changes are testing- or configuration-related. --- Cargo.lock | 4 ++-- alloc/Cargo.toml | 2 +- std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 207c744ee2248..b01fec9b8f5c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.140" +version = "0.1.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df14d41c5d172a886df3753d54238eefb0f61c96cbd8b363c33ccc92c457bee3" +checksum = "b5e7a0206befe4e574e37d6d7a0fe82e88fdf54bedb0608f239cb11b7a6aa6be" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index 07596fa16f982..36f617b45261a 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "=0.1.140", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/std/Cargo.toml b/std/Cargo.toml index e7f7f38cb4154..f34dc185eb195 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.140" } +compiler_builtins = { version = "=0.1.141" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From b22fdce11707a99e8e38408b328157d428230d71 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 12 Jan 2025 20:52:30 +0000 Subject: [PATCH 287/481] Enforce syntactical stability of const traits in HIR --- core/src/intrinsics/fallback.rs | 1 + core/src/marker.rs | 1 + core/src/ops/arith.rs | 1 + core/src/ops/deref.rs | 2 ++ core/src/ops/drop.rs | 1 + 5 files changed, 6 insertions(+) diff --git a/core/src/intrinsics/fallback.rs b/core/src/intrinsics/fallback.rs index 1779126b180ea..70484e4d0f2a1 100644 --- a/core/src/intrinsics/fallback.rs +++ b/core/src/intrinsics/fallback.rs @@ -8,6 +8,7 @@ #![allow(missing_docs)] #[const_trait] +#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] pub trait CarryingMulAdd: Copy + 'static { type Unsigned: Copy + 'static; fn carrying_mul_add( diff --git a/core/src/marker.rs b/core/src/marker.rs index 4af9b666e54fe..01af964a83e26 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -952,6 +952,7 @@ marker_impls! { /// This should be used for `~const` bounds, /// as non-const bounds will always hold for every type. #[unstable(feature = "const_destruct", issue = "133214")] +#[rustc_const_unstable(feature = "const_destruct", issue = "133214")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl] diff --git a/core/src/ops/arith.rs b/core/src/ops/arith.rs index 810b906b8715e..fe7ff2d9ede6a 100644 --- a/core/src/ops/arith.rs +++ b/core/src/ops/arith.rs @@ -65,6 +65,7 @@ /// ``` #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_ops", issue = "90080")] #[rustc_on_unimplemented( on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",), on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",), diff --git a/core/src/ops/deref.rs b/core/src/ops/deref.rs index ed0d30a0f5026..11490ea2bfcb4 100644 --- a/core/src/ops/deref.rs +++ b/core/src/ops/deref.rs @@ -134,6 +134,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] #[const_trait] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -263,6 +264,7 @@ impl const Deref for &mut T { #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] pub trait DerefMut: ~const Deref { /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/core/src/ops/drop.rs b/core/src/ops/drop.rs index 78b5252195f82..e024b7fb4d301 100644 --- a/core/src/ops/drop.rs +++ b/core/src/ops/drop.rs @@ -204,6 +204,7 @@ #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] +#[rustc_const_unstable(feature = "const_destruct", issue = "133214")] pub trait Drop { /// Executes the destructor for this type. /// From 38482b7bea630fd18de04cf2eddec6df1965d603 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 10 Dec 2024 15:45:23 -0500 Subject: [PATCH 288/481] Convert `struct FromBytesWithNulError` into enum One of `CStr` constructors, `CStr::from_bytes_with_nul(bytes: &[u8])` handles 3 cases: 1. `bytes` has one NULL as the last value - creates CStr 2. `bytes` has no NULL - error 3. `bytes` has a NULL in some other position - error The 3rd case is error that may require lossy conversion, but the 2nd case can easily be handled by the user code. Unfortunately, this function returns an opaque `FromBytesWithNulError` error in both 2nd and 3rd case, so the user cannot detect just the 2nd case - having to re-implement the entire function and bring in the `memchr` dependency. In [this code](https://github.com/gquintard/varnish-rs/blob/f86d7a87683b08d2e634d63e77d9dc1d24ed4a13/varnish-sys/src/vcl/ws.rs#L158), my FFI code needs to copy user's `&[u8]` into a C-allocated memory blob in a NUL-terminated `CStr` format. My code must first validate if `&[u8]` has a trailing NUL (case 1), no NUL (adds one on the fly - case 2), or NUL in the middle (3rd case - error). I had to re-implement `from_bytes_with_nul` and add `memchr`dependency just to handle the 2nd case. This PR renames the former `kind` enum from `FromBytesWithNulErrorKind` to `FromBytesWithNulError`, and removes the original struct. --- core/src/ffi/c_str.rs | 50 ++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 8831443a10f17..63915c35288a3 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -124,37 +124,25 @@ pub struct CStr { /// /// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err(); /// ``` -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[stable(feature = "core_c_str", since = "1.64.0")] -pub struct FromBytesWithNulError { - kind: FromBytesWithNulErrorKind, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -enum FromBytesWithNulErrorKind { - InteriorNul(usize), +pub enum FromBytesWithNulError { + /// Data provided contains an interior nul byte at byte `pos`. + InteriorNul { + /// The position of the interior nul byte. + pos: usize, + }, + /// Data provided is not nul terminated. NotNulTerminated, } -// FIXME: const stability attributes should not be required here, I think -impl FromBytesWithNulError { - const fn interior_nul(pos: usize) -> FromBytesWithNulError { - FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } - } - const fn not_nul_terminated() -> FromBytesWithNulError { - FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } - } -} - #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for FromBytesWithNulError { #[allow(deprecated)] fn description(&self) -> &str { - match self.kind { - FromBytesWithNulErrorKind::InteriorNul(..) => { - "data provided contains an interior nul byte" - } - FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated", + match self { + Self::InteriorNul { .. } => "data provided contains an interior nul byte", + Self::NotNulTerminated => "data provided is not nul terminated", } } } @@ -199,7 +187,7 @@ impl fmt::Display for FromBytesWithNulError { #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.description())?; - if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { + if let Self::InteriorNul { pos } = self { write!(f, " at byte pos {pos}")?; } Ok(()) @@ -349,25 +337,25 @@ impl CStr { /// use std::ffi::CStr; /// /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); - /// assert!(cstr.is_ok()); + /// assert_eq!(cstr, Ok(c"hello")); /// ``` /// /// Creating a `CStr` without a trailing nul terminator is an error: /// /// ``` - /// use std::ffi::CStr; + /// use std::ffi::{CStr, FromBytesWithNulError}; /// /// let cstr = CStr::from_bytes_with_nul(b"hello"); - /// assert!(cstr.is_err()); + /// assert_eq!(cstr, Err(FromBytesWithNulError::NotNulTerminated)); /// ``` /// /// Creating a `CStr` with an interior nul byte is an error: /// /// ``` - /// use std::ffi::CStr; + /// use std::ffi::{CStr, FromBytesWithNulError}; /// /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0"); - /// assert!(cstr.is_err()); + /// assert_eq!(cstr, Err(FromBytesWithNulError::InteriorNul { pos: 2 })); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] @@ -379,8 +367,8 @@ impl CStr { // of the byte slice. Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) } - Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)), - None => Err(FromBytesWithNulError::not_nul_terminated()), + Some(pos) => Err(FromBytesWithNulError::InteriorNul { pos }), + None => Err(FromBytesWithNulError::NotNulTerminated), } } From 022bec962eb259a0539445cee05a005e4909f652 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 11 Jan 2025 02:56:58 -0500 Subject: [PATCH 289/481] Rename `pos` to `position` --- core/src/ffi/c_str.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 63915c35288a3..7180593edf0d0 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -127,10 +127,10 @@ pub struct CStr { #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[stable(feature = "core_c_str", since = "1.64.0")] pub enum FromBytesWithNulError { - /// Data provided contains an interior nul byte at byte `pos`. + /// Data provided contains an interior nul byte at byte `position`. InteriorNul { /// The position of the interior nul byte. - pos: usize, + position: usize, }, /// Data provided is not nul terminated. NotNulTerminated, @@ -187,8 +187,8 @@ impl fmt::Display for FromBytesWithNulError { #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.description())?; - if let Self::InteriorNul { pos } = self { - write!(f, " at byte pos {pos}")?; + if let Self::InteriorNul { position } = self { + write!(f, " at byte pos {position}")?; } Ok(()) } @@ -355,7 +355,7 @@ impl CStr { /// use std::ffi::{CStr, FromBytesWithNulError}; /// /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0"); - /// assert_eq!(cstr, Err(FromBytesWithNulError::InteriorNul { pos: 2 })); + /// assert_eq!(cstr, Err(FromBytesWithNulError::InteriorNul { position: 2 })); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] @@ -367,7 +367,7 @@ impl CStr { // of the byte slice. Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) } - Some(pos) => Err(FromBytesWithNulError::InteriorNul { pos }), + Some(position) => Err(FromBytesWithNulError::InteriorNul { position }), None => Err(FromBytesWithNulError::NotNulTerminated), } } From 3b4fb2bcec6f4dcf53d484e64d5a9b1d0ce37386 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 03:58:37 +0000 Subject: [PATCH 290/481] Update compiler-builtins to 0.1.143 0.1.142 fixes an issue parsing optimization flags, and 0.1.143 changes `__rust_[ui]128_*` builtins to use a C-safe signature. --- Cargo.lock | 4 ++-- alloc/Cargo.toml | 2 +- std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b01fec9b8f5c4..c8007dd9be046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.141" +version = "0.1.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e7a0206befe4e574e37d6d7a0fe82e88fdf54bedb0608f239cb11b7a6aa6be" +checksum = "c85ba2077e3eab3dd81be4ece6b7fb2ad0887c1fb813e9a45400baf75c6c7c29" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index 36f617b45261a..96caac890a35c 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/std/Cargo.toml b/std/Cargo.toml index f34dc185eb195..da58d7c13bd12 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.141" } +compiler_builtins = { version = "=0.1.143" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From 00312d1a922a4d1063ac5fabd7fc3af859c49ee4 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 23 Dec 2024 00:33:10 -0600 Subject: [PATCH 291/481] Update ReadDir::next in std::sys::pal::unix::fs to use `&raw const (*ptr).field` instead of `ptr.offset(...).cast()`. Also, the macro is only called three times, and all with the same local variable entry_ptr, so just use the local variable directly, and rename the macro to entry_field_ptr. --- std/src/sys/pal/unix/fs.rs | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 54fa31620aced..fdf011c19482a 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -709,7 +709,7 @@ impl Iterator for ReadDir { // thread safety for readdir() as long an individual DIR* is not accessed // concurrently, which is sufficient for Rust. super::os::set_errno(0); - let entry_ptr = readdir64(self.inner.dirp.0); + let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0); if entry_ptr.is_null() { // We either encountered an error, or reached the end. Either way, // the next call to next() should return None. @@ -735,29 +735,19 @@ impl Iterator for ReadDir { // contents were "simply" partially initialized data. // // Like for uninitialized contents, converting entry_ptr to `&dirent64` - // would not be legal. However, unique to dirent64 is that we don't even - // get to use `&raw const (*entry_ptr).d_name` because that operation - // requires the full extent of *entry_ptr to be in bounds of the same - // allocation, which is not necessarily the case here. - // - // Instead we must access fields individually through their offsets. - macro_rules! offset_ptr { - ($entry_ptr:expr, $field:ident) => {{ - const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize; - if true { - // Cast to the same type determined by the else branch. - $entry_ptr.byte_offset(OFFSET).cast::<_>() - } else { - #[allow(deref_nullptr)] - { - &raw const (*ptr::null::()).$field - } - } - }}; + // would not be legal. However, we can use `&raw const (*entry_ptr).d_name` + // to refer the fields individually, because that operation is equivalent + // to `byte_offset` and thus does not require the full extent of `*entry_ptr` + // to be in bounds of the same allocation, only the offset of the field + // being referenced. + macro_rules! entry_field_ptr { + ($field:ident) => { + &raw const (*entry_ptr).$field + }; } // d_name is guaranteed to be null-terminated. - let name = CStr::from_ptr(offset_ptr!(entry_ptr, d_name).cast()); + let name = CStr::from_ptr(entry_field_ptr!(d_name).cast()); let name_bytes = name.to_bytes(); if name_bytes == b"." || name_bytes == b".." { continue; @@ -765,14 +755,14 @@ impl Iterator for ReadDir { #[cfg(not(target_os = "vita"))] let entry = dirent64_min { - d_ino: *offset_ptr!(entry_ptr, d_ino) as u64, + d_ino: *entry_field_ptr!(d_ino) as u64, #[cfg(not(any( target_os = "solaris", target_os = "illumos", target_os = "aix", target_os = "nto", )))] - d_type: *offset_ptr!(entry_ptr, d_type) as u8, + d_type: *entry_field_ptr!(d_type) as u8, }; #[cfg(target_os = "vita")] From 71ac27af554fd1fbc711eb28b014afbc1a3b531e Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 25 Nov 2024 09:50:24 +0100 Subject: [PATCH 292/481] Revert "Remove the Arc rt::init allocation for thread info" This reverts commit 1ee38271cae49178080ea4df8f5aae5ad3a81cd6. --- std/src/rt.rs | 2 +- std/src/thread/mod.rs | 170 +++++++++++++----------------------------- 2 files changed, 54 insertions(+), 118 deletions(-) diff --git a/std/src/rt.rs b/std/src/rt.rs index 24a362072ab61..56952aac6c63d 100644 --- a/std/src/rt.rs +++ b/std/src/rt.rs @@ -110,7 +110,7 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // handle does not match the current ID, we should attempt to use the // current thread ID here instead of unconditionally creating a new // one. Also see #130210. - let thread = unsafe { Thread::new_main(thread::current_id()) }; + let thread = Thread::new_main(thread::current_id()); if let Err(_thread) = thread::set_current(thread) { // `thread::current` will create a new handle if none has been set yet. // Thus, if someone uses it before main, this call will fail. That's a diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index b6ee00a253a95..81d75641ab595 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -158,12 +158,9 @@ #[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; -use core::cell::SyncUnsafeCell; -use core::ffi::CStr; -use core::mem::MaybeUninit; - use crate::any::Any; use crate::cell::UnsafeCell; +use crate::ffi::CStr; use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop, forget}; use crate::num::NonZero; @@ -1259,31 +1256,30 @@ impl ThreadId { // Thread //////////////////////////////////////////////////////////////////////////////// +/// The internal representation of a `Thread`'s name. +enum ThreadName { + Main, + Other(ThreadNameString), + Unnamed, +} + // This module ensures private fields are kept private, which is necessary to enforce the safety requirements. mod thread_name_string { use core::str; + use super::ThreadName; use crate::ffi::{CStr, CString}; /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated. pub(crate) struct ThreadNameString { inner: CString, } - - impl ThreadNameString { - pub fn as_str(&self) -> &str { - // SAFETY: `self.inner` is only initialised via `String`, which upholds the validity invariant of `str`. - unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) } - } - } - impl core::ops::Deref for ThreadNameString { type Target = CStr; fn deref(&self) -> &CStr { &self.inner } } - impl From for ThreadNameString { fn from(s: String) -> Self { Self { @@ -1291,82 +1287,34 @@ mod thread_name_string { } } } + impl ThreadName { + pub fn as_cstr(&self) -> Option<&CStr> { + match self { + ThreadName::Main => Some(c"main"), + ThreadName::Other(other) => Some(other), + ThreadName::Unnamed => None, + } + } + + pub fn as_str(&self) -> Option<&str> { + // SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`, + // which is guaranteed to be UTF-8. + self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) }) + } + } } pub(crate) use thread_name_string::ThreadNameString; -static MAIN_THREAD_INFO: SyncUnsafeCell<(MaybeUninit, MaybeUninit)> = - SyncUnsafeCell::new((MaybeUninit::uninit(), MaybeUninit::uninit())); - -/// The internal representation of a `Thread` that is not the main thread. -struct OtherInner { - name: Option, +/// The internal representation of a `Thread` handle +struct Inner { + name: ThreadName, // Guaranteed to be UTF-8 id: ThreadId, parker: Parker, } -/// The internal representation of a `Thread` handle. -#[derive(Clone)] -enum Inner { - /// Represents the main thread. May only be constructed by Thread::new_main. - Main(&'static (ThreadId, Parker)), - /// Represents any other thread. - Other(Pin>), -} - impl Inner { - fn id(&self) -> ThreadId { - match self { - Self::Main((thread_id, _)) => *thread_id, - Self::Other(other) => other.id, - } - } - - fn cname(&self) -> Option<&CStr> { - match self { - Self::Main(_) => Some(c"main"), - Self::Other(other) => other.name.as_deref(), - } - } - - fn name(&self) -> Option<&str> { - match self { - Self::Main(_) => Some("main"), - Self::Other(other) => other.name.as_ref().map(ThreadNameString::as_str), - } - } - - fn into_raw(self) -> *const () { - match self { - // Just return the pointer to `MAIN_THREAD_INFO`. - Self::Main(ptr) => crate::ptr::from_ref(ptr).cast(), - Self::Other(arc) => { - // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant. - let inner = unsafe { Pin::into_inner_unchecked(arc) }; - Arc::into_raw(inner) as *const () - } - } - } - - /// # Safety - /// - /// See [`Thread::from_raw`]. - unsafe fn from_raw(ptr: *const ()) -> Self { - // If the pointer is to `MAIN_THREAD_INFO`, we know it is the `Main` variant. - if crate::ptr::eq(ptr.cast(), &MAIN_THREAD_INFO) { - Self::Main(unsafe { &*ptr.cast() }) - } else { - // Safety: Upheld by caller - Self::Other(unsafe { Pin::new_unchecked(Arc::from_raw(ptr as *const OtherInner)) }) - } - } - - fn parker(&self) -> Pin<&Parker> { - match self { - Self::Main((_, parker_ref)) => Pin::static_ref(parker_ref), - Self::Other(inner) => unsafe { - Pin::map_unchecked(inner.as_ref(), |inner| &inner.parker) - }, - } + fn parker(self: Pin<&Self>) -> Pin<&Parker> { + unsafe { Pin::map_unchecked(self, |inner| &inner.parker) } } } @@ -1390,47 +1338,33 @@ impl Inner { /// docs of [`Builder`] and [`spawn`] for more details. /// /// [`thread::current`]: current::current -pub struct Thread(Inner); +pub struct Thread { + inner: Pin>, +} impl Thread { /// Used only internally to construct a thread object without spawning. pub(crate) fn new(id: ThreadId, name: String) -> Thread { - Self::new_inner(id, Some(ThreadNameString::from(name))) + Self::new_inner(id, ThreadName::Other(name.into())) } pub(crate) fn new_unnamed(id: ThreadId) -> Thread { - Self::new_inner(id, None) + Self::new_inner(id, ThreadName::Unnamed) } - /// Used in runtime to construct main thread - /// - /// # Safety - /// - /// This must only ever be called once, and must be called on the main thread. - pub(crate) unsafe fn new_main(thread_id: ThreadId) -> Thread { - // Safety: As this is only called once and on the main thread, nothing else is accessing MAIN_THREAD_INFO - // as the only other read occurs in `main_thread_info` *after* the main thread has been constructed, - // and this function is the only one that constructs the main thread. - // - // Pre-main thread spawning cannot hit this either, as the caller promises that this is only called on the main thread. - let main_thread_info = unsafe { &mut *MAIN_THREAD_INFO.get() }; - - unsafe { Parker::new_in_place((&raw mut main_thread_info.1).cast()) }; - main_thread_info.0.write(thread_id); - - // Store a `'static` ref to the initialised ThreadId and Parker, - // to avoid having to repeatedly prove initialisation. - Self(Inner::Main(unsafe { &*MAIN_THREAD_INFO.get().cast() })) + /// Constructs the thread handle for the main thread. + pub(crate) fn new_main(id: ThreadId) -> Thread { + Self::new_inner(id, ThreadName::Main) } - fn new_inner(id: ThreadId, name: Option) -> Thread { + fn new_inner(id: ThreadId, name: ThreadName) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // // SAFETY: We pin the Arc immediately after creation, so its address never // changes. let inner = unsafe { - let mut arc = Arc::::new_uninit(); + let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); (&raw mut (*ptr).name).write(name); (&raw mut (*ptr).id).write(id); @@ -1438,7 +1372,7 @@ impl Thread { Pin::new_unchecked(arc.assume_init()) }; - Self(Inner::Other(inner)) + Thread { inner } } /// Like the public [`park`], but callable on any handle. This is used to @@ -1447,7 +1381,7 @@ impl Thread { /// # Safety /// May only be called from the thread to which this handle belongs. pub(crate) unsafe fn park(&self) { - unsafe { self.0.parker().park() } + unsafe { self.inner.as_ref().parker().park() } } /// Like the public [`park_timeout`], but callable on any handle. This is @@ -1456,7 +1390,7 @@ impl Thread { /// # Safety /// May only be called from the thread to which this handle belongs. pub(crate) unsafe fn park_timeout(&self, dur: Duration) { - unsafe { self.0.parker().park_timeout(dur) } + unsafe { self.inner.as_ref().parker().park_timeout(dur) } } /// Atomically makes the handle's token available if it is not already. @@ -1492,7 +1426,7 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn unpark(&self) { - self.0.parker().unpark(); + self.inner.as_ref().parker().unpark(); } /// Gets the thread's unique identifier. @@ -1512,7 +1446,7 @@ impl Thread { #[stable(feature = "thread_id", since = "1.19.0")] #[must_use] pub fn id(&self) -> ThreadId { - self.0.id() + self.inner.id } /// Gets the thread's name. @@ -1555,11 +1489,7 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub fn name(&self) -> Option<&str> { - self.0.name() - } - - fn cname(&self) -> Option<&CStr> { - self.0.cname() + self.inner.name.as_str() } /// Consumes the `Thread`, returning a raw pointer. @@ -1583,7 +1513,9 @@ impl Thread { /// ``` #[unstable(feature = "thread_raw", issue = "97523")] pub fn into_raw(self) -> *const () { - self.0.into_raw() + // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant. + let inner = unsafe { Pin::into_inner_unchecked(self.inner) }; + Arc::into_raw(inner) as *const () } /// Constructs a `Thread` from a raw pointer. @@ -1605,7 +1537,11 @@ impl Thread { #[unstable(feature = "thread_raw", issue = "97523")] pub unsafe fn from_raw(ptr: *const ()) -> Thread { // Safety: Upheld by caller. - unsafe { Thread(Inner::from_raw(ptr)) } + unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } } + } + + fn cname(&self) -> Option<&CStr> { + self.inner.name.as_cstr() } } From 9ab82d73924a4f977db3163ffed1911e561e661c Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 25 Nov 2024 13:01:35 +0100 Subject: [PATCH 293/481] std: lazily allocate the main thread handle Thereby, we also allow accessing thread::current before main: as the runtime no longer tries to install its own handle, this will no longer trigger an abort. Rather, the name returned from name will only be "main" after the runtime initialization code has run, but I think that is acceptable. This new approach also requires some changes to the signal handling code, as calling `thread::current` would now allocate when called on the main thread, which is not acceptable. I fixed this by adding a new function (`with_current_name`) that performs all the naming logic without allocation or without initializing the thread ID (which could allocate on some platforms). --- std/src/panicking.rs | 39 +++--- std/src/rt.rs | 23 +--- std/src/sys/pal/unix/stack_overflow.rs | 9 +- std/src/sys/pal/windows/stack_overflow.rs | 8 +- std/src/thread/current.rs | 36 +++--- std/src/thread/mod.rs | 150 ++++++++++++++-------- 6 files changed, 151 insertions(+), 114 deletions(-) diff --git a/std/src/panicking.rs b/std/src/panicking.rs index 3b02254548b1c..8e50bf11dd082 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -258,31 +258,34 @@ fn default_hook(info: &PanicHookInfo<'_>) { let location = info.location().unwrap(); let msg = payload_as_str(info.payload()); - let thread = thread::try_current(); - let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = #[optimize(size)] |err: &mut dyn crate::io::Write| { // Use a lock to prevent mixed output in multithreading context. // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. let mut lock = backtrace::lock(); - // Try to write the panic message to a buffer first to prevent other concurrent outputs - // interleaving with it. - let mut buffer = [0u8; 512]; - let mut cursor = crate::io::Cursor::new(&mut buffer[..]); - - let write_msg = |dst: &mut dyn crate::io::Write| { - // We add a newline to ensure the panic message appears at the start of a line. - writeln!(dst, "\nthread '{name}' panicked at {location}:\n{msg}") - }; - if write_msg(&mut cursor).is_ok() { - let pos = cursor.position() as usize; - let _ = err.write_all(&buffer[0..pos]); - } else { - // The message did not fit into the buffer, write it directly instead. - let _ = write_msg(err); - }; + thread::with_current_name(|name| { + let name = name.unwrap_or(""); + + // Try to write the panic message to a buffer first to prevent other concurrent outputs + // interleaving with it. + let mut buffer = [0u8; 512]; + let mut cursor = crate::io::Cursor::new(&mut buffer[..]); + + let write_msg = |dst: &mut dyn crate::io::Write| { + // We add a newline to ensure the panic message appears at the start of a line. + writeln!(dst, "\nthread '{name}' panicked at {location}:\n{msg}") + }; + + if write_msg(&mut cursor).is_ok() { + let pos = cursor.position() as usize; + let _ = err.write_all(&buffer[0..pos]); + } else { + // The message did not fit into the buffer, write it directly instead. + let _ = write_msg(err); + }; + }); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); diff --git a/std/src/rt.rs b/std/src/rt.rs index 56952aac6c63d..384369b0012b5 100644 --- a/std/src/rt.rs +++ b/std/src/rt.rs @@ -23,7 +23,7 @@ pub use core::panicking::{panic_display, panic_fmt}; #[rustfmt::skip] use crate::any::Any; use crate::sync::Once; -use crate::thread::{self, Thread}; +use crate::thread::{self, main_thread}; use crate::{mem, panic, sys}; // Prints to the "panic output", depending on the platform this may be: @@ -102,24 +102,9 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { sys::init(argc, argv, sigpipe) }; - // Set up the current thread handle to give it the right name. - // - // When code running before main uses `ReentrantLock` (for example by - // using `println!`), the thread ID can become initialized before we - // create this handle. Since `set_current` fails when the ID of the - // handle does not match the current ID, we should attempt to use the - // current thread ID here instead of unconditionally creating a new - // one. Also see #130210. - let thread = Thread::new_main(thread::current_id()); - if let Err(_thread) = thread::set_current(thread) { - // `thread::current` will create a new handle if none has been set yet. - // Thus, if someone uses it before main, this call will fail. That's a - // bad idea though, as we then cannot set the main thread name here. - // - // FIXME: detect the main thread in `thread::current` and use the - // correct name there. - rtabort!("code running before main must not use thread::current"); - } + // Remember the main thread ID to give it the correct name. + // SAFETY: this is the only time and place where we call this function. + unsafe { main_thread::set(thread::current_id()) }; } /// Clean up the thread-local runtime state. This *should* be run after all other diff --git a/std/src/sys/pal/unix/stack_overflow.rs b/std/src/sys/pal/unix/stack_overflow.rs index 69b31da427fcb..db5c6bd3a1c32 100644 --- a/std/src/sys/pal/unix/stack_overflow.rs +++ b/std/src/sys/pal/unix/stack_overflow.rs @@ -100,10 +100,11 @@ mod imp { // If the faulting address is within the guard page, then we print a // message saying so and abort. if start <= addr && addr < end { - rtprintpanic!( - "\nthread '{}' has overflowed its stack\n", - thread::current().name().unwrap_or("") - ); + thread::with_current_name(|name| { + let name = name.unwrap_or(""); + rtprintpanic!("\nthread '{name}' has overflowed its stack\n"); + }); + rtabort!("stack overflow"); } else { // Unregister ourselves by reverting back to the default behavior. diff --git a/std/src/sys/pal/windows/stack_overflow.rs b/std/src/sys/pal/windows/stack_overflow.rs index 467e21ab56a28..734cd30bed08f 100644 --- a/std/src/sys/pal/windows/stack_overflow.rs +++ b/std/src/sys/pal/windows/stack_overflow.rs @@ -18,10 +18,10 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN let code = rec.ExceptionCode; if code == c::EXCEPTION_STACK_OVERFLOW { - rtprintpanic!( - "\nthread '{}' has overflowed its stack\n", - thread::current().name().unwrap_or("") - ); + thread::with_current_name(|name| { + let name = name.unwrap_or(""); + rtprintpanic!("\nthread '{name}' has overflowed its stack\n"); + }); } c::EXCEPTION_CONTINUE_SEARCH } diff --git a/std/src/thread/current.rs b/std/src/thread/current.rs index 3d2c288b36085..fa88059fe64e3 100644 --- a/std/src/thread/current.rs +++ b/std/src/thread/current.rs @@ -15,7 +15,7 @@ local_pointer! { /// /// We store the thread ID so that it never gets destroyed during the lifetime /// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s. -mod id { +pub(super) mod id { use super::*; cfg_if::cfg_if! { @@ -27,7 +27,7 @@ mod id { pub(super) const CHEAP: bool = true; - pub(super) fn get() -> Option { + pub(crate) fn get() -> Option { ID.get() } @@ -44,7 +44,7 @@ mod id { pub(super) const CHEAP: bool = false; - pub(super) fn get() -> Option { + pub(crate) fn get() -> Option { let id0 = ID0.get().addr() as u64; let id16 = ID16.get().addr() as u64; let id32 = ID32.get().addr() as u64; @@ -67,7 +67,7 @@ mod id { pub(super) const CHEAP: bool = false; - pub(super) fn get() -> Option { + pub(crate) fn get() -> Option { let id0 = ID0.get().addr() as u64; let id32 = ID32.get().addr() as u64; ThreadId::from_u64((id32 << 32) + id0) @@ -85,7 +85,7 @@ mod id { pub(super) const CHEAP: bool = true; - pub(super) fn get() -> Option { + pub(crate) fn get() -> Option { let id = ID.get().addr() as u64; ThreadId::from_u64(id) } @@ -112,7 +112,7 @@ mod id { /// Tries to set the thread handle for the current thread. Fails if a handle was /// already set or if the thread ID of `thread` would change an already-set ID. -pub(crate) fn set_current(thread: Thread) -> Result<(), Thread> { +pub(super) fn set_current(thread: Thread) -> Result<(), Thread> { if CURRENT.get() != NONE { return Err(thread); } @@ -140,28 +140,28 @@ pub(crate) fn current_id() -> ThreadId { // to retrieve it from the current thread handle, which will only take one // TLS access. if !id::CHEAP { - let current = CURRENT.get(); - if current > DESTROYED { - unsafe { - let current = ManuallyDrop::new(Thread::from_raw(current)); - return current.id(); - } + if let Some(id) = try_with_current(|t| t.map(|t| t.id())) { + return id; } } id::get_or_init() } -/// Gets a handle to the thread that invokes it, if the handle has been initialized. -pub(crate) fn try_current() -> Option { +/// Gets a reference to the handle of the thread that invokes it, if the handle +/// has been initialized. +pub(super) fn try_with_current(f: F) -> R +where + F: FnOnce(Option<&Thread>) -> R, +{ let current = CURRENT.get(); if current > DESTROYED { unsafe { let current = ManuallyDrop::new(Thread::from_raw(current)); - Some((*current).clone()) + f(Some(¤t)) } } else { - None + f(None) } } @@ -176,7 +176,7 @@ pub(crate) fn current_or_unnamed() -> Thread { (*current).clone() } } else if current == DESTROYED { - Thread::new_unnamed(id::get_or_init()) + Thread::new(id::get_or_init(), None) } else { init_current(current) } @@ -221,7 +221,7 @@ fn init_current(current: *mut ()) -> Thread { CURRENT.set(BUSY); // If the thread ID was initialized already, use it. let id = id::get_or_init(); - let thread = Thread::new_unnamed(id); + let thread = Thread::new(id, None); // Make sure that `crate::rt::thread_cleanup` will be run, which will // call `drop_current`. diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 81d75641ab595..cf7a951d100ec 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -183,7 +183,8 @@ mod current; #[stable(feature = "rust1", since = "1.0.0")] pub use current::current; -pub(crate) use current::{current_id, current_or_unnamed, drop_current, set_current, try_current}; +pub(crate) use current::{current_id, current_or_unnamed, drop_current}; +use current::{set_current, try_with_current}; mod spawnhook; @@ -498,10 +499,7 @@ impl Builder { }); let id = ThreadId::new(); - let my_thread = match name { - Some(name) => Thread::new(id, name), - None => Thread::new_unnamed(id), - }; + let my_thread = Thread::new(id, name); let hooks = if no_hooks { spawnhook::ChildSpawnHooks::default() @@ -1232,7 +1230,7 @@ impl ThreadId { } } - #[cfg(not(target_thread_local))] + #[cfg(any(not(target_thread_local), target_has_atomic = "64"))] fn from_u64(v: u64) -> Option { NonZero::new(v).map(ThreadId) } @@ -1256,30 +1254,16 @@ impl ThreadId { // Thread //////////////////////////////////////////////////////////////////////////////// -/// The internal representation of a `Thread`'s name. -enum ThreadName { - Main, - Other(ThreadNameString), - Unnamed, -} - // This module ensures private fields are kept private, which is necessary to enforce the safety requirements. mod thread_name_string { - use core::str; - - use super::ThreadName; use crate::ffi::{CStr, CString}; + use crate::str; /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated. pub(crate) struct ThreadNameString { inner: CString, } - impl core::ops::Deref for ThreadNameString { - type Target = CStr; - fn deref(&self) -> &CStr { - &self.inner - } - } + impl From for ThreadNameString { fn from(s: String) -> Self { Self { @@ -1287,27 +1271,91 @@ mod thread_name_string { } } } - impl ThreadName { - pub fn as_cstr(&self) -> Option<&CStr> { - match self { - ThreadName::Main => Some(c"main"), - ThreadName::Other(other) => Some(other), - ThreadName::Unnamed => None, - } + + impl ThreadNameString { + pub fn as_cstr(&self) -> &CStr { + &self.inner } - pub fn as_str(&self) -> Option<&str> { - // SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`, - // which is guaranteed to be UTF-8. - self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) }) + pub fn as_str(&self) -> &str { + // SAFETY: `ThreadNameString` is guaranteed to be UTF-8. + unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) } + } + } +} + +use thread_name_string::ThreadNameString; + +pub(crate) mod main_thread { + cfg_if::cfg_if! { + if #[cfg(target_has_atomic = "64")] { + use super::ThreadId; + use crate::sync::atomic::AtomicU64; + use crate::sync::atomic::Ordering::Relaxed; + + static MAIN: AtomicU64 = AtomicU64::new(0); + + pub(super) fn get() -> Option { + ThreadId::from_u64(MAIN.load(Relaxed)) + } + + /// # Safety + /// May only be called once. + pub(crate) unsafe fn set(id: ThreadId) { + MAIN.store(id.as_u64().get(), Relaxed) + } + } else { + use super::ThreadId; + use crate::mem::MaybeUninit; + use crate::sync::atomic::AtomicBool; + use crate::sync::atomic::Ordering::{Acquire, Release}; + + static INIT: AtomicBool = AtomicBool::new(false); + static mut MAIN: MaybeUninit = MaybeUninit::uninit(); + + pub(super) fn get() -> Option { + if INIT.load(Acquire) { + Some(unsafe { MAIN.assume_init() }) + } else { + None + } + } + + /// # Safety + /// May only be called once. + pub(crate) unsafe fn set(id: ThreadId) { + unsafe { MAIN = MaybeUninit::new(id) }; + INIT.store(true, Release); + } } } } -pub(crate) use thread_name_string::ThreadNameString; + +pub(crate) fn with_current_name(f: F) -> R +where + F: FnOnce(Option<&str>) -> R, +{ + try_with_current(|thread| { + if let Some(thread) = thread { + if let Some(name) = &thread.inner.name { + return f(Some(name.as_str())); + } else if Some(thread.inner.id) == main_thread::get() { + return f(Some("main")); + } + } else if let Some(main) = main_thread::get() + && let Some(id) = current::id::get() + && id == main + { + return f(Some("main")); + } + + f(None) + }) +} /// The internal representation of a `Thread` handle struct Inner { - name: ThreadName, // Guaranteed to be UTF-8 + name: Option, id: ThreadId, parker: Parker, } @@ -1343,21 +1391,9 @@ pub struct Thread { } impl Thread { - /// Used only internally to construct a thread object without spawning. - pub(crate) fn new(id: ThreadId, name: String) -> Thread { - Self::new_inner(id, ThreadName::Other(name.into())) - } - - pub(crate) fn new_unnamed(id: ThreadId) -> Thread { - Self::new_inner(id, ThreadName::Unnamed) - } - - /// Constructs the thread handle for the main thread. - pub(crate) fn new_main(id: ThreadId) -> Thread { - Self::new_inner(id, ThreadName::Main) - } + pub(crate) fn new(id: ThreadId, name: Option) -> Thread { + let name = name.map(ThreadNameString::from); - fn new_inner(id: ThreadId, name: ThreadName) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // @@ -1489,7 +1525,13 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub fn name(&self) -> Option<&str> { - self.inner.name.as_str() + if let Some(name) = &self.inner.name { + Some(name.as_str()) + } else if main_thread::get() == Some(self.inner.id) { + Some("main") + } else { + None + } } /// Consumes the `Thread`, returning a raw pointer. @@ -1541,7 +1583,13 @@ impl Thread { } fn cname(&self) -> Option<&CStr> { - self.inner.name.as_cstr() + if let Some(name) = &self.inner.name { + Some(name.as_cstr()) + } else if main_thread::get() == Some(self.inner.id) { + Some(c"main") + } else { + None + } } } From 189650529153a123b92dbcc73f3e06b72b3b7fff Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 27 Nov 2024 14:40:09 +0100 Subject: [PATCH 294/481] add comments explaining main thread identification --- std/src/thread/current.rs | 3 +++ std/src/thread/mod.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/std/src/thread/current.rs b/std/src/thread/current.rs index fa88059fe64e3..414711298f047 100644 --- a/std/src/thread/current.rs +++ b/std/src/thread/current.rs @@ -156,6 +156,9 @@ where { let current = CURRENT.get(); if current > DESTROYED { + // SAFETY: `Arc` does not contain interior mutability, so it does not + // matter that the address of the handle might be different depending + // on where this is called. unsafe { let current = ManuallyDrop::new(Thread::from_raw(current)); f(Some(¤t)) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index cf7a951d100ec..59b395336f2e3 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -1286,6 +1286,18 @@ mod thread_name_string { use thread_name_string::ThreadNameString; +/// Store the ID of the main thread. +/// +/// The thread handle for the main thread is created lazily, and this might even +/// happen pre-main. Since not every platform has a way to identify the main +/// thread when that happens – macOS's `pthread_main_np` function being a notable +/// exception – we cannot assign it the right name right then. Instead, in our +/// runtime startup code, we remember the thread ID of the main thread (through +/// this modules `set` function) and use it to identify the main thread from then +/// on. This works reliably and has the additional advantage that we can report +/// the right thread name on main even after the thread handle has been destroyed. +/// Note however that this also means that the name reported in pre-main functions +/// will be incorrect, but that's just something we have to live with. pub(crate) mod main_thread { cfg_if::cfg_if! { if #[cfg(target_has_atomic = "64")] { @@ -1331,21 +1343,35 @@ pub(crate) mod main_thread { } } +/// Run a function with the current thread's name. +/// +/// Modulo thread local accesses, this function is safe to call from signal +/// handlers and in similar circumstances where allocations are not possible. pub(crate) fn with_current_name(f: F) -> R where F: FnOnce(Option<&str>) -> R, { try_with_current(|thread| { if let Some(thread) = thread { + // If there is a current thread handle, try to use the name stored + // there. if let Some(name) = &thread.inner.name { return f(Some(name.as_str())); } else if Some(thread.inner.id) == main_thread::get() { + // The main thread doesn't store its name in the handle, we must + // identify it through its ID. Since we already have the `Thread`, + // we can retrieve the ID from it instead of going through another + // thread local. return f(Some("main")); } } else if let Some(main) = main_thread::get() && let Some(id) = current::id::get() && id == main { + // The main thread doesn't always have a thread handle, we must + // identify it through its ID instead. The checks are ordered so + // that the current ID is only loaded if it is actually needed, + // since loading it from TLS might need multiple expensive accesses. return f(Some("main")); } From cbeb3d9b3761de0d75e5d371725d0a185593e810 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jan 2025 20:22:59 +0100 Subject: [PATCH 295/481] intrinsics: deprecate calling them via the unstable std::intrinsics path --- core/src/intrinsics/mod.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 7b31bbec7547c..41b2ffad6680d 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1897,7 +1897,11 @@ pub const fn forget(_: T) { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] +#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] +#[cfg_attr( + not(bootstrap), + rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" +)] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] #[rustc_nounwind] @@ -4325,7 +4329,11 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] +#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] +#[cfg_attr( + not(bootstrap), + rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" +)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4429,7 +4437,11 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] +#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] +#[cfg_attr( + not(bootstrap), + rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" +)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4512,7 +4524,11 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] +#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] +#[cfg_attr( + not(bootstrap), + rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" +)] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces From 0d2cdfbfa3d4ba21d27d9e18a82131f41743105a Mon Sep 17 00:00:00 2001 From: DJMrTV Date: Tue, 14 Jan 2025 19:26:28 +0100 Subject: [PATCH 296/481] fix typo in typenames of pin documentation --- core/src/pin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/pin.rs b/core/src/pin.rs index 83730285636fb..71044190f0c88 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -331,7 +331,7 @@ //! //! Note that this invariant is enforced by simply making it impossible to call code that would //! perform a move on the pinned value. This is the case since the only way to access that pinned -//! value is through the pinning [Pin]<[&mut] T>>, which in turn restricts our access. +//! value is through the pinning [Pin]<[&mut] T>, which in turn restricts our access. //! //! ## [`Unpin`] //! @@ -379,7 +379,7 @@ //! //! Exposing access to the inner field which you want to remain pinned must then be carefully //! considered as well! Remember, exposing a method that gives access to a -//! [Pin]<[&mut] InnerT>> where InnerT: [Unpin] would allow safe code to +//! [Pin]<[&mut] InnerT> where InnerT: [Unpin] would allow safe code to //! trivially move the inner value out of that pinning pointer, which is precisely what you're //! seeking to prevent! Exposing a field of a pinned value through a pinning pointer is called //! "projecting" a pin, and the more general case of deciding in which cases a pin should be able From 4e50bc72237e7c21f9358380fef549fbddcf1fab Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 10 Jan 2025 13:00:45 -0800 Subject: [PATCH 297/481] Less unsafe in `dangling`/`without_provenance` --- core/src/ptr/alignment.rs | 12 +++++++++--- core/src/ptr/mod.rs | 11 +++-------- core/src/ptr/non_null.rs | 16 +++++++--------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/core/src/ptr/alignment.rs b/core/src/ptr/alignment.rs index 74a1d40f4e734..2da94e72566e9 100644 --- a/core/src/ptr/alignment.rs +++ b/core/src/ptr/alignment.rs @@ -42,9 +42,10 @@ impl Alignment { /// but in an `Alignment` instead of a `usize`. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] + #[must_use] pub const fn of() -> Self { - // SAFETY: rustc ensures that type alignment is always a power of two. - unsafe { Alignment::new_unchecked(mem::align_of::()) } + // This can't actually panic since type alignment is always a power of two. + const { Alignment::new(mem::align_of::()).unwrap() } } /// Creates an `Alignment` from a `usize`, or returns `None` if it's @@ -95,8 +96,13 @@ impl Alignment { #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const fn as_nonzero(self) -> NonZero { + // This transmutes directly to avoid the UbCheck in `NonZero::new_unchecked` + // since there's no way for the user to trip that check anyway -- the + // validity invariant of the type would have to have been broken earlier -- + // and emitting it in an otherwise simple method is bad for compile time. + // SAFETY: All the discriminants are non-zero. - unsafe { NonZero::new_unchecked(self.as_usize()) } + unsafe { mem::transmute::>(self) } } /// Returns the base-2 logarithm of the alignment. diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index f58c0e1241142..e1348552b65c3 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -596,12 +596,7 @@ pub const fn null_mut() -> *mut T { #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn without_provenance(addr: usize) -> *const T { - // An int-to-pointer transmute currently has exactly the intended semantics: it creates a - // pointer without provenance. Note that this is *not* a stable guarantee about transmute - // semantics, it relies on sysroot crates having special status. - // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that - // pointer). - unsafe { mem::transmute(addr) } + without_provenance_mut(addr) } /// Creates a new pointer that is dangling, but non-null and well-aligned. @@ -618,7 +613,7 @@ pub const fn without_provenance(addr: usize) -> *const T { #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn dangling() -> *const T { - without_provenance(mem::align_of::()) + dangling_mut() } /// Creates a pointer with the given address and no [provenance][crate::ptr#provenance]. @@ -661,7 +656,7 @@ pub const fn without_provenance_mut(addr: usize) -> *mut T { #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] pub const fn dangling_mut() -> *mut T { - without_provenance_mut(mem::align_of::()) + NonNull::dangling().as_ptr() } /// Converts an address back to a pointer, picking up some previously 'exposed' diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index 2c9131254f7c4..d93069d384edd 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -91,12 +91,12 @@ impl NonNull { /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[unstable(feature = "nonnull_provenance", issue = "135243")] + #[must_use] + #[inline] pub const fn without_provenance(addr: NonZero) -> Self { + let pointer = crate::ptr::without_provenance(addr.get()); // SAFETY: we know `addr` is non-zero. - unsafe { - let ptr = crate::ptr::without_provenance_mut(addr.get()); - NonNull::new_unchecked(ptr) - } + unsafe { NonNull { pointer } } } /// Creates a new `NonNull` that is dangling, but well-aligned. @@ -123,11 +123,8 @@ impl NonNull { #[must_use] #[inline] pub const fn dangling() -> Self { - // SAFETY: ptr::dangling_mut() returns a non-null well-aligned pointer. - unsafe { - let ptr = crate::ptr::dangling_mut::(); - NonNull::new_unchecked(ptr) - } + let align = crate::ptr::Alignment::of::(); + NonNull::without_provenance(align.as_nonzero()) } /// Converts an address back to a mutable pointer, picking up some previously 'exposed' @@ -137,6 +134,7 @@ impl NonNull { /// /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[unstable(feature = "nonnull_provenance", issue = "135243")] + #[inline] pub fn with_exposed_provenance(addr: NonZero) -> Self { // SAFETY: we know `addr` is non-zero. unsafe { From 6893e1a1060164eaaddd3f0cac0ee6cc4da1d8fd Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 22 Dec 2024 17:12:42 -0300 Subject: [PATCH 298/481] Adjust syntax --- core/src/macros/mod.rs | 52 +++++++++ core/tests/lib.rs | 3 + core/tests/macros.rs | 53 +++++---- core/tests/macros_bootstrap.rs | 193 +++++++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 21 deletions(-) create mode 100644 core/tests/macros_bootstrap.rs diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 402b436d28e68..5c04e5a40df09 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -224,6 +224,7 @@ pub macro assert_matches { /// } /// } /// ``` +#[cfg(bootstrap)] #[unstable(feature = "cfg_match", issue = "115585")] #[rustc_diagnostic_item = "cfg_match"] pub macro cfg_match { @@ -284,6 +285,57 @@ pub macro cfg_match { } } +/// A macro for defining `#[cfg]` match-like statements. +/// +/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of +/// `#[cfg]` cases, emitting the implementation which matches first. +/// +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +/// without having to rewrite each clause multiple times. +/// +/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when +/// all previous declarations do not evaluate to true. +/// +/// # Example +/// +/// ``` +/// #![feature(cfg_match)] +/// +/// cfg_match! { +/// unix => { +/// fn foo() { /* unix specific functionality */ } +/// } +/// target_pointer_width = "32" => { +/// fn foo() { /* non-unix, 32-bit functionality */ } +/// } +/// _ => { +/// fn foo() { /* fallback implementation */ } +/// } +/// } +/// ``` +#[cfg(not(bootstrap))] +#[unstable(feature = "cfg_match", issue = "115585")] +#[rustc_diagnostic_item = "cfg_match"] +pub macro cfg_match { + ({ $($tt:tt)* }) => {{ + cfg_match! { $($tt)* } + }}, + (_ => { $($output:tt)* }) => { + $($output)* + }, + ( + $cfg:meta => $output:tt + $($( $rest:tt )+)? + ) => { + #[cfg($cfg)] + cfg_match! { _ => $output } + $( + #[cfg(not($cfg))] + cfg_match! { $($rest)+ } + )? + }, +} + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 18feee9fb2545..a8980c5f30aec 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -153,7 +153,10 @@ mod intrinsics; mod io; mod iter; mod lazy; +#[cfg(not(bootstrap))] mod macros; +#[cfg(bootstrap)] +mod macros_bootstrap; mod manually_drop; mod mem; mod net; diff --git a/core/tests/macros.rs b/core/tests/macros.rs index fdb4ea2941285..b30a40b7df28e 100644 --- a/core/tests/macros.rs +++ b/core/tests/macros.rs @@ -10,7 +10,7 @@ struct Struct; impl Trait for Struct { cfg_match! { - cfg(feature = "blah") => { + feature = "blah" => { fn blah(&self) { unimplemented!(); } @@ -47,21 +47,21 @@ fn matches_leading_pipe() { #[test] fn cfg_match_basic() { cfg_match! { - cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }} + target_pointer_width = "64" => { fn f0_() -> bool { true }} } cfg_match! { - cfg(unix) => { fn f1_() -> bool { true }} - cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }} + unix => { fn f1_() -> bool { true } } + any(target_os = "macos", target_os = "linux") => { fn f1_() -> bool { false }} } cfg_match! { - cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }} - cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }} + target_pointer_width = "32" => { fn f2_() -> bool { false } } + target_pointer_width = "64" => { fn f2_() -> bool { true } } } cfg_match! { - cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }} + target_pointer_width = "16" => { fn f3_() -> i32 { 1 } } _ => { fn f3_() -> i32 { 2 }} } @@ -83,7 +83,7 @@ fn cfg_match_basic() { #[test] fn cfg_match_debug_assertions() { cfg_match! { - cfg(debug_assertions) => { + debug_assertions => { assert!(cfg!(debug_assertions)); assert_eq!(4, 2+2); } @@ -98,13 +98,13 @@ fn cfg_match_debug_assertions() { #[test] fn cfg_match_no_duplication_on_64() { cfg_match! { - cfg(windows) => { + windows => { fn foo() {} } - cfg(unix) => { + unix => { fn foo() {} } - cfg(target_pointer_width = "64") => { + target_pointer_width = "64" => { fn foo() {} } } @@ -114,7 +114,7 @@ fn cfg_match_no_duplication_on_64() { #[test] fn cfg_match_options() { cfg_match! { - cfg(test) => { + test => { use core::option::Option as Option2; fn works1() -> Option2 { Some(1) } } @@ -122,26 +122,26 @@ fn cfg_match_options() { } cfg_match! { - cfg(feature = "foo") => { fn works2() -> bool { false } } - cfg(test) => { fn works2() -> bool { true } } + feature = "foo" => { fn works2() -> bool { false } } + test => { fn works2() -> bool { true } } _ => { fn works2() -> bool { false } } } cfg_match! { - cfg(feature = "foo") => { fn works3() -> bool { false } } + feature = "foo" => { fn works3() -> bool { false } } _ => { fn works3() -> bool { true } } } cfg_match! { - cfg(test) => { + test => { use core::option::Option as Option3; fn works4() -> Option3 { Some(1) } } } cfg_match! { - cfg(feature = "foo") => { fn works5() -> bool { false } } - cfg(test) => { fn works5() -> bool { true } } + feature = "foo" => { fn works5() -> bool { false } } + test => { fn works5() -> bool { true } } } assert!(works1().is_some()); @@ -154,7 +154,7 @@ fn cfg_match_options() { #[test] fn cfg_match_two_functions() { cfg_match! { - cfg(target_pointer_width = "64") => { + target_pointer_width = "64" => { fn foo1() {} fn bar1() {} } @@ -178,7 +178,7 @@ fn cfg_match_two_functions() { fn _accepts_expressions() -> i32 { cfg_match! { - cfg(unix) => { 1 } + unix => { 1 } _ => { 2 } } } @@ -189,7 +189,18 @@ fn _allows_stmt_expr_attributes() { let one = 1; let two = 2; cfg_match! { - cfg(unix) => { one * two; } + unix => { one * two; } _ => { one + two; } } } + +fn _expression() { + let _ = cfg_match!({ + windows => { + " XP" + } + _ => { + "" + } + }); +} diff --git a/core/tests/macros_bootstrap.rs b/core/tests/macros_bootstrap.rs new file mode 100644 index 0000000000000..f10ef862c5dd9 --- /dev/null +++ b/core/tests/macros_bootstrap.rs @@ -0,0 +1,193 @@ +#![allow(unused_must_use)] + +#[allow(dead_code)] +trait Trait { + fn blah(&self); +} + +#[allow(dead_code)] +struct Struct; + +impl Trait for Struct { + cfg_match! { + cfg(feature = "blah") => { + fn blah(&self) { + unimplemented!(); + } + } + _ => { + fn blah(&self) { + unimplemented!(); + } + } + } +} + +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} + +#[rustfmt::skip] +#[test] +fn matches_leading_pipe() { + matches!(1, | 1 | 2 | 3); +} + +#[test] +fn cfg_match_basic() { + cfg_match! { + cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }} + } + + cfg_match! { + cfg(unix) => { fn f1_() -> bool { true }} + cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }} + } + + cfg_match! { + cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }} + cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }} + } + + cfg_match! { + cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }} + _ => { fn f3_() -> i32 { 2 }} + } + + #[cfg(target_pointer_width = "64")] + assert!(f0_()); + + #[cfg(unix)] + assert!(f1_()); + + #[cfg(target_pointer_width = "32")] + assert!(!f2_()); + #[cfg(target_pointer_width = "64")] + assert!(f2_()); + + #[cfg(not(target_pointer_width = "16"))] + assert_eq!(f3_(), 2); +} + +#[test] +fn cfg_match_debug_assertions() { + cfg_match! { + cfg(debug_assertions) => { + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } + _ => { + assert!(cfg!(not(debug_assertions))); + assert_eq!(10, 5+5); + } + } +} + +#[cfg(target_pointer_width = "64")] +#[test] +fn cfg_match_no_duplication_on_64() { + cfg_match! { + cfg(windows) => { + fn foo() {} + } + cfg(unix) => { + fn foo() {} + } + cfg(target_pointer_width = "64") => { + fn foo() {} + } + } + foo(); +} + +#[test] +fn cfg_match_options() { + cfg_match! { + cfg(test) => { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } + _ => { fn works1() -> Option { None } } + } + + cfg_match! { + cfg(feature = "foo") => { fn works2() -> bool { false } } + cfg(test) => { fn works2() -> bool { true } } + _ => { fn works2() -> bool { false } } + } + + cfg_match! { + cfg(feature = "foo") => { fn works3() -> bool { false } } + _ => { fn works3() -> bool { true } } + } + + cfg_match! { + cfg(test) => { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_match! { + cfg(feature = "foo") => { fn works5() -> bool { false } } + cfg(test) => { fn works5() -> bool { true } } + } + + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); +} + +#[test] +fn cfg_match_two_functions() { + cfg_match! { + cfg(target_pointer_width = "64") => { + fn foo1() {} + fn bar1() {} + } + _ => { + fn foo2() {} + fn bar2() {} + } + } + + #[cfg(target_pointer_width = "64")] + { + foo1(); + bar1(); + } + #[cfg(not(target_pointer_width = "64"))] + { + foo2(); + bar2(); + } +} + +fn _accepts_expressions() -> i32 { + cfg_match! { + cfg(unix) => { 1 } + _ => { 2 } + } +} + +fn _allows_stmt_expr_attributes() { + let one = 1; + let two = 2; + cfg_match! { + cfg(unix) => { one * two; } + _ => { one + two; } + } +} From 402c93a38cec0406b87df902eead9447be8ff795 Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Thu, 19 Dec 2024 13:54:37 +0800 Subject: [PATCH 299/481] Add missing safety descriptions to Arc's 'from_raw','increment_strong_count','decrement_strong_count' --- alloc/src/sync.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 11e7128e67771..33cab6aab9fdc 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -1397,6 +1397,8 @@ impl Arc { /// different types. See [`mem::transmute`][transmute] for more information /// on what restrictions apply in this case. /// + /// The raw pointer must point to a block of memory allocated by the global allocator + /// /// The user of `from_raw` has to make sure a specific value of `T` is only /// dropped once. /// @@ -1452,7 +1454,8 @@ impl Arc { /// /// The pointer must have been obtained through `Arc::into_raw`, and the /// associated `Arc` instance must be valid (i.e. the strong count must be at - /// least 1) for the duration of this method. + /// least 1) for the duration of this method, and `ptr` must point to a block of memory + /// allocated by the global allocator. /// /// # Examples /// @@ -1486,7 +1489,8 @@ impl Arc { /// /// The pointer must have been obtained through `Arc::into_raw`, and the /// associated `Arc` instance must be valid (i.e. the strong count must be at - /// least 1) when invoking this method. This method can be used to release the final + /// least 1) when invoking this method, and `ptr` must point to a block of memory + /// allocated by the global allocator. This method can be used to release the final /// `Arc` and backing storage, but **should not** be called after the final `Arc` has been /// released. /// From 634b557597e961a299a7d04535eb19e9d136de23 Mon Sep 17 00:00:00 2001 From: ClearLove <98693523+DiuDiu777@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:16:43 +0800 Subject: [PATCH 300/481] fix typo in library/alloc/src/sync.rs Co-authored-by: Ibraheem Ahmed --- alloc/src/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 33cab6aab9fdc..8eee7cff2080d 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -1397,7 +1397,7 @@ impl Arc { /// different types. See [`mem::transmute`][transmute] for more information /// on what restrictions apply in this case. /// - /// The raw pointer must point to a block of memory allocated by the global allocator + /// The raw pointer must point to a block of memory allocated by the global allocator. /// /// The user of `from_raw` has to make sure a specific value of `T` is only /// dropped once. From 1d313962b06bad4c6480b1680e1bb9a27852a5e1 Mon Sep 17 00:00:00 2001 From: Aeon <165953379+AeonSolstice@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:08:22 -0500 Subject: [PATCH 301/481] Clarify note in `std::sync::LazyLock` example --- std/src/sync/lazy_lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sync/lazy_lock.rs b/std/src/sync/lazy_lock.rs index 1e4f9b79e0f4a..98c83d8d326ca 100644 --- a/std/src/sync/lazy_lock.rs +++ b/std/src/sync/lazy_lock.rs @@ -31,7 +31,7 @@ union Data { /// ``` /// use std::sync::LazyLock; /// -/// // n.b. static items do not call [`Drop`] on program termination, so this won't be deallocated. +/// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated. /// // this is fine, as the OS can deallocate the terminated program faster than we can free memory /// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional. /// static DEEP_THOUGHT: LazyLock = LazyLock::new(|| { From d7e31757eeeb525919c35f0d162d091528619112 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 17 Jan 2025 01:30:05 +1100 Subject: [PATCH 302/481] Move `std::pipe::*` into `std::io` Signed-off-by: Jiahao XU --- std/src/io/mod.rs | 249 +++++++++++++++++++++ std/src/io/tests.rs | 17 ++ std/src/lib.rs | 2 - std/src/pipe.rs | 258 ---------------------- std/src/pipe/tests.rs | 19 -- std/src/sys/anonymous_pipe/unix.rs | 3 +- std/src/sys/anonymous_pipe/unsupported.rs | 3 +- std/src/sys/anonymous_pipe/windows.rs | 4 +- std/tests/pipe_subprocess.rs | 3 +- 9 files changed, 271 insertions(+), 287 deletions(-) delete mode 100644 std/src/pipe.rs delete mode 100644 std/src/pipe/tests.rs diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 7912f969bbd9f..231c8712ebd55 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -330,6 +330,7 @@ pub use self::{ }; use crate::mem::take; use crate::ops::{Deref, DerefMut}; +use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::{cmp, fmt, slice, str, sys}; mod buffered; @@ -3250,3 +3251,251 @@ impl Iterator for Lines { } } } + +/// Create anonymous pipe that is close-on-exec and blocking. +/// +/// # Behavior +/// +/// A pipe is a synchronous, unidirectional data channel between two or more processes, like an +/// interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular: +/// +/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. +/// * A write on a [`PipeWriter`] blocks when the pipe is full. +/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] +/// returns EOF. +/// * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. +/// +/// # Capacity +/// +/// Pipe capacity is platform dependent. To quote the Linux [man page]: +/// +/// > Different implementations have different limits for the pipe capacity. Applications should +/// > not rely on a particular capacity: an application should be designed so that a reading process +/// > consumes data as soon as it is available, so that a writing process does not remain blocked. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(anonymous_pipe)] +/// # #[cfg(miri)] fn main() {} +/// # #[cfg(not(miri))] +/// # fn main() -> std::io::Result<()> { +/// # use std::process::Command; +/// # use std::io::{Read, Write}; +/// let (ping_rx, mut ping_tx) = std::io::pipe()?; +/// let (mut pong_rx, pong_tx) = std::io::pipe()?; +/// +/// // Spawn a process that echoes its input. +/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; +/// +/// ping_tx.write_all(b"hello")?; +/// // Close to unblock echo_server's reader. +/// drop(ping_tx); +/// +/// let mut buf = String::new(); +/// // Block until echo_server's writer is closed. +/// pong_rx.read_to_string(&mut buf)?; +/// assert_eq!(&buf, "hello"); +/// +/// echo_server.wait()?; +/// # Ok(()) +/// # } +/// ``` +/// [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html +/// [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe +/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[inline] +pub fn pipe() -> Result<(PipeReader, PipeWriter)> { + pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) +} + +/// Read end of the anonymous pipe. +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[derive(Debug)] +pub struct PipeReader(pub(crate) AnonPipe); + +/// Write end of the anonymous pipe. +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[derive(Debug)] +pub struct PipeWriter(pub(crate) AnonPipe); + +impl PipeReader { + /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::fs; + /// # use std::io::Write; + /// # use std::process::Command; + /// const NUM_SLOT: u8 = 2; + /// const NUM_PROC: u8 = 5; + /// const OUTPUT: &str = "work.txt"; + /// + /// let mut jobs = vec![]; + /// let (reader, mut writer) = std::io::pipe()?; + /// + /// // Write NUM_SLOT characters the pipe. + /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; + /// + /// // Spawn several processes that read a character from the pipe, do some work, then + /// // write back to the pipe. When the pipe is empty, the processes block, so only + /// // NUM_SLOT processes can be working at any given time. + /// for _ in 0..NUM_PROC { + /// jobs.push( + /// Command::new("bash") + /// .args(["-c", + /// &format!( + /// "read -n 1\n\ + /// echo -n 'x' >> '{OUTPUT}'\n\ + /// echo -n '|'", + /// ), + /// ]) + /// .stdin(reader.try_clone()?) + /// .stdout(writer.try_clone()?) + /// .spawn()?, + /// ); + /// } + /// + /// // Wait for all jobs to finish. + /// for mut job in jobs { + /// job.wait()?; + /// } + /// + /// // Check our work and clean up. + /// let xs = fs::read_to_string(OUTPUT)?; + /// fs::remove_file(OUTPUT)?; + /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "anonymous_pipe", issue = "127154")] + pub fn try_clone(&self) -> Result { + self.0.try_clone().map(Self) + } +} + +impl PipeWriter { + /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::process::Command; + /// # use std::io::Read; + /// let (mut reader, writer) = std::io::pipe()?; + /// + /// // Spawn a process that writes to stdout and stderr. + /// let mut peer = Command::new("bash") + /// .args([ + /// "-c", + /// "echo -n foo\n\ + /// echo -n bar >&2" + /// ]) + /// .stdout(writer.try_clone()?) + /// .stderr(writer) + /// .spawn()?; + /// + /// // Read and check the result. + /// let mut msg = String::new(); + /// reader.read_to_string(&mut msg)?; + /// assert_eq!(&msg, "foobar"); + /// + /// peer.wait()?; + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "anonymous_pipe", issue = "127154")] + pub fn try_clone(&self) -> Result { + self.0.try_clone().map(Self) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl Read for &PipeReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + self.0.read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + self.0.read_to_end(buf) + } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { + self.0.read_buf(buf) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl Read for PipeReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + self.0.read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + self.0.read_to_end(buf) + } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { + self.0.read_buf(buf) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl Write for &PipeWriter { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl Write for PipeWriter { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } +} diff --git a/std/src/io/tests.rs b/std/src/io/tests.rs index 47cbb9614afdd..85098b3bb181f 100644 --- a/std/src/io/tests.rs +++ b/std/src/io/tests.rs @@ -823,3 +823,20 @@ fn try_oom_error() { let io_err = io::Error::from(reserve_err); assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind()); } + +#[test] +#[cfg(all(windows, unix, not(miri)))] +fn pipe_creation_clone_and_rw() { + let (rx, tx) = std::io::pipe().unwrap(); + + tx.try_clone().unwrap().write_all(b"12345").unwrap(); + drop(tx); + + let mut rx2 = rx.try_clone().unwrap(); + drop(rx); + + let mut s = String::new(); + rx2.read_to_string(&mut s).unwrap(); + drop(rx2); + assert_eq!(s, "12345"); +} diff --git a/std/src/lib.rs b/std/src/lib.rs index 5c12236617c98..38d7ecc736392 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -596,8 +596,6 @@ pub mod panic; #[unstable(feature = "pattern_type_macro", issue = "123646")] pub mod pat; pub mod path; -#[unstable(feature = "anonymous_pipe", issue = "127154")] -pub mod pipe; pub mod process; #[unstable(feature = "random", issue = "130703")] pub mod random; diff --git a/std/src/pipe.rs b/std/src/pipe.rs deleted file mode 100644 index 913c22588a76c..0000000000000 --- a/std/src/pipe.rs +++ /dev/null @@ -1,258 +0,0 @@ -//! A cross-platform anonymous pipe. -//! -//! This module provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on -//! Windows. -//! -//! # Behavior -//! -//! A pipe is a synchronous, unidirectional data channel between two or more processes, like an -//! interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular: -//! -//! * A read on a [`PipeReader`] blocks until the pipe is non-empty. -//! * A write on a [`PipeWriter`] blocks when the pipe is full. -//! * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] -//! returns EOF. -//! * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. -//! -//! # Capacity -//! -//! Pipe capacity is platform dependent. To quote the Linux [man page]: -//! -//! > Different implementations have different limits for the pipe capacity. Applications should -//! > not rely on a particular capacity: an application should be designed so that a reading process -//! > consumes data as soon as it is available, so that a writing process does not remain blocked. -//! -//! # Examples -//! -//! ```no_run -//! #![feature(anonymous_pipe)] -//! # #[cfg(miri)] fn main() {} -//! # #[cfg(not(miri))] -//! # fn main() -> std::io::Result<()> { -//! # use std::process::Command; -//! # use std::io::{Read, Write}; -//! let (ping_rx, mut ping_tx) = std::pipe::pipe()?; -//! let (mut pong_rx, pong_tx) = std::pipe::pipe()?; -//! -//! // Spawn a process that echoes its input. -//! let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; -//! -//! ping_tx.write_all(b"hello")?; -//! // Close to unblock echo_server's reader. -//! drop(ping_tx); -//! -//! let mut buf = String::new(); -//! // Block until echo_server's writer is closed. -//! pong_rx.read_to_string(&mut buf)?; -//! assert_eq!(&buf, "hello"); -//! -//! echo_server.wait()?; -//! # Ok(()) -//! # } -//! ``` -//! [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html -//! [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe -//! [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -use crate::io; -use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; - -/// Create anonymous pipe that is close-on-exec and blocking. -/// -/// # Examples -/// -/// See the [module-level](crate::pipe) documentation for examples. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[inline] -pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { - pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) -} - -/// Read end of the anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeReader(pub(crate) AnonPipe); - -/// Write end of the anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeWriter(pub(crate) AnonPipe); - -impl PipeReader { - /// Create a new [`PipeReader`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::fs; - /// # use std::io::Write; - /// # use std::process::Command; - /// const NUM_SLOT: u8 = 2; - /// const NUM_PROC: u8 = 5; - /// const OUTPUT: &str = "work.txt"; - /// - /// let mut jobs = vec![]; - /// let (reader, mut writer) = std::pipe::pipe()?; - /// - /// // Write NUM_SLOT characters the pipe. - /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; - /// - /// // Spawn several processes that read a character from the pipe, do some work, then - /// // write back to the pipe. When the pipe is empty, the processes block, so only - /// // NUM_SLOT processes can be working at any given time. - /// for _ in 0..NUM_PROC { - /// jobs.push( - /// Command::new("bash") - /// .args(["-c", - /// &format!( - /// "read -n 1\n\ - /// echo -n 'x' >> '{OUTPUT}'\n\ - /// echo -n '|'", - /// ), - /// ]) - /// .stdin(reader.try_clone()?) - /// .stdout(writer.try_clone()?) - /// .spawn()?, - /// ); - /// } - /// - /// // Wait for all jobs to finish. - /// for mut job in jobs { - /// job.wait()?; - /// } - /// - /// // Check our work and clean up. - /// let xs = fs::read_to_string(OUTPUT)?; - /// fs::remove_file(OUTPUT)?; - /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> io::Result { - self.0.try_clone().map(Self) - } -} - -impl PipeWriter { - /// Create a new [`PipeWriter`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::process::Command; - /// # use std::io::Read; - /// let (mut reader, writer) = std::pipe::pipe()?; - /// - /// // Spawn a process that writes to stdout and stderr. - /// let mut peer = Command::new("bash") - /// .args([ - /// "-c", - /// "echo -n foo\n\ - /// echo -n bar >&2" - /// ]) - /// .stdout(writer.try_clone()?) - /// .stderr(writer) - /// .spawn()?; - /// - /// // Read and check the result. - /// let mut msg = String::new(); - /// reader.read_to_string(&mut msg)?; - /// assert_eq!(&msg, "foobar"); - /// - /// peer.wait()?; - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> io::Result { - self.0.try_clone().map(Self) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl io::Read for &PipeReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl io::Read for PipeReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl io::Write for &PipeWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl io::Write for PipeWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} diff --git a/std/src/pipe/tests.rs b/std/src/pipe/tests.rs deleted file mode 100644 index 9c38e10678752..0000000000000 --- a/std/src/pipe/tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::io::{Read, Write}; -use crate::pipe::pipe; - -#[test] -#[cfg(all(windows, unix, not(miri)))] -fn pipe_creation_clone_and_rw() { - let (rx, tx) = pipe().unwrap(); - - tx.try_clone().unwrap().write_all(b"12345").unwrap(); - drop(tx); - - let mut rx2 = rx.try_clone().unwrap(); - drop(rx); - - let mut s = String::new(); - rx2.read_to_string(&mut s).unwrap(); - drop(rx2); - assert_eq!(s, "12345"); -} diff --git a/std/src/sys/anonymous_pipe/unix.rs b/std/src/sys/anonymous_pipe/unix.rs index 9168024730e67..9e398765634b7 100644 --- a/std/src/sys/anonymous_pipe/unix.rs +++ b/std/src/sys/anonymous_pipe/unix.rs @@ -1,6 +1,5 @@ -use crate::io; +use crate::io::{self, PipeReader, PipeWriter}; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::pipe::{PipeReader, PipeWriter}; use crate::process::Stdio; use crate::sys::fd::FileDesc; use crate::sys::pipe::anon_pipe; diff --git a/std/src/sys/anonymous_pipe/unsupported.rs b/std/src/sys/anonymous_pipe/unsupported.rs index dd51e70315e96..4e79ac9c21aad 100644 --- a/std/src/sys/anonymous_pipe/unsupported.rs +++ b/std/src/sys/anonymous_pipe/unsupported.rs @@ -1,5 +1,4 @@ -use crate::io; -use crate::pipe::{PipeReader, PipeWriter}; +use crate::io::{self, PipeReader, PipeWriter}; use crate::process::Stdio; pub use crate::sys::pipe::AnonPipe; diff --git a/std/src/sys/anonymous_pipe/windows.rs b/std/src/sys/anonymous_pipe/windows.rs index a48198f8a812b..eb7fa8ec1c9a1 100644 --- a/std/src/sys/anonymous_pipe/windows.rs +++ b/std/src/sys/anonymous_pipe/windows.rs @@ -1,12 +1,12 @@ +use crate::io::{self, PipeReader, PipeWriter}; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, }; -use crate::pipe::{PipeReader, PipeWriter}; use crate::process::Stdio; +use crate::ptr; use crate::sys::c; use crate::sys::handle::Handle; use crate::sys_common::{FromInner, IntoInner}; -use crate::{io, ptr}; pub type AnonPipe = Handle; diff --git a/std/tests/pipe_subprocess.rs b/std/tests/pipe_subprocess.rs index 1535742a83a21..df946cdcf2b70 100644 --- a/std/tests/pipe_subprocess.rs +++ b/std/tests/pipe_subprocess.rs @@ -3,8 +3,7 @@ fn main() { #[cfg(all(not(miri), any(unix, windows)))] { - use std::io::Read; - use std::pipe::pipe; + use std::io::{Read, pipe}; use std::{env, process}; if env::var("I_AM_THE_CHILD").is_ok() { From f7430ec31eefdff615224aef2c8d12c20a6d6d47 Mon Sep 17 00:00:00 2001 From: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Date: Fri, 17 Jan 2025 01:45:14 +1100 Subject: [PATCH 303/481] Fix import of pipe in kernel_copy.rs Signed-off-by: Jiahao XU --- std/src/sys/pal/unix/kernel_copy.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/std/src/sys/pal/unix/kernel_copy.rs b/std/src/sys/pal/unix/kernel_copy.rs index 36823a503b17c..bbf29f3252341 100644 --- a/std/src/sys/pal/unix/kernel_copy.rs +++ b/std/src/sys/pal/unix/kernel_copy.rs @@ -52,15 +52,14 @@ use crate::cmp::min; use crate::fs::{File, Metadata}; use crate::io::copy::generic_copy; use crate::io::{ - BufRead, BufReader, BufWriter, Error, Read, Result, StderrLock, StdinLock, StdoutLock, Take, - Write, + BufRead, BufReader, BufWriter, Error, PipeReader, PipeWriter, Read, Result, StderrLock, + StdinLock, StdoutLock, Take, Write, }; use crate::mem::ManuallyDrop; use crate::net::TcpStream; use crate::os::unix::fs::FileTypeExt; use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use crate::os::unix::net::UnixStream; -use crate::pipe::{PipeReader, PipeWriter}; use crate::process::{ChildStderr, ChildStdin, ChildStdout}; use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; From 03904629a16f3a306a27d6c311eaab84160c93e4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 Jan 2025 22:47:24 +0000 Subject: [PATCH 304/481] Stabilize `float_next_up_down` FCP completed at [1]. Closes https://github.com/rust-lang/rust/issues/91399 [1]: https://github.com/rust-lang/rust/issues/91399#issuecomment-2598734570 --- core/src/num/f128.rs | 4 ---- core/src/num/f16.rs | 4 ---- core/src/num/f32.rs | 8 ++++---- core/src/num/f64.rs | 8 ++++---- std/src/lib.rs | 1 - 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/core/src/num/f128.rs b/core/src/num/f128.rs index 4ebeaf046114a..212007d84befb 100644 --- a/core/src/num/f128.rs +++ b/core/src/num/f128.rs @@ -504,7 +504,6 @@ impl f128 { /// /// ```rust /// #![feature(f128)] - /// #![feature(float_next_up_down)] /// # // FIXME(f16_f128): remove when `eqtf2` is available /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// @@ -522,7 +521,6 @@ impl f128 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "f128", issue = "116909")] - // #[unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -558,7 +556,6 @@ impl f128 { /// /// ```rust /// #![feature(f128)] - /// #![feature(float_next_up_down)] /// # // FIXME(f16_f128): remove when `eqtf2` is available /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// @@ -576,7 +573,6 @@ impl f128 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "f128", issue = "116909")] - // #[unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index c82f0d7cd4ad5..fa06a33523e27 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -497,7 +497,6 @@ impl f16 { /// /// ```rust /// #![feature(f16)] - /// #![feature(float_next_up_down)] /// # // FIXME(f16_f128): ABI issues on MSVC /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// @@ -515,7 +514,6 @@ impl f16 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "f16", issue = "116909")] - // #[unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -551,7 +549,6 @@ impl f16 { /// /// ```rust /// #![feature(f16)] - /// #![feature(float_next_up_down)] /// # // FIXME(f16_f128): ABI issues on MSVC /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// @@ -569,7 +566,6 @@ impl f16 { /// [`MAX`]: Self::MAX #[inline] #[unstable(feature = "f16", issue = "116909")] - // #[unstable(feature = "float_next_up_down", issue = "91399")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index 2b6adef65e94a..a9f413c260384 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -726,7 +726,6 @@ impl f32 { /// is finite `x == x.next_up().next_down()` also holds. /// /// ```rust - /// #![feature(float_next_up_down)] /// // f32::EPSILON is the difference between 1.0 and the next number up. /// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON); /// // But not for most numbers. @@ -739,7 +738,8 @@ impl f32 { /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] - #[unstable(feature = "float_next_up_down", issue = "91399")] + #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -774,7 +774,6 @@ impl f32 { /// is finite `x == x.next_down().next_up()` also holds. /// /// ```rust - /// #![feature(float_next_up_down)] /// let x = 1.0f32; /// // Clamp value into range [0, 1). /// let clamped = x.clamp(0.0, 1.0f32.next_down()); @@ -787,7 +786,8 @@ impl f32 { /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] - #[unstable(feature = "float_next_up_down", issue = "91399")] + #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 037b3afa6c46c..77594a653cc8b 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -743,7 +743,6 @@ impl f64 { /// is finite `x == x.next_up().next_down()` also holds. /// /// ```rust - /// #![feature(float_next_up_down)] /// // f64::EPSILON is the difference between 1.0 and the next number up. /// assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON); /// // But not for most numbers. @@ -756,7 +755,8 @@ impl f64 { /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] - #[unstable(feature = "float_next_up_down", issue = "91399")] + #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -791,7 +791,6 @@ impl f64 { /// is finite `x == x.next_down().next_up()` also holds. /// /// ```rust - /// #![feature(float_next_up_down)] /// let x = 1.0f64; /// // Clamp value into range [0, 1). /// let clamped = x.clamp(0.0, 1.0f64.next_down()); @@ -804,7 +803,8 @@ impl f64 { /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] - #[unstable(feature = "float_next_up_down", issue = "91399")] + #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here diff --git a/std/src/lib.rs b/std/src/lib.rs index 38d7ecc736392..39f234e4ba661 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -333,7 +333,6 @@ #![feature(extend_one)] #![feature(float_gamma)] #![feature(float_minimum_maximum)] -#![feature(float_next_up_down)] #![feature(fmt_internals)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] From a2154d7c3edb087a95b46b36b0766ff68936b79b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 Jan 2025 22:52:50 +0000 Subject: [PATCH 305/481] Add references to the IEEE functions for `float_next_up_down` Mention the IEEE function by name and create a doc alias of the same. --- core/src/num/f128.rs | 6 ++++++ core/src/num/f16.rs | 6 ++++++ core/src/num/f32.rs | 6 ++++++ core/src/num/f64.rs | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/core/src/num/f128.rs b/core/src/num/f128.rs index 212007d84befb..8fb1588e60b35 100644 --- a/core/src/num/f128.rs +++ b/core/src/num/f128.rs @@ -515,11 +515,14 @@ impl f128 { /// # } /// ``` /// + /// This operation corresponds to IEEE-754 `nextUp`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextUp")] #[unstable(feature = "f128", issue = "116909")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing @@ -567,11 +570,14 @@ impl f128 { /// # } /// ``` /// + /// This operation corresponds to IEEE-754 `nextDown`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextDown")] #[unstable(feature = "f128", issue = "116909")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index fa06a33523e27..8c2af74b8f842 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -508,11 +508,14 @@ impl f16 { /// # } /// ``` /// + /// This operation corresponds to IEEE-754 `nextUp`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextUp")] #[unstable(feature = "f16", issue = "116909")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing @@ -560,11 +563,14 @@ impl f16 { /// # } /// ``` /// + /// This operation corresponds to IEEE-754 `nextDown`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextDown")] #[unstable(feature = "f16", issue = "116909")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index a9f413c260384..817bedbd44f98 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -733,11 +733,14 @@ impl f32 { /// assert_eq!(16777216f32.next_up(), 16777218.0); /// ``` /// + /// This operation corresponds to IEEE-754 `nextUp`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextUp")] #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_up(self) -> Self { @@ -781,11 +784,14 @@ impl f32 { /// assert_eq!(clamped.next_up(), 1.0); /// ``` /// + /// This operation corresponds to IEEE-754 `nextDown`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextDown")] #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_down(self) -> Self { diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 77594a653cc8b..1b0651a0def07 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -750,11 +750,14 @@ impl f64 { /// assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0); /// ``` /// + /// This operation corresponds to IEEE-754 `nextUp`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextUp")] #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_up(self) -> Self { @@ -798,11 +801,14 @@ impl f64 { /// assert_eq!(clamped.next_up(), 1.0); /// ``` /// + /// This operation corresponds to IEEE-754 `nextDown`. + /// /// [`NEG_INFINITY`]: Self::NEG_INFINITY /// [`INFINITY`]: Self::INFINITY /// [`MIN`]: Self::MIN /// [`MAX`]: Self::MAX #[inline] + #[doc(alias = "nextDown")] #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] pub const fn next_down(self) -> Self { From 916aaf92a9a14b416f4f9c22be7cec0b9e4984aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sat, 18 Jan 2025 22:08:38 +0000 Subject: [PATCH 306/481] Revert "Auto merge of #134330 - scottmcm:no-more-rvalue-len, r=matthewjasper" This reverts commit 0a7f3c61f09a984d3e98caebbf7eef17400bf494, reversing changes made to 83157152c1ce77f41657498a27a200f366a4c2a4. --- core/src/intrinsics/mir.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/intrinsics/mir.rs b/core/src/intrinsics/mir.rs index 834f44c7790d9..55dcf7cd47e97 100644 --- a/core/src/intrinsics/mir.rs +++ b/core/src/intrinsics/mir.rs @@ -233,7 +233,7 @@ //! //! - Operands implicitly convert to `Use` rvalues. //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. -//! - [`Discriminant`] and [`CopyForDeref`] have associated functions. +//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions. //! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. //! - The binary operation `Offset` can be created via [`Offset`]. //! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. @@ -401,6 +401,7 @@ define!("mir_storage_dead", fn StorageDead(local: T)); define!("mir_assume", fn Assume(operand: bool)); define!("mir_deinit", fn Deinit(place: T)); define!("mir_checked", fn Checked(binop: T) -> (T, bool)); +define!("mir_len", fn Len(place: T) -> usize); define!( "mir_ptr_metadata", fn PtrMetadata(place: *const P) ->

::Metadata From 288c7ff2150746659935d12c6f7a35ed32c5d0dd Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Tue, 31 Dec 2024 09:46:37 -0700 Subject: [PATCH 307/481] Improve `select_nth_unstable` documentation clarity * Instead uses `before` and `after` variable names in the example where `greater` and `lesser` are flipped. * Uses `<=` and `>=` instead of "less than or equal to" and "greater than or equal to" to make the docs more concise. * General attempt to remove unnecessary words and be more precise. For example it seems slightly wrong to say "its final sorted position", since this implies there is only one sorted position for this element. --- core/src/slice/mod.rs | 82 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 5a22110880cc5..0eda7aa82dbdb 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3071,19 +3071,18 @@ impl [T] { sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); } - /// Reorders the slice such that the element at `index` after the reordering is at its final - /// sorted position. + /// Reorders the slice such that the element at `index` is at a sort-order position. All + /// elements before `index` will then be `<=` this value, and all elements after will be `>=`. /// - /// This reordering has the additional property that any value at position `i < index` will be - /// less than or equal to any value at a position `j > index`. Additionally, this reordering is - /// unstable (i.e. any number of equal elements may end up at position `index`), in-place (i.e. - /// does not allocate), and runs in *O*(*n*) time. This function is also known as "kth element" - /// in other libraries. + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: /// - /// It returns a triplet of the following from the reordered slice: the subslice prior to - /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in - /// those two subslices will respectively all be less-than-or-equal-to and - /// greater-than-or-equal-to the value of the element at `index`. + /// * The unsorted subslice before `index` (elements all pass `x <= self[index]`) + /// * The element at `index` + /// * The unsorted subslice after `index` (elements all pass `x >= self[index]`) /// /// # Current implementation /// @@ -3096,7 +3095,7 @@ impl [T] { /// /// # Panics /// - /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// Panics when `index >= len()`, and so always panics on empty slices. /// /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. /// @@ -3105,8 +3104,7 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the items less than or equal to the median, the median, and greater than or equal to - /// // the median. + /// // Find the items `<=` the median, the median, and `>=` the median. /// let (lesser, median, greater) = v.select_nth_unstable(2); /// /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); @@ -3132,19 +3130,19 @@ impl [T] { sort::select::partition_at_index(self, index, T::lt) } - /// Reorders the slice with a comparator function such that the element at `index` after the - /// reordering is at its final sorted position. + /// Reorders the slice with a comparator function such that the element at `index` is at a + /// sort-order position. All elements before `index` will then be `<=` this value, and all + /// elements after will be `>=` according to the comparator function. /// - /// This reordering has the additional property that any value at position `i < index` will be - /// less than or equal to any value at a position `j > index` using the comparator function. - /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This /// function is also known as "kth element" in other libraries. /// - /// It returns a triplet of the following from the slice reordered according to the provided - /// comparator function: the subslice prior to `index`, the element at `index`, and the subslice - /// after `index`; accordingly, the values in those two subslices will respectively all be - /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`. + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index` (elements all pass `compare(x, self[index]).is_le()`) + /// * The element at `index` + /// * The unsorted subslice after `index` (elements all pass `compare(x, self[index]).is_ge()`) /// /// # Current implementation /// @@ -3157,7 +3155,7 @@ impl [T] { /// /// # Panics /// - /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// Panics when `index >= len()`, and so always panics on empty slices. /// /// May panic if `compare` does not implement a [total order]. /// @@ -3166,13 +3164,13 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the items less than or equal to the median, the median, and greater than or equal to - /// // the median as if the slice were sorted in descending order. - /// let (lesser, median, greater) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// // Find the items `>=` the median, the median, and `<=` the median, by using a reversed + /// // comparator. + /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); /// - /// assert!(lesser == [4, 2] || lesser == [2, 4]); + /// assert!(before == [4, 2] || before == [2, 4]); /// assert_eq!(median, &mut 1); - /// assert!(greater == [-3, -5] || greater == [-5, -3]); + /// assert!(after == [-3, -5] || after == [-5, -3]); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -3197,19 +3195,19 @@ impl [T] { sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) } - /// Reorders the slice with a key extraction function such that the element at `index` after the - /// reordering is at its final sorted position. + /// Reorders the slice with a key extraction function such that the element at `index` is at a + /// sort-order position. All elements before `index` will have keys `<=` the key at `index`, and + /// all elements after will have keys `>=`. /// - /// This reordering has the additional property that any value at position `i < index` will be - /// less than or equal to any value at a position `j > index` using the key extraction function. - /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This /// function is also known as "kth element" in other libraries. /// - /// It returns a triplet of the following from the slice reordered according to the provided key - /// extraction function: the subslice prior to `index`, the element at `index`, and the subslice - /// after `index`; accordingly, the values in those two subslices will respectively all be - /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`. + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index` (elements all pass `f(x) <= f(self[index])`) + /// * The element at `index` + /// * The unsorted subslice after `index` (elements all pass `f(x) >= f(self[index])`) /// /// # Current implementation /// @@ -3231,8 +3229,8 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 1, -3, 2]; /// - /// // Find the items less than or equal to the median, the median, and greater than or equal to - /// // the median as if the slice were sorted according to absolute value. + /// // Find the items <= the median absolute value, the median absolute value, and >= the median + /// // absolute value. /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); /// /// assert!(lesser == [1, 2] || lesser == [2, 1]); From 34250e6492bb3174c09810ac9b99c67ca093db96 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 14:52:16 -0700 Subject: [PATCH 308/481] `then be` -> `be` based on feedback from @ibraheemdev --- core/src/slice/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 0eda7aa82dbdb..50e714c3a365a 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3072,7 +3072,7 @@ impl [T] { } /// Reorders the slice such that the element at `index` is at a sort-order position. All - /// elements before `index` will then be `<=` this value, and all elements after will be `>=`. + /// elements before `index` will be `<=` this value, and all elements after will be `>=`. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This @@ -3131,8 +3131,8 @@ impl [T] { } /// Reorders the slice with a comparator function such that the element at `index` is at a - /// sort-order position. All elements before `index` will then be `<=` this value, and all - /// elements after will be `>=` according to the comparator function. + /// sort-order position. All elements before `index` will be `<=` this value, and all elements + /// after will be `>=` according to the comparator function. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This From 1565e6aa5279f4ad6eccbd12d329813b02712a8f Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:32:47 -0700 Subject: [PATCH 309/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 50e714c3a365a..8c6f830bb6c6d 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3131,8 +3131,8 @@ impl [T] { } /// Reorders the slice with a comparator function such that the element at `index` is at a - /// sort-order position. All elements before `index` will be `<=` this value, and all elements - /// after will be `>=` according to the comparator function. + /// sort-order position. All elements before `index` will be `<=` to this value, and all elements + /// after will be `>=` to it, according to the comparator function. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This From 9eb40d82686a98db2d1e41f1750c46110240a3ea Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:33:02 -0700 Subject: [PATCH 310/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 8c6f830bb6c6d..e0f273b0091ad 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3104,7 +3104,7 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the items `<=` the median, the median, and `>=` the median. + /// // Find the items `<=` to the median, the median itself, and the items `>=` to it. /// let (lesser, median, greater) = v.select_nth_unstable(2); /// /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); From d6f56c475089137a9f17f7891d42ff0a5eccfe75 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:33:23 -0700 Subject: [PATCH 311/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index e0f273b0091ad..4cd929cadf2ab 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3080,9 +3080,9 @@ impl [T] { /// /// Returns a triple partitioning the reordered slice: /// - /// * The unsorted subslice before `index` (elements all pass `x <= self[index]`) - /// * The element at `index` - /// * The unsorted subslice after `index` (elements all pass `x >= self[index]`) + /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. + /// * The element at `index`. + /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. /// /// # Current implementation /// From fa5ca284936e943571359998e4e82d20764795c2 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:33:33 -0700 Subject: [PATCH 312/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 4cd929cadf2ab..0b739e0d6c103 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3078,7 +3078,7 @@ impl [T] { /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This /// function is also known as "kth element" in other libraries. /// - /// Returns a triple partitioning the reordered slice: + /// Returns a triple that partitions the reordered slice: /// /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. /// * The element at `index`. From e0fa01d1b5a8dbef9c02357f079201ba93ad6da7 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:33:42 -0700 Subject: [PATCH 313/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 0b739e0d6c103..9ec939abe3963 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3072,7 +3072,7 @@ impl [T] { } /// Reorders the slice such that the element at `index` is at a sort-order position. All - /// elements before `index` will be `<=` this value, and all elements after will be `>=`. + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to it. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This From 4b4bdfb08a6065b952670f01759c0f1fb4219c7b Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:34:21 -0700 Subject: [PATCH 314/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 9ec939abe3963..60addf742f4d3 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3205,9 +3205,9 @@ impl [T] { /// /// Returns a triple partitioning the reordered slice: /// - /// * The unsorted subslice before `index` (elements all pass `f(x) <= f(self[index])`) - /// * The element at `index` - /// * The unsorted subslice after `index` (elements all pass `f(x) >= f(self[index])`) + /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// * The element at `index`. + /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. /// /// # Current implementation /// From 5468fdd5b55b776fbde3c9e6757ccb84f9c202fe Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:34:29 -0700 Subject: [PATCH 315/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 60addf742f4d3..8e98e1e061764 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3196,8 +3196,8 @@ impl [T] { } /// Reorders the slice with a key extraction function such that the element at `index` is at a - /// sort-order position. All elements before `index` will have keys `<=` the key at `index`, and - /// all elements after will have keys `>=`. + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, and + /// all elements after will have keys `>=` to it. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This From 1e107675c2fa501f99f4b29b8418ed974a575ccc Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:35:12 -0700 Subject: [PATCH 316/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 8e98e1e061764..579ba3c3996f7 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3164,8 +3164,8 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the items `>=` the median, the median, and `<=` the median, by using a reversed - /// // comparator. + /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using + /// // a reversed comparator. /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); /// /// assert!(before == [4, 2] || before == [2, 4]); From 0b3a29c5e74c23d8dde94fcaeca86d1e03e56140 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:35:22 -0700 Subject: [PATCH 317/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 579ba3c3996f7..ac8bcc2f55118 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3140,9 +3140,9 @@ impl [T] { /// /// Returns a triple partitioning the reordered slice: /// - /// * The unsorted subslice before `index` (elements all pass `compare(x, self[index]).is_le()`) - /// * The element at `index` - /// * The unsorted subslice after `index` (elements all pass `compare(x, self[index]).is_ge()`) + /// * The unsorted subslice before `index`, whose elements all satisfy `compare(x, self[index]).is_le()`. + /// * The element at `index`. + /// * The unsorted subslice after `index`, whose elements all satisfy `compare(x, self[index]).is_ge()`. /// /// # Current implementation /// From 29189f7ad3641e74633fb30a2d4cbdd86be323f6 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:35:41 -0700 Subject: [PATCH 318/481] Update library/core/src/slice/mod.rs Co-authored-by: Ibraheem Ahmed --- core/src/slice/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index ac8bcc2f55118..519b087d70356 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3229,8 +3229,7 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 1, -3, 2]; /// - /// // Find the items <= the median absolute value, the median absolute value, and >= the median - /// // absolute value. + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items `>=` to it. /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); /// /// assert!(lesser == [1, 2] || lesser == [2, 1]); From 63303b91e74a0189b83e379104810f6427b9970a Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Sat, 18 Jan 2025 18:40:16 -0700 Subject: [PATCH 319/481] Rewrap following accepting review suggestions from @ibraheemdev --- core/src/slice/mod.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 519b087d70356..ba5746d0adea1 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3072,7 +3072,8 @@ impl [T] { } /// Reorders the slice such that the element at `index` is at a sort-order position. All - /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to it. + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to + /// it. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This @@ -3081,7 +3082,9 @@ impl [T] { /// Returns a triple that partitions the reordered slice: /// /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. + /// /// * The element at `index`. + /// /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. /// /// # Current implementation @@ -3131,8 +3134,8 @@ impl [T] { } /// Reorders the slice with a comparator function such that the element at `index` is at a - /// sort-order position. All elements before `index` will be `<=` to this value, and all elements - /// after will be `>=` to it, according to the comparator function. + /// sort-order position. All elements before `index` will be `<=` to this value, and all + /// elements after will be `>=` to it, according to the comparator function. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This @@ -3140,9 +3143,13 @@ impl [T] { /// /// Returns a triple partitioning the reordered slice: /// - /// * The unsorted subslice before `index`, whose elements all satisfy `compare(x, self[index]).is_le()`. + /// * The unsorted subslice before `index`, whose elements all satisfy + /// `compare(x, self[index]).is_le()`. + /// /// * The element at `index`. - /// * The unsorted subslice after `index`, whose elements all satisfy `compare(x, self[index]).is_ge()`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy + /// `compare(x, self[index]).is_ge()`. /// /// # Current implementation /// @@ -3196,8 +3203,8 @@ impl [T] { } /// Reorders the slice with a key extraction function such that the element at `index` is at a - /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, and - /// all elements after will have keys `>=` to it. + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, + /// and all elements after will have keys `>=` to it. /// /// This reordering is unstable (i.e. any element that compares equal to the nth element may end /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This @@ -3206,7 +3213,9 @@ impl [T] { /// Returns a triple partitioning the reordered slice: /// /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// /// * The element at `index`. + /// /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. /// /// # Current implementation @@ -3229,7 +3238,8 @@ impl [T] { /// ``` /// let mut v = [-5i32, 4, 1, -3, 2]; /// - /// // Find the items `<=` to the absolute median, the absolute median itself, and the items `>=` to it. + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items + /// // `>=` to it. /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); /// /// assert!(lesser == [1, 2] || lesser == [2, 1]); From 85f265b5179801e0023114383553cf20866f3386 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 19 Jan 2025 00:21:55 +0000 Subject: [PATCH 320/481] cargo update compiler & tools dependencies: Locking 13 packages to latest compatible versions Updating anstyle-wincon v3.0.6 -> v3.0.7 Updating bitflags v2.7.0 -> v2.8.0 Updating chrono-tz v0.10.0 -> v0.10.1 Updating js-sys v0.3.76 -> v0.3.77 Updating log v0.4.22 -> v0.4.25 Updating miniz_oxide v0.8.2 -> v0.8.3 Updating uuid v1.11.1 -> v1.12.0 Updating valuable v0.1.0 -> v0.1.1 Updating wasm-bindgen v0.2.99 -> v0.2.100 Updating wasm-bindgen-backend v0.2.99 -> v0.2.100 Updating wasm-bindgen-macro v0.2.99 -> v0.2.100 Updating wasm-bindgen-macro-support v0.2.99 -> v0.2.100 Updating wasm-bindgen-shared v0.2.99 -> v0.2.100 note: pass `--verbose` to see 41 unchanged dependencies behind latest library dependencies: Locking 1 package to latest compatible version Updating miniz_oxide v0.8.2 -> v0.8.3 note: pass `--verbose` to see 4 unchanged dependencies behind latest rustbook dependencies: Locking 12 packages to latest compatible versions Updating anstyle-wincon v3.0.6 -> v3.0.7 Updating bitflags v2.7.0 -> v2.8.0 Updating cc v1.2.8 -> v1.2.10 Updating js-sys v0.3.76 -> v0.3.77 Updating log v0.4.22 -> v0.4.25 Updating miniz_oxide v0.8.2 -> v0.8.3 Adding rustversion v1.0.19 Updating wasm-bindgen v0.2.99 -> v0.2.100 Updating wasm-bindgen-backend v0.2.99 -> v0.2.100 Updating wasm-bindgen-macro v0.2.99 -> v0.2.100 Updating wasm-bindgen-macro-support v0.2.99 -> v0.2.100 Updating wasm-bindgen-shared v0.2.99 -> v0.2.100 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8007dd9be046..7b9081d46a056 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", "compiler_builtins", From c48b5c7f5365cf3e51493086b060a4f52252048f Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 13 Jan 2025 21:00:57 +0300 Subject: [PATCH 321/481] further improve panic_immediate_abort by removing rtprintpanic messages --- std/src/rt.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/std/src/rt.rs b/std/src/rt.rs index 384369b0012b5..3a22a16cb165e 100644 --- a/std/src/rt.rs +++ b/std/src/rt.rs @@ -32,9 +32,14 @@ use crate::{mem, panic, sys}; // - nothing (so this macro is a no-op) macro_rules! rtprintpanic { ($($t:tt)*) => { + #[cfg(not(feature = "panic_immediate_abort"))] if let Some(mut out) = crate::sys::stdio::panic_output() { let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); } + #[cfg(feature = "panic_immediate_abort")] + { + let _ = format_args!($($t)*); + } } } From 98d484b4ba1803a6fe563cfc44e3ddbae4967d49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Jan 2025 17:10:44 +0100 Subject: [PATCH 322/481] remove unnecessary rustc_allowed_through_unstable_modules --- std/src/os/fd/raw.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/std/src/os/fd/raw.rs b/std/src/os/fd/raw.rs index 22f5528248a32..03dff94350dad 100644 --- a/std/src/os/fd/raw.rs +++ b/std/src/os/fd/raw.rs @@ -19,11 +19,9 @@ use crate::sys_common::{AsInner, IntoInner}; use crate::{fs, io}; /// Raw file descriptors. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(not(target_os = "hermit"))] pub type RawFd = raw::c_int; -#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_os = "hermit")] pub type RawFd = i32; @@ -33,7 +31,6 @@ pub type RawFd = i32; /// This is only available on unix and WASI platforms and must be imported in /// order to call the method. Windows platforms have a corresponding /// `AsRawHandle` and `AsRawSocket` set of traits. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { /// Extracts the raw file descriptor. @@ -67,7 +64,6 @@ pub trait AsRawFd { /// A trait to express the ability to construct an object from a raw file /// descriptor. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file @@ -112,7 +108,6 @@ pub trait FromRawFd { /// A trait to express the ability to consume an object and acquire ownership of /// its raw file descriptor. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "into_raw_os", since = "1.4.0")] pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. From fa1809a10c85ed4087957bc2f6284d44987f8f5c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Jan 2025 17:10:56 +0100 Subject: [PATCH 323/481] wasi/io: remove dead files --- std/src/os/wasi/io/fd.rs | 9 --------- std/src/os/wasi/io/mod.rs | 4 ++++ std/src/os/wasi/io/raw.rs | 20 -------------------- std/src/os/wasi/io/{fd => }/tests.rs | 0 4 files changed, 4 insertions(+), 29 deletions(-) delete mode 100644 std/src/os/wasi/io/fd.rs delete mode 100644 std/src/os/wasi/io/raw.rs rename std/src/os/wasi/io/{fd => }/tests.rs (100%) diff --git a/std/src/os/wasi/io/fd.rs b/std/src/os/wasi/io/fd.rs deleted file mode 100644 index 930aca887e3c4..0000000000000 --- a/std/src/os/wasi/io/fd.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Owned and borrowed file descriptors. - -#![unstable(feature = "wasi_ext", issue = "71213")] - -// Tests for this module -#[cfg(test)] -mod tests; - -pub use crate::os::fd::owned::*; diff --git a/std/src/os/wasi/io/mod.rs b/std/src/os/wasi/io/mod.rs index 4e123a1eec8ae..5f9a735db085e 100644 --- a/std/src/os/wasi/io/mod.rs +++ b/std/src/os/wasi/io/mod.rs @@ -4,3 +4,7 @@ #[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use crate::os::fd::*; + +// Tests for this module +#[cfg(test)] +mod tests; diff --git a/std/src/os/wasi/io/raw.rs b/std/src/os/wasi/io/raw.rs deleted file mode 100644 index da3b36adad409..0000000000000 --- a/std/src/os/wasi/io/raw.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! WASI-specific extensions to general I/O primitives. - -#![unstable(feature = "wasi_ext", issue = "71213")] - -// NOTE: despite the fact that this module is unstable, -// stable Rust had the capability to access the stable -// re-exported items from os::fd::raw through this -// unstable module. -// In PR #95956 the stability checker was changed to check -// all path segments of an item rather than just the last, -// which caused the aforementioned stable usage to regress -// (see issue #99502). -// As a result, the items in os::fd::raw were given the -// rustc_allowed_through_unstable_modules attribute. -// No regression tests were added to ensure this property, -// as CI is not configured to test wasm32-wasi. -// If this module is stabilized, -// you may want to remove those attributes -// (assuming no other unstable modules need them). -pub use crate::os::fd::raw::*; diff --git a/std/src/os/wasi/io/fd/tests.rs b/std/src/os/wasi/io/tests.rs similarity index 100% rename from std/src/os/wasi/io/fd/tests.rs rename to std/src/os/wasi/io/tests.rs From a5431f77275f653147dad05ddb3bcff6b14ed52a Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 17 Jan 2025 12:53:58 +0000 Subject: [PATCH 324/481] doc: Point to methods on `Command` as alternatives to `set/remove_var` --- std/src/env.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/std/src/env.rs b/std/src/env.rs index 11a29cdae62e2..bbd506127fb67 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -336,7 +336,10 @@ impl Error for VarError { /// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// +/// To pass an environment variable to a child process, you can instead use [`Command::env`]. +/// /// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs +/// [`Command::env`]: crate::process::Command::env /// /// # Panics /// @@ -396,7 +399,12 @@ pub unsafe fn set_var, V: AsRef>(key: K, value: V) { /// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// +/// To prevent a child process from inheriting an environment variable, you can +/// instead use [`Command::env_remove`] or [`Command::env_clear`]. +/// /// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs +/// [`Command::env_remove`]: crate::process::Command::env_remove +/// [`Command::env_clear`]: crate::process::Command::env_clear /// /// # Panics /// From 7edf2fde837c63285671413bcb5a169d357ebb3e Mon Sep 17 00:00:00 2001 From: Tom Fryers Date: Mon, 20 Jan 2025 10:16:27 +0000 Subject: [PATCH 325/481] Correct counting to four in cell module docs --- core/src/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/cell.rs b/core/src/cell.rs index 306d565a77e66..20187e478aac5 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -22,8 +22,8 @@ //! (mutable via `&T`), in contrast with typical Rust types that exhibit 'inherited mutability' //! (mutable only via `&mut T`). //! -//! Cell types come in three flavors: `Cell`, `RefCell`, and `OnceCell`. Each provides -//! a different way of providing safe interior mutability. +//! Cell types come in four flavors: `Cell`, `RefCell`, `OnceCell`, and `LazyCell`. +//! Each provides a different way of providing safe interior mutability. //! //! ## `Cell` //! From b2e578eac38064bc7605182d972925841ea1204e Mon Sep 17 00:00:00 2001 From: Jiri Bobek Date: Sun, 1 Dec 2024 08:27:19 +0100 Subject: [PATCH 326/481] Export likely(), unlikely() and cold_path() in std::hint --- core/src/hint.rs | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/core/src/hint.rs b/core/src/hint.rs index 9c054b99a27ac..1ee872fcc9490 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -597,3 +597,143 @@ pub const fn black_box(dummy: T) -> T { pub const fn must_use(value: T) -> T { value } + +/// Hints to the compiler that a branch condition is likely to be true. +/// Returns the value passed to it. +/// +/// It can be used with `if` or boolean `match` expressions. +/// +/// When used outside of a branch condition, it may still work if there is a branch close by, but +/// it is not guaranteed to have any effect. +/// +/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to +/// compound expressions, such as `likely(a && b)`. When applied to compound expressions, it has +/// the following effect: +/// ```text +/// likely(!a) => !unlikely(a) +/// likely(a && b) => likely(a) && likely(b) +/// likely(a || b) => a || likely(b) +/// ``` +/// +/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code. +/// +/// # Examples +/// +/// ``` +/// #![feature(likely_unlikely)] +/// use core::hint::likely; +/// +/// fn foo(x: i32) { +/// if likely(x > 0) { +/// println!("this branch is likely to be taken"); +/// } else { +/// println!("this branch is unlikely to be taken"); +/// } +/// +/// match likely(x > 0) { +/// true => println!("this branch is likely to be taken"), +/// false => println!("this branch is unlikely to be taken"), +/// } +/// +/// // Use outside of a branch condition. This may still work if there is a branch close by, +/// // but it is not guaranteed to have any effect +/// let cond = likely(x != 0); +/// if cond { +/// println!("this branch is likely to be taken"); +/// } +/// } +/// ``` +/// +/// +#[unstable(feature = "likely_unlikely", issue = "26179")] +#[rustc_nounwind] +#[inline(always)] +pub const fn likely(b: bool) -> bool { + crate::intrinsics::likely(b) +} + +/// Hints to the compiler that a branch condition is unlikely to be true. +/// Returns the value passed to it. +/// +/// It can be used with `if` or boolean `match` expressions. +/// +/// When used outside of a branch condition, it may still work if there is a branch close by, but +/// it is not guaranteed to have any effect. +/// +/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to +/// compound expressions, such as `unlikely(a && b)`. When applied to compound expressions, it has +/// the following effect: +/// ```text +/// unlikely(!a) => !likely(a) +/// unlikely(a && b) => a && unlikely(b) +/// unlikely(a || b) => unlikely(a) || unlikely(b) +/// ``` +/// +/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code. +/// +/// # Examples +/// +/// ``` +/// #![feature(likely_unlikely)] +/// use core::hint::unlikely; +/// +/// fn foo(x: i32) { +/// if unlikely(x > 0) { +/// println!("this branch is unlikely to be taken"); +/// } else { +/// println!("this branch is likely to be taken"); +/// } +/// +/// match unlikely(x > 0) { +/// true => println!("this branch is unlikely to be taken"), +/// false => println!("this branch is likely to be taken"), +/// } +/// +/// // Use outside of a branch condition. This may still work if there is a branch close by, +/// // but it is not guaranteed to have any effect +/// let cond = unlikely(x != 0); +/// if cond { +/// println!("this branch is likely to be taken"); +/// } +/// } +/// ``` +#[unstable(feature = "likely_unlikely", issue = "26179")] +#[rustc_nounwind] +#[inline(always)] +pub const fn unlikely(b: bool) -> bool { + crate::intrinsics::unlikely(b) +} + +/// Hints to the compiler that given path is cold, i.e., unlikely to be taken. The compiler may +/// choose to optimize paths that are not cold at the expense of paths that are cold. +/// +/// # Examples +/// +/// ``` +/// #![feature(cold_path)] +/// use core::hint::cold_path; +/// +/// fn foo(x: &[i32]) { +/// if let Some(first) = x.get(0) { +/// // this is the fast path +/// } else { +/// // this path is unlikely +/// cold_path(); +/// } +/// } +/// +/// fn bar(x: i32) -> i32 { +/// match x { +/// 1 => 10, +/// 2 => 100, +/// 3 => { cold_path(); 1000 }, // this branch is unlikely +/// _ => { cold_path(); 10000 }, // this is also unlikely +/// } +/// } +/// ``` +#[unstable(feature = "cold_path", issue = "26179")] +#[rustc_nounwind] +#[inline(always)] +pub const fn cold_path() { + crate::intrinsics::cold_path() +} From b7b793f3ee76d3347965092db90cfdcf09bb6986 Mon Sep 17 00:00:00 2001 From: Jiri Bobek Date: Mon, 20 Jan 2025 16:16:46 +0100 Subject: [PATCH 327/481] 1. Removed 'rustc_nounwind' 2. Rewording of comments --- core/src/hint.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/core/src/hint.rs b/core/src/hint.rs index 1ee872fcc9490..80f6e32b6b2cd 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -603,8 +603,8 @@ pub const fn must_use(value: T) -> T { /// /// It can be used with `if` or boolean `match` expressions. /// -/// When used outside of a branch condition, it may still work if there is a branch close by, but -/// it is not guaranteed to have any effect. +/// When used outside of a branch condition, it may still influence a nearby branch, but +/// probably will not have any effect. /// /// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to /// compound expressions, such as `likely(a && b)`. When applied to compound expressions, it has @@ -635,8 +635,7 @@ pub const fn must_use(value: T) -> T { /// false => println!("this branch is unlikely to be taken"), /// } /// -/// // Use outside of a branch condition. This may still work if there is a branch close by, -/// // but it is not guaranteed to have any effect +/// // Use outside of a branch condition may still influence a nearby branch /// let cond = likely(x != 0); /// if cond { /// println!("this branch is likely to be taken"); @@ -646,7 +645,6 @@ pub const fn must_use(value: T) -> T { /// /// #[unstable(feature = "likely_unlikely", issue = "26179")] -#[rustc_nounwind] #[inline(always)] pub const fn likely(b: bool) -> bool { crate::intrinsics::likely(b) @@ -657,8 +655,8 @@ pub const fn likely(b: bool) -> bool { /// /// It can be used with `if` or boolean `match` expressions. /// -/// When used outside of a branch condition, it may still work if there is a branch close by, but -/// it is not guaranteed to have any effect. +/// When used outside of a branch condition, it may still influence a nearby branch, but +/// probably will not have any effect. /// /// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to /// compound expressions, such as `unlikely(a && b)`. When applied to compound expressions, it has @@ -689,8 +687,7 @@ pub const fn likely(b: bool) -> bool { /// false => println!("this branch is likely to be taken"), /// } /// -/// // Use outside of a branch condition. This may still work if there is a branch close by, -/// // but it is not guaranteed to have any effect +/// // Use outside of a branch condition may still influence a nearby branch /// let cond = unlikely(x != 0); /// if cond { /// println!("this branch is likely to be taken"); @@ -698,7 +695,6 @@ pub const fn likely(b: bool) -> bool { /// } /// ``` #[unstable(feature = "likely_unlikely", issue = "26179")] -#[rustc_nounwind] #[inline(always)] pub const fn unlikely(b: bool) -> bool { crate::intrinsics::unlikely(b) @@ -732,7 +728,6 @@ pub const fn unlikely(b: bool) -> bool { /// } /// ``` #[unstable(feature = "cold_path", issue = "26179")] -#[rustc_nounwind] #[inline(always)] pub const fn cold_path() { crate::intrinsics::cold_path() From 83955aa191ee93f7aa8282b6c64d1a8339d0b078 Mon Sep 17 00:00:00 2001 From: Bardi Harborow Date: Mon, 20 Jan 2025 06:54:22 +1100 Subject: [PATCH 328/481] Recognise new IPv6 documentation range from RFC9637 This commit adds the 3fff::/20 range defined by RFC9637 to those ranges which Ipv6Addr::is_documentation recognises as a documentation IP. --- core/src/net/ip_addr.rs | 11 +++++++---- core/tests/net/ip_addr.rs | 10 ++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/core/src/net/ip_addr.rs b/core/src/net/ip_addr.rs index 7dd5c21401264..b11ba05685352 100644 --- a/core/src/net/ip_addr.rs +++ b/core/src/net/ip_addr.rs @@ -1539,8 +1539,9 @@ impl Ipv6Addr { /// // Addresses reserved for benchmarking (`2001:2::/48`) /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); /// - /// // Addresses reserved for documentation (`2001:db8::/32`) + /// // Addresses reserved for documentation (`2001:db8::/32` and `3fff::/20`) /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); + /// assert_eq!(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 0).is_global(), false); /// /// // Unique local addresses (`fc00::/7`) /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); @@ -1686,11 +1687,12 @@ impl Ipv6Addr { } /// Returns [`true`] if this is an address reserved for documentation - /// (`2001:db8::/32`). + /// (`2001:db8::/32` and `3fff::/20`). /// - /// This property is defined in [IETF RFC 3849]. + /// This property is defined by [IETF RFC 3849] and [IETF RFC 9637]. /// /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [IETF RFC 9637]: https://tools.ietf.org/html/rfc9637 /// /// # Examples /// @@ -1701,12 +1703,13 @@ impl Ipv6Addr { /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// assert_eq!(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] pub const fn is_documentation(&self) -> bool { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + matches!(self.segments(), [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..]) } /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). diff --git a/core/tests/net/ip_addr.rs b/core/tests/net/ip_addr.rs index 707f9a160e127..f01b43282ec42 100644 --- a/core/tests/net/ip_addr.rs +++ b/core/tests/net/ip_addr.rs @@ -332,6 +332,7 @@ fn ip_properties() { check!("ff08::", global | multicast); check!("ff0e::", global | multicast); check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", doc); check!("2001:2::ac32:23ff:21", benchmarking); check!("102:304:506:708:90a:b0c:d0e:f10", global); } @@ -790,6 +791,15 @@ fn ipv6_properties() { documentation ); + check!( + "3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0x3f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + documentation + ); + check!( "2001:2::ac32:23ff:21", &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], From d821f45efd8a8a762668b05681b7d5e610e86fa3 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 13 Dec 2024 18:58:15 +0100 Subject: [PATCH 329/481] panic_unwind: add `#![warn(unreachable_pub)]` --- panic_unwind/src/dummy.rs | 4 ++-- panic_unwind/src/emcc.rs | 4 ++-- panic_unwind/src/gcc.rs | 4 ++-- panic_unwind/src/hermit.rs | 4 ++-- panic_unwind/src/lib.rs | 1 + panic_unwind/src/miri.rs | 4 ++-- panic_unwind/src/seh.rs | 32 ++++++++++++++++---------------- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/panic_unwind/src/dummy.rs b/panic_unwind/src/dummy.rs index a4bcd216c60f0..a0d6876691833 100644 --- a/panic_unwind/src/dummy.rs +++ b/panic_unwind/src/dummy.rs @@ -6,10 +6,10 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; -pub unsafe fn cleanup(_ptr: *mut u8) -> Box { +pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { intrinsics::abort() } -pub unsafe fn panic(_data: Box) -> u32 { +pub(crate) unsafe fn panic(_data: Box) -> u32 { intrinsics::abort() } diff --git a/panic_unwind/src/emcc.rs b/panic_unwind/src/emcc.rs index b986fc1c2a829..9127449edb1a7 100644 --- a/panic_unwind/src/emcc.rs +++ b/panic_unwind/src/emcc.rs @@ -64,7 +64,7 @@ struct Exception { data: Option>, } -pub unsafe fn cleanup(ptr: *mut u8) -> Box { +pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box { // intrinsics::try actually gives us a pointer to this structure. #[repr(C)] struct CatchData { @@ -93,7 +93,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { out } -pub unsafe fn panic(data: Box) -> u32 { +pub(crate) unsafe fn panic(data: Box) -> u32 { let exception = __cxa_allocate_exception(mem::size_of::()) as *mut Exception; if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; diff --git a/panic_unwind/src/gcc.rs b/panic_unwind/src/gcc.rs index b2389078afd0f..e478f6c5fc86c 100644 --- a/panic_unwind/src/gcc.rs +++ b/panic_unwind/src/gcc.rs @@ -58,7 +58,7 @@ struct Exception { cause: Box, } -pub unsafe fn panic(data: Box) -> u32 { +pub(crate) unsafe fn panic(data: Box) -> u32 { let exception = Box::new(Exception { _uwe: uw::_Unwind_Exception { exception_class: RUST_EXCEPTION_CLASS, @@ -82,7 +82,7 @@ pub unsafe fn panic(data: Box) -> u32 { } } -pub unsafe fn cleanup(ptr: *mut u8) -> Box { +pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box { let exception = ptr as *mut uw::_Unwind_Exception; if (*exception).exception_class != RUST_EXCEPTION_CLASS { uw::_Unwind_DeleteException(exception); diff --git a/panic_unwind/src/hermit.rs b/panic_unwind/src/hermit.rs index 69b9edb77c564..8ac827dd9ccbe 100644 --- a/panic_unwind/src/hermit.rs +++ b/panic_unwind/src/hermit.rs @@ -5,14 +5,14 @@ use alloc::boxed::Box; use core::any::Any; -pub unsafe fn cleanup(_ptr: *mut u8) -> Box { +pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { extern "C" { pub fn __rust_abort() -> !; } __rust_abort(); } -pub unsafe fn panic(_data: Box) -> u32 { +pub(crate) unsafe fn panic(_data: Box) -> u32 { extern "C" { pub fn __rust_abort() -> !; } diff --git a/panic_unwind/src/lib.rs b/panic_unwind/src/lib.rs index dc78be76cb4d5..d682816419565 100644 --- a/panic_unwind/src/lib.rs +++ b/panic_unwind/src/lib.rs @@ -26,6 +26,7 @@ #![cfg_attr(miri, allow(dead_code))] #![allow(internal_features)] #![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] +#![warn(unreachable_pub)] use alloc::boxed::Box; use core::any::Any; diff --git a/panic_unwind/src/miri.rs b/panic_unwind/src/miri.rs index 695adadd59b55..a86f0e91eefcc 100644 --- a/panic_unwind/src/miri.rs +++ b/panic_unwind/src/miri.rs @@ -12,14 +12,14 @@ extern "Rust" { fn miri_start_unwind(payload: *mut u8) -> !; } -pub unsafe fn panic(payload: Box) -> u32 { +pub(crate) unsafe fn panic(payload: Box) -> u32 { // The payload we pass to `miri_start_unwind` will be exactly the argument we get // in `cleanup` below. So we just box it up once, to get something pointer-sized. let payload_box: Payload = Box::new(payload); miri_start_unwind(Box::into_raw(payload_box) as *mut u8) } -pub unsafe fn cleanup(payload_box: *mut u8) -> Box { +pub(crate) unsafe fn cleanup(payload_box: *mut u8) -> Box { // Recover the underlying `Box`. let payload_box: Payload = Box::from_raw(payload_box as *mut _); *payload_box diff --git a/panic_unwind/src/seh.rs b/panic_unwind/src/seh.rs index 5afa0a1975612..21bfe74e1a259 100644 --- a/panic_unwind/src/seh.rs +++ b/panic_unwind/src/seh.rs @@ -111,18 +111,18 @@ struct Exception { mod imp { #[repr(transparent)] #[derive(Copy, Clone)] - pub struct ptr_t(*mut u8); + pub(super) struct ptr_t(*mut u8); impl ptr_t { - pub const fn null() -> Self { + pub(super) const fn null() -> Self { Self(core::ptr::null_mut()) } - pub const fn new(ptr: *mut u8) -> Self { + pub(super) const fn new(ptr: *mut u8) -> Self { Self(ptr) } - pub const fn raw(self) -> *mut u8 { + pub(super) const fn raw(self) -> *mut u8 { self.0 } } @@ -133,18 +133,18 @@ mod imp { // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`. #[repr(transparent)] #[derive(Copy, Clone)] - pub struct ptr_t(u32); + pub(super) struct ptr_t(u32); extern "C" { - pub static __ImageBase: u8; + static __ImageBase: u8; } impl ptr_t { - pub const fn null() -> Self { + pub(super) const fn null() -> Self { Self(0) } - pub fn new(ptr: *mut u8) -> Self { + pub(super) fn new(ptr: *mut u8) -> Self { // We need to expose the provenance of the pointer because it is not carried by // the `u32`, while the FFI needs to have this provenance to excess our statics. // @@ -159,7 +159,7 @@ mod imp { Self(offset as u32) } - pub const fn raw(self) -> u32 { + pub(super) const fn raw(self) -> u32 { self.0 } } @@ -168,7 +168,7 @@ mod imp { use imp::ptr_t; #[repr(C)] -pub struct _ThrowInfo { +struct _ThrowInfo { pub attributes: c_uint, pub pmfnUnwind: ptr_t, pub pForwardCompat: ptr_t, @@ -176,13 +176,13 @@ pub struct _ThrowInfo { } #[repr(C)] -pub struct _CatchableTypeArray { +struct _CatchableTypeArray { pub nCatchableTypes: c_int, pub arrayOfCatchableTypes: [ptr_t; 1], } #[repr(C)] -pub struct _CatchableType { +struct _CatchableType { pub properties: c_uint, pub pType: ptr_t, pub thisDisplacement: _PMD, @@ -191,14 +191,14 @@ pub struct _CatchableType { } #[repr(C)] -pub struct _PMD { +struct _PMD { pub mdisp: c_int, pub pdisp: c_int, pub vdisp: c_int, } #[repr(C)] -pub struct _TypeDescriptor { +struct _TypeDescriptor { pub pVFTable: *const u8, pub spare: *mut u8, pub name: [u8; 11], @@ -288,7 +288,7 @@ cfg_if::cfg_if! { } } -pub unsafe fn panic(data: Box) -> u32 { +pub(crate) unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store_seqcst; // _CxxThrowException executes entirely on this stack frame, so there's no @@ -350,7 +350,7 @@ pub unsafe fn panic(data: Box) -> u32 { _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); } -pub unsafe fn cleanup(payload: *mut u8) -> Box { +pub(crate) unsafe fn cleanup(payload: *mut u8) -> Box { // A null payload here means that we got here from the catch (...) of // __rust_try. This happens when a non-Rust foreign exception is caught. if payload.is_null() { From e17247ffd5bfd900d3516b33bea6bb3266383d15 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 13 Dec 2024 19:25:26 +0100 Subject: [PATCH 330/481] rtstartup: add `#![warn(unreachable_pub)]` --- rtstartup/rsbegin.rs | 1 + rtstartup/rsend.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/rtstartup/rsbegin.rs b/rtstartup/rsbegin.rs index 9a3d95bd8ddfb..d3ff5c14aa4a8 100644 --- a/rtstartup/rsbegin.rs +++ b/rtstartup/rsbegin.rs @@ -19,6 +19,7 @@ #![no_core] #![allow(non_camel_case_types)] #![allow(internal_features)] +#![warn(unreachable_pub)] #[lang = "sized"] trait Sized {} diff --git a/rtstartup/rsend.rs b/rtstartup/rsend.rs index 2514eb0034402..81acfbed4477d 100644 --- a/rtstartup/rsend.rs +++ b/rtstartup/rsend.rs @@ -6,6 +6,7 @@ #![crate_type = "rlib"] #![no_core] #![allow(internal_features)] +#![warn(unreachable_pub)] #[lang = "sized"] trait Sized {} From 74faf66d5c8166f6f21c7ad7cb8ebaf4e9fa1ea8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 13 Dec 2024 19:53:04 +0100 Subject: [PATCH 331/481] core: add `#![warn(unreachable_pub)]` --- core/src/array/mod.rs | 2 +- core/src/escape.rs | 22 +++++++++---------- core/src/ffi/mod.rs | 20 ++++++++--------- core/src/lib.rs | 4 +++- core/src/net/display_buffer.rs | 6 +++--- core/src/num/dec2flt/decimal.rs | 20 ++++++++--------- core/src/num/dec2flt/fpu.rs | 8 +++---- core/src/num/dec2flt/table.rs | 9 ++++---- core/src/num/int_log10.rs | 28 ++++++++++++------------ core/src/num/int_sqrt.rs | 8 +++---- core/src/num/overflow_panic.rs | 16 +++++++------- core/src/num/wrapping.rs | 38 ++++++++++++++++----------------- core/src/ops/index_range.rs | 14 ++++++------ core/src/ops/try_trait.rs | 7 ++++-- core/src/slice/rotate.rs | 2 +- core/src/unicode/mod.rs | 2 ++ 16 files changed, 107 insertions(+), 99 deletions(-) diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index 2ae5ded1fd55b..ba61679564a69 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -893,7 +893,7 @@ impl Guard<'_, T> { /// /// No more than N elements must be initialized. #[inline] - pub unsafe fn push_unchecked(&mut self, item: T) { + pub(crate) unsafe fn push_unchecked(&mut self, item: T) { // SAFETY: If `initialized` was correct before and the caller does not // invoke this method more than N times then writes will be in-bounds // and slots will not be initialized more than once. diff --git a/core/src/escape.rs b/core/src/escape.rs index 0685f525dca83..0c3329f676eeb 100644 --- a/core/src/escape.rs +++ b/core/src/escape.rs @@ -163,28 +163,28 @@ pub(crate) struct EscapeIterInner { } impl EscapeIterInner { - pub const fn backslash(c: ascii::Char) -> Self { + pub(crate) const fn backslash(c: ascii::Char) -> Self { let (data, range) = backslash(c); Self { data, alive: range } } - pub const fn ascii(c: u8) -> Self { + pub(crate) const fn ascii(c: u8) -> Self { let (data, range) = escape_ascii(c); Self { data, alive: range } } - pub const fn unicode(c: char) -> Self { + pub(crate) const fn unicode(c: char) -> Self { let (data, range) = escape_unicode(c); Self { data, alive: range } } #[inline] - pub const fn empty() -> Self { + pub(crate) const fn empty() -> Self { Self { data: [ascii::Char::Null; N], alive: 0..0 } } #[inline] - pub fn as_ascii(&self) -> &[ascii::Char] { + pub(crate) fn as_ascii(&self) -> &[ascii::Char] { // SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`. unsafe { self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end)) @@ -192,34 +192,34 @@ impl EscapeIterInner { } #[inline] - pub fn as_str(&self) -> &str { + pub(crate) fn as_str(&self) -> &str { self.as_ascii().as_str() } #[inline] - pub fn len(&self) -> usize { + pub(crate) fn len(&self) -> usize { usize::from(self.alive.end - self.alive.start) } - pub fn next(&mut self) -> Option { + pub(crate) fn next(&mut self) -> Option { let i = self.alive.next()?; // SAFETY: `i` is guaranteed to be a valid index for `self.data`. unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) } } - pub fn next_back(&mut self) -> Option { + pub(crate) fn next_back(&mut self) -> Option { let i = self.alive.next_back()?; // SAFETY: `i` is guaranteed to be a valid index for `self.data`. unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) } } - pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + pub(crate) fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { self.alive.advance_by(n) } - pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + pub(crate) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { self.alive.advance_back_by(n) } } diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 5f32775822be6..79d094556c45c 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -172,10 +172,10 @@ mod c_char_definition { target_arch = "xtensa", ) ))] { - pub type c_char = u8; + pub(super) type c_char = u8; } else { // On every other target, c_char is signed. - pub type c_char = i8; + pub(super) type c_char = i8; } } } @@ -183,11 +183,11 @@ mod c_char_definition { mod c_int_definition { cfg_if! { if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { - pub type c_int = i16; - pub type c_uint = u16; + pub(super) type c_int = i16; + pub(super) type c_uint = u16; } else { - pub type c_int = i32; - pub type c_uint = u32; + pub(super) type c_int = i32; + pub(super) type c_uint = u32; } } } @@ -195,12 +195,12 @@ mod c_int_definition { mod c_long_definition { cfg_if! { if #[cfg(all(target_pointer_width = "64", not(windows)))] { - pub type c_long = i64; - pub type c_ulong = u64; + pub(super) type c_long = i64; + pub(super) type c_ulong = u64; } else { // The minimal size of `long` in the C standard is 32 bits - pub type c_long = i32; - pub type c_ulong = u32; + pub(super) type c_long = i32; + pub(super) type c_ulong = u32; } } } diff --git a/core/src/lib.rs b/core/src/lib.rs index e845bb34426c4..f58eab3b1b1a2 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -101,6 +101,7 @@ #![warn(multiple_supertrait_upcastable)] #![allow(internal_features)] #![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] // Do not check link redundancy on bootstraping phase #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] @@ -396,7 +397,8 @@ pub mod primitive; unused_imports, unsafe_op_in_unsafe_fn, ambiguous_glob_reexports, - deprecated_in_future + deprecated_in_future, + unreachable_pub )] #[allow(rustdoc::bare_urls)] mod core_arch; diff --git a/core/src/net/display_buffer.rs b/core/src/net/display_buffer.rs index a7d12217081f6..625ad5401f5c0 100644 --- a/core/src/net/display_buffer.rs +++ b/core/src/net/display_buffer.rs @@ -2,19 +2,19 @@ use crate::mem::MaybeUninit; use crate::{fmt, str}; /// Used for slow path in `Display` implementations when alignment is required. -pub struct DisplayBuffer { +pub(super) struct DisplayBuffer { buf: [MaybeUninit; SIZE], len: usize, } impl DisplayBuffer { #[inline] - pub const fn new() -> Self { + pub(super) const fn new() -> Self { Self { buf: [MaybeUninit::uninit(); SIZE], len: 0 } } #[inline] - pub fn as_str(&self) -> &str { + pub(super) fn as_str(&self) -> &str { // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation // which writes a valid UTF-8 string to `buf` and correctly sets `len`. unsafe { diff --git a/core/src/num/dec2flt/decimal.rs b/core/src/num/dec2flt/decimal.rs index be9c0eccd5eb8..b37724ba62d5e 100644 --- a/core/src/num/dec2flt/decimal.rs +++ b/core/src/num/dec2flt/decimal.rs @@ -12,7 +12,7 @@ use crate::num::dec2flt::common::{ByteSlice, is_8digits}; #[derive(Clone)] -pub struct Decimal { +pub(super) struct Decimal { /// The number of significant digits in the decimal. pub num_digits: usize, /// The offset of the decimal point in the significant digits. @@ -55,13 +55,13 @@ impl Decimal { /// /// In Python: /// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))` - pub const MAX_DIGITS: usize = 768; + pub(super) const MAX_DIGITS: usize = 768; /// The max digits that can be exactly represented in a 64-bit integer. - pub const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; - pub const DECIMAL_POINT_RANGE: i32 = 2047; + pub(super) const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; + pub(super) const DECIMAL_POINT_RANGE: i32 = 2047; /// Append a digit to the buffer. - pub fn try_add_digit(&mut self, digit: u8) { + pub(super) fn try_add_digit(&mut self, digit: u8) { if self.num_digits < Self::MAX_DIGITS { self.digits[self.num_digits] = digit; } @@ -69,7 +69,7 @@ impl Decimal { } /// Trim trailing zeros from the buffer. - pub fn trim(&mut self) { + pub(super) fn trim(&mut self) { // All of the following calls to `Decimal::trim` can't panic because: // // 1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`. @@ -83,7 +83,7 @@ impl Decimal { } } - pub fn round(&self) -> u64 { + pub(super) fn round(&self) -> u64 { if self.num_digits == 0 || self.decimal_point < 0 { return 0; } else if self.decimal_point > 18 { @@ -111,7 +111,7 @@ impl Decimal { } /// Computes decimal * 2^shift. - pub fn left_shift(&mut self, shift: usize) { + pub(super) fn left_shift(&mut self, shift: usize) { if self.num_digits == 0 { return; } @@ -152,7 +152,7 @@ impl Decimal { } /// Computes decimal * 2^-shift. - pub fn right_shift(&mut self, shift: usize) { + pub(super) fn right_shift(&mut self, shift: usize) { let mut read_index = 0; let mut write_index = 0; let mut n = 0_u64; @@ -202,7 +202,7 @@ impl Decimal { } /// Parse a big integer representation of the float as a decimal. -pub fn parse_decimal(mut s: &[u8]) -> Decimal { +pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal { let mut d = Decimal::default(); let start = s; diff --git a/core/src/num/dec2flt/fpu.rs b/core/src/num/dec2flt/fpu.rs index 8d62684f8d383..daeee1755b0b5 100644 --- a/core/src/num/dec2flt/fpu.rs +++ b/core/src/num/dec2flt/fpu.rs @@ -1,7 +1,7 @@ //! Platform-specific, assembly instructions to avoid //! intermediate rounding on architectures with FPUs. -pub use fpu_precision::set_precision; +pub(super) use fpu_precision::set_precision; // On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available. // The x87 FPU operates with 80 bits of precision by default, which means that operations will @@ -42,7 +42,7 @@ mod fpu_precision { /// - 0b10, double precision i.e., 64-bits /// - 0b11, double extended precision i.e., 80-bits (default state) /// The 0b01 value is reserved and should not be used. - pub struct FPUControlWord(u16); + pub(crate) struct FPUControlWord(u16); fn set_cw(cw: u16) { // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with @@ -57,7 +57,7 @@ mod fpu_precision { } /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. - pub fn set_precision() -> FPUControlWord { + pub(crate) fn set_precision() -> FPUControlWord { let mut cw = 0_u16; // Compute the value for the Precision Control field that is appropriate for `T`. @@ -97,5 +97,5 @@ mod fpu_precision { // precision of the computation is determined on a per-operation basis. #[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))] mod fpu_precision { - pub fn set_precision() {} + pub(crate) fn set_precision() {} } diff --git a/core/src/num/dec2flt/table.rs b/core/src/num/dec2flt/table.rs index 4856074a62bd0..942c2eacfd276 100644 --- a/core/src/num/dec2flt/table.rs +++ b/core/src/num/dec2flt/table.rs @@ -6,16 +6,17 @@ //! //! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py` -pub const SMALLEST_POWER_OF_FIVE: i32 = -342; -pub const LARGEST_POWER_OF_FIVE: i32 = 308; -pub const N_POWERS_OF_FIVE: usize = (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize; +pub(super) const SMALLEST_POWER_OF_FIVE: i32 = -342; +pub(super) const LARGEST_POWER_OF_FIVE: i32 = 308; +pub(super) const N_POWERS_OF_FIVE: usize = + (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize; // Use static to avoid long compile times: Rust compiler errors // can have the entire table compiled multiple times, and then // emit code multiple times, even if it's stripped out in // the final binary. #[rustfmt::skip] -pub static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [ +pub(super) static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [ (0xeef453d6923bd65a, 0x113faa2906a13b3f), // 5^-342 (0x9558b4661b6565f8, 0x4ac7ca59a424c507), // 5^-341 (0xbaaee17fa23ebf76, 0x5d79bcf00d2df649), // 5^-340 diff --git a/core/src/num/int_log10.rs b/core/src/num/int_log10.rs index 0ce31b40a3845..28a3f5d880ad7 100644 --- a/core/src/num/int_log10.rs +++ b/core/src/num/int_log10.rs @@ -3,7 +3,7 @@ // 0 < val <= u8::MAX #[inline] -pub const fn u8(val: u8) -> u32 { +pub(super) const fn u8(val: u8) -> u32 { let val = val as u32; // For better performance, avoid branches by assembling the solution @@ -45,13 +45,13 @@ const fn less_than_5(val: u32) -> u32 { // 0 < val <= u16::MAX #[inline] -pub const fn u16(val: u16) -> u32 { +pub(super) const fn u16(val: u16) -> u32 { less_than_5(val as u32) } // 0 < val <= u32::MAX #[inline] -pub const fn u32(mut val: u32) -> u32 { +pub(super) const fn u32(mut val: u32) -> u32 { let mut log = 0; if val >= 100_000 { val /= 100_000; @@ -62,7 +62,7 @@ pub const fn u32(mut val: u32) -> u32 { // 0 < val <= u64::MAX #[inline] -pub const fn u64(mut val: u64) -> u32 { +pub(super) const fn u64(mut val: u64) -> u32 { let mut log = 0; if val >= 10_000_000_000 { val /= 10_000_000_000; @@ -77,7 +77,7 @@ pub const fn u64(mut val: u64) -> u32 { // 0 < val <= u128::MAX #[inline] -pub const fn u128(mut val: u128) -> u32 { +pub(super) const fn u128(mut val: u128) -> u32 { let mut log = 0; if val >= 100_000_000_000_000_000_000_000_000_000_000 { val /= 100_000_000_000_000_000_000_000_000_000_000; @@ -93,49 +93,49 @@ pub const fn u128(mut val: u128) -> u32 { #[cfg(target_pointer_width = "16")] #[inline] -pub const fn usize(val: usize) -> u32 { +pub(super) const fn usize(val: usize) -> u32 { u16(val as _) } #[cfg(target_pointer_width = "32")] #[inline] -pub const fn usize(val: usize) -> u32 { +pub(super) const fn usize(val: usize) -> u32 { u32(val as _) } #[cfg(target_pointer_width = "64")] #[inline] -pub const fn usize(val: usize) -> u32 { +pub(super) const fn usize(val: usize) -> u32 { u64(val as _) } // 0 < val <= i8::MAX #[inline] -pub const fn i8(val: i8) -> u32 { +pub(super) const fn i8(val: i8) -> u32 { u8(val as u8) } // 0 < val <= i16::MAX #[inline] -pub const fn i16(val: i16) -> u32 { +pub(super) const fn i16(val: i16) -> u32 { u16(val as u16) } // 0 < val <= i32::MAX #[inline] -pub const fn i32(val: i32) -> u32 { +pub(super) const fn i32(val: i32) -> u32 { u32(val as u32) } // 0 < val <= i64::MAX #[inline] -pub const fn i64(val: i64) -> u32 { +pub(super) const fn i64(val: i64) -> u32 { u64(val as u64) } // 0 < val <= i128::MAX #[inline] -pub const fn i128(val: i128) -> u32 { +pub(super) const fn i128(val: i128) -> u32 { u128(val as u128) } @@ -143,6 +143,6 @@ pub const fn i128(val: i128) -> u32 { /// on every single primitive type. #[cold] #[track_caller] -pub const fn panic_for_nonpositive_argument() -> ! { +pub(super) const fn panic_for_nonpositive_argument() -> ! { panic!("argument of integer logarithm must be positive") } diff --git a/core/src/num/int_sqrt.rs b/core/src/num/int_sqrt.rs index 601e81f69930f..c7a322c08c139 100644 --- a/core/src/num/int_sqrt.rs +++ b/core/src/num/int_sqrt.rs @@ -37,7 +37,7 @@ const U8_ISQRT_WITH_REMAINDER: [(u8, u8); 256] = { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] -pub const fn u8(n: u8) -> u8 { +pub(super) const fn u8(n: u8) -> u8 { U8_ISQRT_WITH_REMAINDER[n as usize].0 } @@ -58,7 +58,7 @@ macro_rules! signed_fn { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn $SignedT(n: $SignedT) -> $SignedT { + pub(super) const unsafe fn $SignedT(n: $SignedT) -> $SignedT { debug_assert!(n >= 0, "Negative input inside `isqrt`."); $UnsignedT(n as $UnsignedT) as $SignedT } @@ -83,7 +83,7 @@ macro_rules! unsigned_fn { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT { + pub(super) const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT { if n <= <$HalfBitsT>::MAX as $UnsignedT { $HalfBitsT(n as $HalfBitsT) as $UnsignedT } else { @@ -311,6 +311,6 @@ unsigned_fn!(u128, u64, u128_stages); /// on every single primitive type. #[cold] #[track_caller] -pub const fn panic_for_negative_argument() -> ! { +pub(super) const fn panic_for_negative_argument() -> ! { panic!("argument of integer square root cannot be negative") } diff --git a/core/src/num/overflow_panic.rs b/core/src/num/overflow_panic.rs index 203037ffb43ea..e30573dd3f392 100644 --- a/core/src/num/overflow_panic.rs +++ b/core/src/num/overflow_panic.rs @@ -4,48 +4,48 @@ #[cold] #[track_caller] -pub const fn add() -> ! { +pub(super) const fn add() -> ! { panic!("attempt to add with overflow") } #[cold] #[track_caller] -pub const fn sub() -> ! { +pub(super) const fn sub() -> ! { panic!("attempt to subtract with overflow") } #[cold] #[track_caller] -pub const fn mul() -> ! { +pub(super) const fn mul() -> ! { panic!("attempt to multiply with overflow") } #[cold] #[track_caller] -pub const fn div() -> ! { +pub(super) const fn div() -> ! { panic!("attempt to divide with overflow") } #[cold] #[track_caller] -pub const fn rem() -> ! { +pub(super) const fn rem() -> ! { panic!("attempt to calculate the remainder with overflow") } #[cold] #[track_caller] -pub const fn neg() -> ! { +pub(super) const fn neg() -> ! { panic!("attempt to negate with overflow") } #[cold] #[track_caller] -pub const fn shr() -> ! { +pub(super) const fn shr() -> ! { panic!("attempt to shift right with overflow") } #[cold] #[track_caller] -pub const fn shl() -> ! { +pub(super) const fn shl() -> ! { panic!("attempt to shift left with overflow") } diff --git a/core/src/num/wrapping.rs b/core/src/num/wrapping.rs index 1156b389e2867..55fa91d0b9f49 100644 --- a/core/src/num/wrapping.rs +++ b/core/src/num/wrapping.rs @@ -1058,33 +1058,33 @@ mod shift_max { #[cfg(target_pointer_width = "16")] mod platform { - pub const usize: u32 = super::u16; - pub const isize: u32 = super::i16; + pub(crate) const usize: u32 = super::u16; + pub(crate) const isize: u32 = super::i16; } #[cfg(target_pointer_width = "32")] mod platform { - pub const usize: u32 = super::u32; - pub const isize: u32 = super::i32; + pub(crate) const usize: u32 = super::u32; + pub(crate) const isize: u32 = super::i32; } #[cfg(target_pointer_width = "64")] mod platform { - pub const usize: u32 = super::u64; - pub const isize: u32 = super::i64; + pub(crate) const usize: u32 = super::u64; + pub(crate) const isize: u32 = super::i64; } - pub const i8: u32 = (1 << 3) - 1; - pub const i16: u32 = (1 << 4) - 1; - pub const i32: u32 = (1 << 5) - 1; - pub const i64: u32 = (1 << 6) - 1; - pub const i128: u32 = (1 << 7) - 1; - pub use self::platform::isize; - - pub const u8: u32 = i8; - pub const u16: u32 = i16; - pub const u32: u32 = i32; - pub const u64: u32 = i64; - pub const u128: u32 = i128; - pub use self::platform::usize; + pub(super) const i8: u32 = (1 << 3) - 1; + pub(super) const i16: u32 = (1 << 4) - 1; + pub(super) const i32: u32 = (1 << 5) - 1; + pub(super) const i64: u32 = (1 << 6) - 1; + pub(super) const i128: u32 = (1 << 7) - 1; + pub(super) use self::platform::isize; + + pub(super) const u8: u32 = i8; + pub(super) const u16: u32 = i16; + pub(super) const u32: u32 = i32; + pub(super) const u64: u32 = i64; + pub(super) const u128: u32 = i128; + pub(super) use self::platform::usize; } diff --git a/core/src/ops/index_range.rs b/core/src/ops/index_range.rs index dce3514a1595b..b82184b15b2f5 100644 --- a/core/src/ops/index_range.rs +++ b/core/src/ops/index_range.rs @@ -18,7 +18,7 @@ impl IndexRange { /// # Safety /// - `start <= end` #[inline] - pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self { + pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self { ub_checks::assert_unsafe_precondition!( check_library_ub, "IndexRange::new_unchecked requires `start <= end`", @@ -28,22 +28,22 @@ impl IndexRange { } #[inline] - pub const fn zero_to(end: usize) -> Self { + pub(crate) const fn zero_to(end: usize) -> Self { IndexRange { start: 0, end } } #[inline] - pub const fn start(&self) -> usize { + pub(crate) const fn start(&self) -> usize { self.start } #[inline] - pub const fn end(&self) -> usize { + pub(crate) const fn end(&self) -> usize { self.end } #[inline] - pub const fn len(&self) -> usize { + pub(crate) const fn len(&self) -> usize { // SAFETY: By invariant, this cannot wrap // Using the intrinsic because a UB check here impedes LLVM optimization. (#131563) unsafe { crate::intrinsics::unchecked_sub(self.end, self.start) } @@ -79,7 +79,7 @@ impl IndexRange { /// /// This is designed to help implement `Iterator::advance_by`. #[inline] - pub fn take_prefix(&mut self, n: usize) -> Self { + pub(crate) fn take_prefix(&mut self, n: usize) -> Self { let mid = if n <= self.len() { // SAFETY: We just checked that this will be between start and end, // and thus the addition cannot overflow. @@ -99,7 +99,7 @@ impl IndexRange { /// /// This is designed to help implement `Iterator::advance_back_by`. #[inline] - pub fn take_suffix(&mut self, n: usize) -> Self { + pub(crate) fn take_suffix(&mut self, n: usize) -> Self { let mid = if n <= self.len() { // SAFETY: We just checked that this will be between start and end, // and thus the subtraction cannot overflow. diff --git a/core/src/ops/try_trait.rs b/core/src/ops/try_trait.rs index cd444c86ed06e..3ba2957526f9c 100644 --- a/core/src/ops/try_trait.rs +++ b/core/src/ops/try_trait.rs @@ -338,6 +338,7 @@ pub trait FromResidual::Residual> { #[inline] #[track_caller] // because `Result::from_residual` has it #[lang = "from_yeet"] +#[allow(unreachable_pub)] // not-exposed but still used via lang-item pub fn from_yeet(yeeted: Y) -> T where T: FromResidual>, @@ -383,12 +384,14 @@ impl NeverShortCircuit { /// This is useful for implementing infallible functions in terms of the `try_` ones, /// without accidentally capturing extra generic parameters in a closure. #[inline] - pub fn wrap_mut_1(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit { + pub(crate) fn wrap_mut_1( + mut f: impl FnMut(A) -> T, + ) -> impl FnMut(A) -> NeverShortCircuit { move |a| NeverShortCircuit(f(a)) } #[inline] - pub fn wrap_mut_2(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self { + pub(crate) fn wrap_mut_2(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self { move |a, b| NeverShortCircuit(f(a, b)) } } diff --git a/core/src/slice/rotate.rs b/core/src/slice/rotate.rs index 1e4865a7caad9..d8e0acb565c8c 100644 --- a/core/src/slice/rotate.rs +++ b/core/src/slice/rotate.rs @@ -60,7 +60,7 @@ use crate::{cmp, ptr}; /// we cannot swap any more, but a smaller rotation problem is left to solve /// ``` /// when `left < right` the swapping happens from the left instead. -pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) { +pub(super) unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) { type BufType = [usize; 32]; if T::IS_ZST { return; diff --git a/core/src/unicode/mod.rs b/core/src/unicode/mod.rs index 6066aa9921607..49dbdeb1a6d1c 100644 --- a/core/src/unicode/mod.rs +++ b/core/src/unicode/mod.rs @@ -17,6 +17,8 @@ pub(crate) use unicode_data::uppercase::lookup as Uppercase; pub(crate) use unicode_data::white_space::lookup as White_Space; pub(crate) mod printable; + +#[allow(unreachable_pub)] mod unicode_data; /// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of From 7bd117a3f35558e330913121fe7f1f8a11060679 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 16 Jan 2025 18:37:09 +0100 Subject: [PATCH 332/481] core: `#[allow(unreachable_pub)]` on unreachable `pub use` --- core/src/arch.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/src/arch.rs b/core/src/arch.rs index cb130f60cecf1..81d828a971c80 100644 --- a/core/src/arch.rs +++ b/core/src/arch.rs @@ -1,6 +1,14 @@ #![doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")] -#[allow(unused_imports)] +#[allow( + // some targets don't have anything to reexport, which + // makes the `pub use` unused and unreachable, allow + // both lints as to not have `#[cfg]`s + // + // cf. https://github.com/rust-lang/rust/pull/116033#issuecomment-1760085575 + unused_imports, + unreachable_pub +)] #[stable(feature = "simd_arch", since = "1.27.0")] pub use crate::core_arch::arch::*; From 4857e294a6aeb56b41e0ea98103f1e88b9625042 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 8 Jan 2025 00:27:14 +0100 Subject: [PATCH 333/481] Outline panicking code for `LocalKey::with` See https://github.com/rust-lang/rust/pull/115491 for prior related modifications. https://godbolt.org/z/MTsz87jGj shows a reduction of the code size for TLS accesses. --- std/src/thread/local.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/std/src/thread/local.rs b/std/src/thread/local.rs index 2313f4b5beb11..c003503ca8b09 100644 --- a/std/src/thread/local.rs +++ b/std/src/thread/local.rs @@ -230,6 +230,14 @@ impl fmt::Display for AccessError { #[stable(feature = "thread_local_try_with", since = "1.26.0")] impl Error for AccessError {} +// This ensures the panicking code is outlined from `with` for `LocalKey`. +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[track_caller] +#[cold] +fn panic_access_error(err: AccessError) -> ! { + panic!("cannot access a Thread Local Storage value during or after destruction: {err:?}") +} + impl LocalKey { #[doc(hidden)] #[unstable( @@ -269,10 +277,10 @@ impl LocalKey { where F: FnOnce(&T) -> R, { - self.try_with(f).expect( - "cannot access a Thread Local Storage value \ - during or after destruction", - ) + match self.try_with(f) { + Ok(r) => r, + Err(err) => panic_access_error(err), + } } /// Acquires a reference to the value in this TLS key. @@ -327,10 +335,10 @@ impl LocalKey { let mut init = Some(init); let reference = unsafe { - (self.inner)(Some(&mut init)).as_ref().expect( - "cannot access a Thread Local Storage value \ - during or after destruction", - ) + match (self.inner)(Some(&mut init)).as_ref() { + Some(r) => r, + None => panic_access_error(AccessError), + } }; f(init, reference) From dbc6a7df5b3f256b6a224cfceee466df4892749b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 19 Jan 2025 16:15:00 -0800 Subject: [PATCH 334/481] Add an example of using `carrying_mul_add` to write wider multiplication Just the basic quadratic version that you wouldn't actually want for a true bigint, but it's nice and short so is useful as an example :) --- core/src/num/uint_macros.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 404e4bcffd379..c8433b3bb168a 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -2663,8 +2663,8 @@ macro_rules! uint_impl { /// /// Basic usage: /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. + /// Please note that this example is shared between integer types, + /// which explains why `u32` is used here. /// /// ``` /// #![feature(bigint_helper_methods)] @@ -2677,6 +2677,35 @@ macro_rules! uint_impl { "(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX));" )] /// ``` + /// + /// This is the core per-digit operation for "grade school" O(n²) multiplication. + /// + /// Please note that this example is shared between integer types, + /// using `u8` for simplicity of the demonstration. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// + /// fn quadratic_mul(a: [u8; N], b: [u8; N]) -> [u8; N] { + /// let mut out = [0; N]; + /// for j in 0..N { + /// let mut carry = 0; + /// for i in 0..(N - j) { + /// (out[j + i], carry) = u8::carrying_mul_add(a[i], b[j], out[j + i], carry); + /// } + /// } + /// out + /// } + /// + /// // -1 * -1 == 1 + /// assert_eq!(quadratic_mul([0xFF; 3], [0xFF; 3]), [1, 0, 0]); + /// + /// assert_eq!(u32::wrapping_mul(0x9e3779b9, 0x7f4a7c15), 0xCFFC982D); + /// assert_eq!( + /// quadratic_mul(u32::to_le_bytes(0x9e3779b9), u32::to_le_bytes(0x7f4a7c15)), + /// u32::to_le_bytes(0xCFFC982D) + /// ); + /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ From f765aec88104162528080c1dc55f4e4ac9e82440 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 21 Jan 2025 14:36:18 +0100 Subject: [PATCH 335/481] fix OsString::from_encoded_bytes_unchecked description --- std/src/ffi/os_str.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 7fb57d410431e..c4c8dbccd7a44 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -203,8 +203,8 @@ impl OsString { self } - /// Converts the `OsString` into a byte slice. To convert the byte slice back into an - /// `OsString`, use the [`OsStr::from_encoded_bytes_unchecked`] function. + /// Converts the `OsString` into a byte vector. To convert the byte vector back into an + /// `OsString`, use the [`OsString::from_encoded_bytes_unchecked`] function. /// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit From d04f76f47aacf7b120b7b534827c2d6fa9840c04 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 21 Jan 2025 17:27:24 +0000 Subject: [PATCH 336/481] Remove test panic from File::open --- std/src/sys/pal/windows/fs.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index b3659351b8c11..f8493c21ad444 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -328,9 +328,6 @@ impl File { mem::size_of::() as u32, ); if result == 0 { - if api::get_last_error().code != 0 { - panic!("FILE_ALLOCATION_INFO failed!!!"); - } let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), From 5b2e442329eae094c69b93d9cc712c8edaec3dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 22 Jan 2025 04:46:55 +0100 Subject: [PATCH 337/481] Library: Finalize dyn compatibility renaming --- std/src/keyword_docs.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/std/src/keyword_docs.rs b/std/src/keyword_docs.rs index 0c526eafdf36f..1d26bf37f4d28 100644 --- a/std/src/keyword_docs.rs +++ b/std/src/keyword_docs.rs @@ -2387,13 +2387,12 @@ mod async_keyword {} /// [`async`]: ../std/keyword.async.html mod await_keyword {} -// FIXME(dyn_compat_renaming): Update URL and link text. #[doc(keyword = "dyn")] // /// `dyn` is a prefix of a [trait object]'s type. /// /// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait` -/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1]. +/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1]. /// /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that /// is being passed. That is, the type has been [erased]. @@ -2406,7 +2405,7 @@ mod await_keyword {} /// the function pointer and then that function pointer is called. /// /// See the Reference for more information on [trait objects][ref-trait-obj] -/// and [object safety][ref-obj-safety]. +/// and [dyn compatibility][ref-dyn-compat]. /// /// ## Trade-offs /// @@ -2419,9 +2418,9 @@ mod await_keyword {} /// [trait object]: ../book/ch17-02-trait-objects.html /// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch /// [ref-trait-obj]: ../reference/types/trait-object.html -/// [ref-obj-safety]: ../reference/items/traits.html#object-safety +/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility /// [erased]: https://en.wikipedia.org/wiki/Type_erasure -/// [^1]: Formerly known as 'object safe'. +/// [^1]: Formerly known as *object safe*. mod dyn_keyword {} #[doc(keyword = "union")] From ebf92844dfb88ced5dd66e33908ebb48d8f1a6b4 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 22 Jan 2025 18:36:33 +0300 Subject: [PATCH 338/481] Remove erroneous `unsafe` in `BTreeSet::upper_bound_mut` --- alloc/src/collections/btree/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 9660023d6945e..041f80c1f2c52 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -1442,20 +1442,20 @@ impl BTreeSet { /// /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) }; + /// let mut cursor = set.upper_bound_mut(Bound::Included(&3)); /// assert_eq!(cursor.peek_prev(), Some(&3)); /// assert_eq!(cursor.peek_next(), Some(&4)); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) }; + /// let mut cursor = set.upper_bound_mut(Bound::Excluded(&3)); /// assert_eq!(cursor.peek_prev(), Some(&2)); /// assert_eq!(cursor.peek_next(), Some(&3)); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) }; + /// let mut cursor = set.upper_bound_mut(Bound::Unbounded); /// assert_eq!(cursor.peek_prev(), Some(&4)); /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where T: Borrow + Ord, Q: Ord, From f9703121ae45c3a96ad6785f5589efd61727dc67 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 2 Jan 2025 22:37:03 +0200 Subject: [PATCH 339/481] Implement `ByteStr` and `ByteString` types Approved ACP: https://github.com/rust-lang/libs-team/issues/502 Tracking issue: https://github.com/rust-lang/rust/issues/134915 These types represent human-readable strings that are conventionally, but not always, UTF-8. The `Debug` impl prints non-UTF-8 bytes using escape sequences, and the `Display` impl uses the Unicode replacement character. This is a minimal implementation of these types and associated trait impls. It does not add any helper methods to other types such as `[u8]` or `Vec`. I've omitted a few implementations of `AsRef`, `AsMut`, `Borrow`, `From`, and `PartialOrd`, when those would be the second implementation for a type (counting the `T` impl) or otherwise may cause inference failures. These impls are important, but we can attempt to add them later in standalone commits, and run them through crater. In addition to the `bstr` feature, I've added a `bstr_internals` feature for APIs provided by `core` for use by `alloc` but not currently intended for stabilization. This API and its implementation are based *heavily* on the `bstr` crate by Andrew Gallant (@BurntSushi). --- alloc/src/bstr.rs | 683 +++++++++++++++++++++++++++++++++++++++++++++ alloc/src/lib.rs | 4 + core/src/bstr.rs | 576 ++++++++++++++++++++++++++++++++++++++ core/src/lib.rs | 4 + core/tests/bstr.rs | 54 ++++ std/src/bstr.rs | 4 + std/src/lib.rs | 4 + 7 files changed, 1329 insertions(+) create mode 100644 alloc/src/bstr.rs create mode 100644 core/src/bstr.rs create mode 100644 core/tests/bstr.rs create mode 100644 std/src/bstr.rs diff --git a/alloc/src/bstr.rs b/alloc/src/bstr.rs new file mode 100644 index 0000000000000..c27c6afb55853 --- /dev/null +++ b/alloc/src/bstr.rs @@ -0,0 +1,683 @@ +//! The `ByteStr` and `ByteString` types and trait implementations. + +use core::borrow::{Borrow, BorrowMut}; +#[unstable(feature = "bstr", issue = "134915")] +pub use core::bstr::ByteStr; +use core::bstr::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; +use core::cmp::Ordering; +use core::ops::{ + Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, + RangeTo, RangeToInclusive, +}; +use core::str::FromStr; +use core::{fmt, hash}; + +use crate::borrow::{Cow, ToOwned}; +use crate::boxed::Box; +use crate::rc::Rc; +use crate::string::String; +use crate::sync::Arc; +use crate::vec::Vec; + +/// A wrapper for `Vec` representing a human-readable string that's conventionally, but not +/// always, UTF-8. +/// +/// Unlike `String`, this type permits non-UTF-8 contents, making it suitable for user input, +/// non-native filenames (as `Path` only supports native filenames), and other applications that +/// need to round-trip whatever data the user provides. +/// +/// A `ByteString` owns its contents and can grow and shrink, like a `Vec` or `String`. For a +/// borrowed byte string, see [`ByteStr`](../../std/bstr/struct.ByteStr.html). +/// +/// `ByteString` implements `Deref` to `&Vec`, so all methods available on `&Vec` are +/// available on `ByteString`. Similarly, `ByteString` implements `DerefMut` to `&mut Vec`, +/// so you can modify a `ByteString` using any method available on `&mut Vec`. +/// +/// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`, +/// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively. +/// +/// # Examples +/// +/// You can create a new `ByteString` from a `Vec` directly, or via a `From` impl from various +/// string types: +/// +/// ``` +/// # #![feature(bstr)] +/// # use std::bstr::ByteString; +/// let s1 = ByteString(vec![b'H', b'e', b'l', b'l', b'o']); +/// let s2 = ByteString::from("Hello"); +/// let s3 = ByteString::from(b"Hello"); +/// assert_eq!(s1, s2); +/// assert_eq!(s2, s3); +/// ``` +#[unstable(feature = "bstr", issue = "134915")] +#[repr(transparent)] +#[derive(Clone)] +pub struct ByteString(pub Vec); + +impl ByteString { + #[inline] + pub(crate) fn as_bytes(&self) -> &[u8] { + &self.0 + } + + #[inline] + pub(crate) fn as_bytestr(&self) -> &ByteStr { + ByteStr::new(&self.0) + } + + #[inline] + pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Deref for ByteString { + type Target = Vec; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl DerefMut for ByteString { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for ByteString {} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Debug for ByteString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_bytestr(), f) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Display for ByteString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_bytestr(), f) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<[u8]> for ByteString { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef for ByteString { + #[inline] + fn as_ref(&self) -> &ByteStr { + self.as_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<[u8]> for ByteString { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut for ByteString { + #[inline] + fn as_mut(&mut self) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<[u8]> for ByteString { + #[inline] + fn borrow(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow for ByteString { + #[inline] + fn borrow(&self) -> &ByteStr { + self.as_bytestr() + } +} + +// `impl Borrow for Vec` omitted to avoid inference failures +// `impl Borrow for String` omitted to avoid inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<[u8]> for ByteString { + #[inline] + fn borrow_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut for ByteString { + #[inline] + fn borrow_mut(&mut self) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +// `impl BorrowMut for Vec` omitted to avoid inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl Default for ByteString { + fn default() -> Self { + ByteString(Vec::new()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { + #[inline] + fn from(s: &'a [u8; N]) -> Self { + ByteString(s.as_slice().to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From<[u8; N]> for ByteString { + #[inline] + fn from(s: [u8; N]) -> Self { + ByteString(s.as_slice().to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a [u8]> for ByteString { + #[inline] + fn from(s: &'a [u8]) -> Self { + ByteString(s.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for ByteString { + #[inline] + fn from(s: Vec) -> Self { + ByteString(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From for Vec { + #[inline] + fn from(s: ByteString) -> Self { + s.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a str> for ByteString { + #[inline] + fn from(s: &'a str) -> Self { + ByteString(s.as_bytes().to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From for ByteString { + #[inline] + fn from(s: String) -> Self { + ByteString(s.into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteStr> for ByteString { + #[inline] + fn from(s: &'a ByteStr) -> Self { + ByteString(s.0.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From for Cow<'a, ByteStr> { + #[inline] + fn from(s: ByteString) -> Self { + Cow::Owned(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { + #[inline] + fn from(s: &'a ByteString) -> Self { + Cow::Borrowed(s.as_bytestr()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator for ByteString { + #[inline] + fn from_iter>(iter: T) -> Self { + ByteString(iter.into_iter().collect::().into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator for ByteString { + #[inline] + fn from_iter>(iter: T) -> Self { + ByteString(iter.into_iter().collect()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a str> for ByteString { + #[inline] + fn from_iter>(iter: T) -> Self { + ByteString(iter.into_iter().collect::().into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a [u8]> for ByteString { + #[inline] + fn from_iter>(iter: T) -> Self { + let mut buf = Vec::new(); + for b in iter { + buf.extend_from_slice(b); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a ByteStr> for ByteString { + #[inline] + fn from_iter>(iter: T) -> Self { + let mut buf = Vec::new(); + for b in iter { + buf.extend_from_slice(&b.0); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator for ByteString { + #[inline] + fn from_iter>(iter: T) -> Self { + let mut buf = Vec::new(); + for mut b in iter { + buf.append(&mut b.0); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromStr for ByteString { + type Err = core::convert::Infallible; + + #[inline] + fn from_str(s: &str) -> Result { + Ok(ByteString(s.as_bytes().to_vec())) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index for ByteString { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, _: RangeFull) -> &ByteStr { + self.as_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: Range) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeInclusive) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeFrom) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeTo) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeToInclusive) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut for ByteString { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut for ByteString { + #[inline] + fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteString { + #[inline] + fn index_mut(&mut self, r: Range) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeInclusive) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeFrom) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeTo) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeToInclusive) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl hash::Hash for ByteString { + #[inline] + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Eq for ByteString {} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialEq for ByteString { + #[inline] + fn eq(&self, other: &ByteString) -> bool { + self.0 == other.0 + } +} + +macro_rules! impl_partial_eq_ord_cow { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = (&**other).as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = (&**self).as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option { + let other: &[u8] = (&**other).as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option { + let this: &[u8] = (&**self).as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +// PartialOrd with `Vec` omitted to avoid inference failures +impl_partial_eq!(ByteString, Vec); +// PartialOrd with `[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteString, [u8]); +// PartialOrd with `&[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteString, &[u8]); +// PartialOrd with `String` omitted to avoid inference failures +impl_partial_eq!(ByteString, String); +// PartialOrd with `str` omitted to avoid inference failures +impl_partial_eq!(ByteString, str); +// PartialOrd with `&str` omitted to avoid inference failures +impl_partial_eq!(ByteString, &str); +impl_partial_eq_ord!(ByteString, ByteStr); +impl_partial_eq_ord!(ByteString, &ByteStr); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteString, [u8; N]); +// PartialOrd with `&[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteString, &[u8; N]); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, ByteStr>); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, str>); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, [u8]>); + +#[unstable(feature = "bstr", issue = "134915")] +impl Ord for ByteString { + #[inline] + fn cmp(&self, other: &ByteString) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialOrd for ByteString { + #[inline] + fn partial_cmp(&self, other: &ByteString) -> Option { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl ToOwned for ByteStr { + type Owned = ByteString; + + #[inline] + fn to_owned(&self) -> ByteString { + ByteString(self.0.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl TryFrom for String { + type Error = crate::string::FromUtf8Error; + + #[inline] + fn try_from(s: ByteString) -> Result { + String::from_utf8(s.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteString> for &'a str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteString) -> Result { + crate::str::from_utf8(s.0.as_slice()) + } +} + +// Additional impls for `ByteStr` that require types from `alloc`: + +#[unstable(feature = "bstr", issue = "134915")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + Self::from(Box::<[u8]>::from(&self.0)) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { + #[inline] + fn from(s: &'a ByteStr) -> Self { + Cow::Borrowed(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for Box { + #[inline] + fn from(s: Box<[u8]>) -> Box { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for Box<[u8]> { + #[inline] + fn from(s: Box) -> Box<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for Rc { + #[inline] + fn from(s: Rc<[u8]>) -> Rc { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for Rc<[u8]> { + #[inline] + fn from(s: Rc) -> Rc<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for Arc { + #[inline] + fn from(s: Arc<[u8]>) -> Arc { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Arc::from_raw(Arc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl From> for Arc<[u8]> { + #[inline] + fn from(s: Arc) -> Arc<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Arc::from_raw(Arc::into_raw(s) as _) } + } +} + +// PartialOrd with `Vec` omitted to avoid inference failures +impl_partial_eq!(ByteStr, Vec); +// PartialOrd with `String` omitted to avoid inference failures +impl_partial_eq!(ByteStr, String); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, ByteStr>); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, str>); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, [u8]>); + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteStr> for String { + type Error = core::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteStr) -> Result { + Ok(core::str::from_utf8(&s.0)?.into()) + } +} diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index b4f08debc932a..28e4217e30394 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -102,6 +102,8 @@ #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(box_uninit_write)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_eval_select)] @@ -228,6 +230,8 @@ mod boxed { pub use std::boxed::Box; } pub mod borrow; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod collections; #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))] pub mod ffi; diff --git a/core/src/bstr.rs b/core/src/bstr.rs new file mode 100644 index 0000000000000..11212761eadd7 --- /dev/null +++ b/core/src/bstr.rs @@ -0,0 +1,576 @@ +//! The `ByteStr` type and trait implementations. + +use crate::borrow::{Borrow, BorrowMut}; +use crate::cmp::Ordering; +use crate::ops::{ + Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, + RangeTo, RangeToInclusive, +}; +use crate::{fmt, hash}; + +/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not +/// always, UTF-8. +/// +/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input, +/// non-native filenames (as `Path` only supports native filenames), and other applications that +/// need to round-trip whatever data the user provides. +/// +/// For an owned, growable byte string buffer, use +/// [`ByteString`](../../std/bstr/struct.ByteString.html). +/// +/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on +/// `ByteStr`. +/// +/// # Representation +/// +/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer +/// which includes a pointer to some bytes and a length. +/// +/// # Trait implementations +/// +/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality +/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience. +/// +/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8 +/// presented as hex escape sequences. +/// +/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a +/// `str`, with invalid UTF-8 presented as the Unicode replacement character: � +/// +#[unstable(feature = "bstr", issue = "134915")] +#[repr(transparent)] +pub struct ByteStr(pub [u8]); + +impl ByteStr { + /// Creates a `ByteStr` slice from anything that can be converted to a byte slice. + /// + /// This is a zero-cost conversion. + /// + /// # Example + /// + /// You can create a `ByteStr` from a byte array, a byte slice or a string slice: + /// + /// ``` + /// # #![feature(bstr)] + /// # use std::bstr::ByteStr; + /// let a = ByteStr::new(b"abc"); + /// let b = ByteStr::new(&b"abc"[..]); + /// let c = ByteStr::new("abc"); + /// + /// assert_eq!(a, b); + /// assert_eq!(a, c); + /// ``` + #[inline] + #[unstable(feature = "bstr", issue = "134915")] + pub fn new>(bytes: &B) -> &Self { + ByteStr::from_bytes(bytes.as_ref()) + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub fn from_bytes(slice: &[u8]) -> &Self { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to + // the wrapped type into a reference to the wrapper type. + unsafe { &*(slice as *const [u8] as *const Self) } + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to + // the wrapped type into a reference to the wrapper type. + unsafe { &mut *(slice as *mut [u8] as *mut Self) } + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Deref for ByteStr { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl DerefMut for ByteStr { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for ByteStr {} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Debug for ByteStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\"")?; + for chunk in self.utf8_chunks() { + for c in chunk.valid().chars() { + match c { + '\0' => write!(f, "\\0")?, + '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?, + _ => write!(f, "{}", c.escape_debug())?, + } + } + write!(f, "{}", chunk.invalid().escape_ascii())?; + } + write!(f, "\"")?; + Ok(()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Display for ByteStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for chunk in this.utf8_chunks() { + f.write_str(chunk.valid())?; + if !chunk.invalid().is_empty() { + f.write_str("\u{FFFD}")?; + } + } + Ok(()) + } + + let Some(align) = f.align() else { + return fmt_nopad(self, f); + }; + let nchars: usize = self + .utf8_chunks() + .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 }) + .sum(); + let padding = f.width().unwrap_or(0).saturating_sub(nchars); + let fill = f.fill(); + let (lpad, rpad) = match align { + fmt::Alignment::Left => (0, padding), + fmt::Alignment::Right => (padding, 0), + fmt::Alignment::Center => { + let half = padding / 2; + (half, half + padding % 2) + } + }; + for _ in 0..lpad { + write!(f, "{fill}")?; + } + fmt_nopad(self, f)?; + for _ in 0..rpad { + write!(f, "{fill}")?; + } + + Ok(()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<[u8]> for ByteStr { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef for ByteStr { + #[inline] + fn as_ref(&self) -> &ByteStr { + self + } +} + +// `impl AsRef for [u8]` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef for str { + #[inline] + fn as_ref(&self) -> &ByteStr { + ByteStr::new(self) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<[u8]> for ByteStr { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +// `impl AsMut for [u8]` omitted to avoid widespread inference failures + +// `impl Borrow for [u8]` omitted to avoid widespread inference failures + +// `impl Borrow for str` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<[u8]> for ByteStr { + #[inline] + fn borrow(&self) -> &[u8] { + &self.0 + } +} + +// `impl BorrowMut for [u8]` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<[u8]> for ByteStr { + #[inline] + fn borrow_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> Default for &'a ByteStr { + fn default() -> Self { + ByteStr::from_bytes(b"") + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> Default for &'a mut ByteStr { + fn default() -> Self { + ByteStr::from_bytes_mut(&mut []) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { + #[inline] + fn from(s: &'a [u8; N]) -> Self { + ByteStr::from_bytes(s) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a [u8]> for &'a ByteStr { + #[inline] + fn from(s: &'a [u8]) -> Self { + ByteStr::from_bytes(s) + } +} + +// Omitted due to slice-from-array-issue-113238: +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a ByteStr> for &'a [u8] { +// #[inline] +// fn from(s: &'a ByteStr) -> Self { +// &s.0 +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] { +// #[inline] +// fn from(s: &'a mut ByteStr) -> Self { +// &mut s.0 +// } +// } + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a str> for &'a ByteStr { + #[inline] + fn from(s: &'a str) -> Self { + ByteStr::from_bytes(s.as_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl hash::Hash for ByteStr { + #[inline] + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index for ByteStr { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, _: RangeFull) -> &ByteStr { + self + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: Range) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeInclusive) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeFrom) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeTo) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeToInclusive) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut for ByteStr { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut for ByteStr { + #[inline] + fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { + self + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteStr { + #[inline] + fn index_mut(&mut self, r: Range) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeInclusive) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeFrom) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeTo) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeToInclusive) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Eq for ByteStr {} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialEq for ByteStr { + #[inline] + fn eq(&self, other: &ByteStr) -> bool { + &self.0 == &other.0 + } +} + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + impl<'a> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + impl<'a> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq; + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq_ord { + ($lhs:ty, $rhs:ty) => { + $crate::bstr::impl_partial_eq!($lhs, $rhs); + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option { + let other: &[u8] = other.as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option { + let this: &[u8] = self.as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq_ord; + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq_n { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq_n; + +// PartialOrd with `[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteStr, [u8]); +// PartialOrd with `&[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteStr, &[u8]); +// PartialOrd with `str` omitted to avoid inference failures +impl_partial_eq!(ByteStr, str); +// PartialOrd with `&str` omitted to avoid inference failures +impl_partial_eq!(ByteStr, &str); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteStr, [u8; N]); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteStr, &[u8; N]); + +#[unstable(feature = "bstr", issue = "134915")] +impl Ord for ByteStr { + #[inline] + fn cmp(&self, other: &ByteStr) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialOrd for ByteStr { + #[inline] + fn partial_cmp(&self, other: &ByteStr) -> Option { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteStr> for &'a str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteStr) -> Result { + crate::str::from_utf8(&s.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a mut ByteStr) -> Result { + crate::str::from_utf8_mut(&mut s.0) + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index f58eab3b1b1a2..01ed3cc69a2cc 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -111,6 +111,8 @@ #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -336,6 +338,8 @@ pub mod ascii; pub mod asserting; #[unstable(feature = "async_iterator", issue = "79024")] pub mod async_iter; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod cell; pub mod char; pub mod ffi; diff --git a/core/tests/bstr.rs b/core/tests/bstr.rs new file mode 100644 index 0000000000000..5fecd0a4084c7 --- /dev/null +++ b/core/tests/bstr.rs @@ -0,0 +1,54 @@ +#![feature(bstr)] + +use core::ByteStr; + +#[test] +fn test_debug() { + assert_eq!( + r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#, + format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")), + ); +} + +#[test] +fn test_display() { + let b1 = ByteStr::new("abc"); + let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc"); + + assert_eq!(&format!("{b1}"), "abc"); + assert_eq!(&format!("{b2}"), "�(��"); + + assert_eq!(&format!("{b1:<7}!"), "abc !"); + assert_eq!(&format!("{b1:>7}!"), " abc!"); + assert_eq!(&format!("{b1:^7}!"), " abc !"); + assert_eq!(&format!("{b1:^6}!"), " abc !"); + assert_eq!(&format!("{b1:-<7}!"), "abc----!"); + assert_eq!(&format!("{b1:->7}!"), "----abc!"); + assert_eq!(&format!("{b1:-^7}!"), "--abc--!"); + assert_eq!(&format!("{b1:-^6}!"), "-abc--!"); + + assert_eq!(&format!("{b2:<7}!"), "�(�� !"); + assert_eq!(&format!("{b2:>7}!"), " �(��!"); + assert_eq!(&format!("{b2:^7}!"), " �(�� !"); + assert_eq!(&format!("{b2:^6}!"), " �(�� !"); + assert_eq!(&format!("{b2:-<7}!"), "�(��---!"); + assert_eq!(&format!("{b2:->7}!"), "---�(��!"); + assert_eq!(&format!("{b2:-^7}!"), "-�(��--!"); + assert_eq!(&format!("{b2:-^6}!"), "-�(��-!"); + + assert_eq!(&format!("{b1:<2}!"), "abc!"); + assert_eq!(&format!("{b1:>2}!"), "abc!"); + assert_eq!(&format!("{b1:^2}!"), "abc!"); + assert_eq!(&format!("{b1:-<2}!"), "abc!"); + assert_eq!(&format!("{b1:->2}!"), "abc!"); + assert_eq!(&format!("{b1:-^2}!"), "abc!"); + + assert_eq!(&format!("{b2:<3}!"), "�(��!"); + assert_eq!(&format!("{b2:>3}!"), "�(��!"); + assert_eq!(&format!("{b2:^3}!"), "�(��!"); + assert_eq!(&format!("{b2:^2}!"), "�(��!"); + assert_eq!(&format!("{b2:-<3}!"), "�(��!"); + assert_eq!(&format!("{b2:->3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^2}!"), "�(��!"); +} diff --git a/std/src/bstr.rs b/std/src/bstr.rs new file mode 100644 index 0000000000000..dd49177162833 --- /dev/null +++ b/std/src/bstr.rs @@ -0,0 +1,4 @@ +//! The `ByteStr` and `ByteString` types and trait implementations. + +#[unstable(feature = "bstr", issue = "134915")] +pub use alloc::bstr::{ByteStr, ByteString}; diff --git a/std/src/lib.rs b/std/src/lib.rs index 39f234e4ba661..acb3a0578e505 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -320,6 +320,8 @@ // Library features (core): // tidy-alphabetical-start #![feature(array_chunks)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] @@ -581,6 +583,8 @@ pub mod f64; pub mod thread; pub mod ascii; pub mod backtrace; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod collections; pub mod env; pub mod error; From e316ba032fa071f6af9eb3a749cf30197e0a32fb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 4 Jan 2025 16:08:20 +0200 Subject: [PATCH 340/481] Add `#[cfg(not(test))]` to some impls to work around https://github.com/rust-lang/rust/issues/135100 --- alloc/src/bstr.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/alloc/src/bstr.rs b/alloc/src/bstr.rs index c27c6afb55853..a447ab38d17cc 100644 --- a/alloc/src/bstr.rs +++ b/alloc/src/bstr.rs @@ -9,10 +9,13 @@ use core::ops::{ Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use core::str::FromStr; use core::{fmt, hash}; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::borrow::{Cow, ToOwned}; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; use crate::rc::Rc; use crate::string::String; @@ -185,6 +188,7 @@ impl Default for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { #[inline] @@ -193,6 +197,7 @@ impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From<[u8; N]> for ByteString { #[inline] @@ -201,6 +206,7 @@ impl From<[u8; N]> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a [u8]> for ByteString { #[inline] @@ -225,6 +231,7 @@ impl From for Vec { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a str> for ByteString { #[inline] @@ -241,6 +248,7 @@ impl From for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for ByteString { #[inline] @@ -249,6 +257,7 @@ impl<'a> From<&'a ByteStr> for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From for Cow<'a, ByteStr> { #[inline] @@ -257,6 +266,7 @@ impl<'a> From for Cow<'a, ByteStr> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { #[inline] @@ -325,6 +335,7 @@ impl FromIterator for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl FromStr for ByteString { type Err = core::convert::Infallible; @@ -482,6 +493,7 @@ impl PartialEq for ByteString { macro_rules! impl_partial_eq_ord_cow { ($lhs:ty, $rhs:ty) => { + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$rhs> for $lhs { @@ -492,6 +504,7 @@ macro_rules! impl_partial_eq_ord_cow { } } + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$lhs> for $rhs { @@ -502,6 +515,7 @@ macro_rules! impl_partial_eq_ord_cow { } } + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$rhs> for $lhs { @@ -512,6 +526,7 @@ macro_rules! impl_partial_eq_ord_cow { } } + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$lhs> for $rhs { @@ -562,6 +577,7 @@ impl PartialOrd for ByteString { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl ToOwned for ByteStr { type Owned = ByteString; @@ -594,6 +610,7 @@ impl<'a> TryFrom<&'a ByteString> for &'a str { // Additional impls for `ByteStr` that require types from `alloc`: +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl Clone for Box { #[inline] @@ -602,6 +619,7 @@ impl Clone for Box { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { #[inline] @@ -610,6 +628,7 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From> for Box { #[inline] @@ -619,6 +638,7 @@ impl From> for Box { } } +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From> for Box<[u8]> { #[inline] From 691f81d58e1730769aa0150a8deaa1f43b501a51 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 6 Jan 2025 15:02:25 +0200 Subject: [PATCH 341/481] Support `no_rc`, `no_sync`, and `no_global_oom_handling` For now, apply `no_global_oom_handling` to all of library/alloc/src/bstr.rs . We can make it more fine-grained later. --- alloc/src/bstr.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/alloc/src/bstr.rs b/alloc/src/bstr.rs index a447ab38d17cc..f16a36b0f9b52 100644 --- a/alloc/src/bstr.rs +++ b/alloc/src/bstr.rs @@ -1,5 +1,8 @@ //! The `ByteStr` and `ByteString` types and trait implementations. +// This could be more fine-grained. +#![cfg(not(no_global_oom_handling))] + use core::borrow::{Borrow, BorrowMut}; #[unstable(feature = "bstr", issue = "134915")] pub use core::bstr::ByteStr; @@ -17,8 +20,10 @@ use core::{fmt, hash}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; +#[cfg(not(no_rc))] use crate::rc::Rc; use crate::string::String; +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] use crate::sync::Arc; use crate::vec::Vec; @@ -649,6 +654,7 @@ impl From> for Box<[u8]> { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(not(no_rc))] impl From> for Rc { #[inline] fn from(s: Rc<[u8]>) -> Rc { @@ -658,6 +664,7 @@ impl From> for Rc { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(not(no_rc))] impl From> for Rc<[u8]> { #[inline] fn from(s: Rc) -> Rc<[u8]> { @@ -667,6 +674,7 @@ impl From> for Rc<[u8]> { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] impl From> for Arc { #[inline] fn from(s: Arc<[u8]>) -> Arc { @@ -676,6 +684,7 @@ impl From> for Arc { } #[unstable(feature = "bstr", issue = "134915")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] impl From> for Arc<[u8]> { #[inline] fn from(s: Arc) -> Arc<[u8]> { From 153baeb27c0e5242209d66be0dee87169cd67f8a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 12:27:24 +0200 Subject: [PATCH 342/481] Omit some more `From` impls to avoid inference failures --- alloc/src/bstr.rs | 119 +++++++++++++++++++++------------------------- core/src/bstr.rs | 48 ++++++++++--------- 2 files changed, 80 insertions(+), 87 deletions(-) diff --git a/alloc/src/bstr.rs b/alloc/src/bstr.rs index f16a36b0f9b52..acb60d9ca8618 100644 --- a/alloc/src/bstr.rs +++ b/alloc/src/bstr.rs @@ -43,21 +43,6 @@ use crate::vec::Vec; /// /// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`, /// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively. -/// -/// # Examples -/// -/// You can create a new `ByteString` from a `Vec` directly, or via a `From` impl from various -/// string types: -/// -/// ``` -/// # #![feature(bstr)] -/// # use std::bstr::ByteString; -/// let s1 = ByteString(vec![b'H', b'e', b'l', b'l', b'o']); -/// let s2 = ByteString::from("Hello"); -/// let s3 = ByteString::from(b"Hello"); -/// assert_eq!(s1, s2); -/// assert_eq!(s2, s3); -/// ``` #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[derive(Clone)] @@ -193,40 +178,42 @@ impl Default for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { - #[inline] - fn from(s: &'a [u8; N]) -> Self { - ByteString(s.as_slice().to_vec()) - } -} - -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl From<[u8; N]> for ByteString { - #[inline] - fn from(s: [u8; N]) -> Self { - ByteString(s.as_slice().to_vec()) - } -} - -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a [u8]> for ByteString { - #[inline] - fn from(s: &'a [u8]) -> Self { - ByteString(s.to_vec()) - } -} - -#[unstable(feature = "bstr", issue = "134915")] -impl From> for ByteString { - #[inline] - fn from(s: Vec) -> Self { - ByteString(s) - } -} +// Omitted due to inference failures +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { +// #[inline] +// fn from(s: &'a [u8; N]) -> Self { +// ByteString(s.as_slice().to_vec()) +// } +// } +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl From<[u8; N]> for ByteString { +// #[inline] +// fn from(s: [u8; N]) -> Self { +// ByteString(s.as_slice().to_vec()) +// } +// } +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a [u8]> for ByteString { +// #[inline] +// fn from(s: &'a [u8]) -> Self { +// ByteString(s.to_vec()) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl From> for ByteString { +// #[inline] +// fn from(s: Vec) -> Self { +// ByteString(s) +// } +// } #[unstable(feature = "bstr", issue = "134915")] impl From for Vec { @@ -236,22 +223,24 @@ impl From for Vec { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a str> for ByteString { - #[inline] - fn from(s: &'a str) -> Self { - ByteString(s.as_bytes().to_vec()) - } -} - -#[unstable(feature = "bstr", issue = "134915")] -impl From for ByteString { - #[inline] - fn from(s: String) -> Self { - ByteString(s.into_bytes()) - } -} +// Omitted due to inference failures +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a str> for ByteString { +// #[inline] +// fn from(s: &'a str) -> Self { +// ByteString(s.as_bytes().to_vec()) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl From for ByteString { +// #[inline] +// fn from(s: String) -> Self { +// ByteString(s.into_bytes()) +// } +// } #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] diff --git a/core/src/bstr.rs b/core/src/bstr.rs index 11212761eadd7..9f20eb1a0e8ee 100644 --- a/core/src/bstr.rs +++ b/core/src/bstr.rs @@ -246,21 +246,23 @@ impl<'a> Default for &'a mut ByteStr { } } -#[unstable(feature = "bstr", issue = "134915")] -impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { - #[inline] - fn from(s: &'a [u8; N]) -> Self { - ByteStr::from_bytes(s) - } -} - -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a [u8]> for &'a ByteStr { - #[inline] - fn from(s: &'a [u8]) -> Self { - ByteStr::from_bytes(s) - } -} +// Omitted due to inference failures +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { +// #[inline] +// fn from(s: &'a [u8; N]) -> Self { +// ByteStr::from_bytes(s) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a [u8]> for &'a ByteStr { +// #[inline] +// fn from(s: &'a [u8]) -> Self { +// ByteStr::from_bytes(s) +// } +// } // Omitted due to slice-from-array-issue-113238: // @@ -280,13 +282,15 @@ impl<'a> From<&'a [u8]> for &'a ByteStr { // } // } -#[unstable(feature = "bstr", issue = "134915")] -impl<'a> From<&'a str> for &'a ByteStr { - #[inline] - fn from(s: &'a str) -> Self { - ByteStr::from_bytes(s.as_bytes()) - } -} +// Omitted due to inference failures +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a str> for &'a ByteStr { +// #[inline] +// fn from(s: &'a str) -> Self { +// ByteStr::from_bytes(s.as_bytes()) +// } +// } #[unstable(feature = "bstr", issue = "134915")] impl hash::Hash for ByteStr { From eadcc4637f4e4716979edf3cccd473ae173c29bc Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 22 Jan 2025 09:19:24 +0200 Subject: [PATCH 343/481] Add doc aliases for BStr and BString --- alloc/src/bstr.rs | 1 + core/src/bstr.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/alloc/src/bstr.rs b/alloc/src/bstr.rs index acb60d9ca8618..61e61019b508c 100644 --- a/alloc/src/bstr.rs +++ b/alloc/src/bstr.rs @@ -46,6 +46,7 @@ use crate::vec::Vec; #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[derive(Clone)] +#[doc(alias = "BString")] pub struct ByteString(pub Vec); impl ByteString { diff --git a/core/src/bstr.rs b/core/src/bstr.rs index 9f20eb1a0e8ee..74e07f3d242cd 100644 --- a/core/src/bstr.rs +++ b/core/src/bstr.rs @@ -39,6 +39,7 @@ use crate::{fmt, hash}; /// #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] +#[doc(alias = "BStr")] pub struct ByteStr(pub [u8]); impl ByteStr { From 5f3a610171a50927ad79db93dd881df6a08fb705 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 22 Jan 2025 17:53:39 +0200 Subject: [PATCH 344/481] Implement `CloneToUninit` for `ByteStr` --- core/src/clone.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/clone.rs b/core/src/clone.rs index ec1aed53eaf72..00300328b64c1 100644 --- a/core/src/clone.rs +++ b/core/src/clone.rs @@ -311,6 +311,16 @@ unsafe impl CloneToUninit for crate::ffi::CStr { } } +#[unstable(feature = "bstr", issue = "134915")] +unsafe impl CloneToUninit for crate::bstr::ByteStr { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]` + unsafe { self.as_bytes().clone_to_uninit(dst) } + } +} + /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust From e568ee4987036d31818cb3c6b4b125902569d042 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 9 Jan 2025 22:44:39 +0100 Subject: [PATCH 345/481] proc_macro: add `#![warn(unreachable_pub)]` --- proc_macro/src/bridge/closure.rs | 4 ++-- proc_macro/src/bridge/fxhash.rs | 4 ++-- proc_macro/src/bridge/rpc.rs | 4 ++-- proc_macro/src/bridge/selfless_reify.rs | 2 +- proc_macro/src/lib.rs | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/proc_macro/src/bridge/closure.rs b/proc_macro/src/bridge/closure.rs index d371ae3cea098..524fdf53d6b7e 100644 --- a/proc_macro/src/bridge/closure.rs +++ b/proc_macro/src/bridge/closure.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; #[repr(C)] -pub struct Closure<'a, A, R> { +pub(super) struct Closure<'a, A, R> { call: unsafe extern "C" fn(*mut Env, A) -> R, env: *mut Env, // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing @@ -26,7 +26,7 @@ impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { } impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { + pub(super) fn call(&mut self, arg: A) -> R { unsafe { (self.call)(self.env, arg) } } } diff --git a/proc_macro/src/bridge/fxhash.rs b/proc_macro/src/bridge/fxhash.rs index 3345e099a3724..5f6b3d1b929e4 100644 --- a/proc_macro/src/bridge/fxhash.rs +++ b/proc_macro/src/bridge/fxhash.rs @@ -9,7 +9,7 @@ use std::hash::{BuildHasherDefault, Hasher}; use std::ops::BitXor; /// Type alias for a hashmap using the `fx` hash algorithm. -pub type FxHashMap = HashMap>; +pub(super) type FxHashMap = HashMap>; /// A speedy hash algorithm for use within rustc. The hashmap in alloc by /// default uses SipHash which isn't quite as speedy as we want. In the compiler @@ -23,7 +23,7 @@ pub type FxHashMap = HashMap>; /// similar or slightly worse than FNV, but the speed of the hash function /// itself is much higher because it works on up to 8 bytes at a time. #[derive(Default)] -pub struct FxHasher { +pub(super) struct FxHasher { hash: usize, } diff --git a/proc_macro/src/bridge/rpc.rs b/proc_macro/src/bridge/rpc.rs index 202a8e04543b2..85fd7d138585c 100644 --- a/proc_macro/src/bridge/rpc.rs +++ b/proc_macro/src/bridge/rpc.rs @@ -67,7 +67,7 @@ macro_rules! rpc_encode_decode { mod tag { #[repr(u8)] enum Tag { $($variant),* } - $(pub const $variant: u8 = Tag::$variant as u8;)* + $(pub(crate) const $variant: u8 = Tag::$variant as u8;)* } match self { @@ -89,7 +89,7 @@ macro_rules! rpc_encode_decode { mod tag { #[repr(u8)] enum Tag { $($variant),* } - $(pub const $variant: u8 = Tag::$variant as u8;)* + $(pub(crate) const $variant: u8 = Tag::$variant as u8;)* } match u8::decode(r, s) { diff --git a/proc_macro/src/bridge/selfless_reify.rs b/proc_macro/src/bridge/selfless_reify.rs index 907ad256e4b43..312a79152e23b 100644 --- a/proc_macro/src/bridge/selfless_reify.rs +++ b/proc_macro/src/bridge/selfless_reify.rs @@ -44,7 +44,7 @@ macro_rules! define_reify_functions { fn $name:ident $(<$($param:ident),*>)? for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; )+) => { - $(pub const fn $name< + $(pub(super) const fn $name< $($($param,)*)? F: Fn($($arg_ty),*) -> $ret_ty + Copy >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index b19c9cee75a0b..6611ce30a1b01 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -32,6 +32,7 @@ #![allow(internal_features)] #![deny(ffi_unwind_calls)] #![warn(rustdoc::unescaped_backticks)] +#![warn(unreachable_pub)] #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] From fa1fdf893c7f42664f59ccc20dda90d83191fc97 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 9 Jan 2025 22:57:57 +0100 Subject: [PATCH 346/481] test: add `#![warn(unreachable_pub)]` --- test/src/cli.rs | 2 +- test/src/console.rs | 18 +++++++++--------- test/src/formatters/json.rs | 2 +- test/src/formatters/junit.rs | 4 ++-- test/src/formatters/pretty.rs | 26 +++++++++++++------------- test/src/formatters/terse.rs | 20 ++++++++++---------- test/src/helpers/concurrency.rs | 2 +- test/src/helpers/mod.rs | 6 +++--- test/src/helpers/shuffle.rs | 4 ++-- test/src/lib.rs | 1 + test/src/options.rs | 2 +- test/src/stats/tests.rs | 6 +++--- test/src/term.rs | 2 +- test/src/test_result.rs | 6 +++--- test/src/tests.rs | 28 ++++++++++++++-------------- test/src/time.rs | 30 +++++++++++++++--------------- 16 files changed, 80 insertions(+), 79 deletions(-) diff --git a/test/src/cli.rs b/test/src/cli.rs index 4ccd825bf8dd3..52c8091762346 100644 --- a/test/src/cli.rs +++ b/test/src/cli.rs @@ -44,7 +44,7 @@ impl TestOpts { } /// Result of parsing the options. -pub type OptRes = Result; +pub(crate) type OptRes = Result; /// Result of parsing the option part. type OptPartRes = Result; diff --git a/test/src/console.rs b/test/src/console.rs index 4d4cdcf4d7b6c..024ef48fc5104 100644 --- a/test/src/console.rs +++ b/test/src/console.rs @@ -20,7 +20,7 @@ use super::types::{NamePadding, TestDesc, TestDescAndFn}; use super::{filter_tests, run_tests, term}; /// Generic wrapper over stdout. -pub enum OutputLocation { +pub(crate) enum OutputLocation { Pretty(Box), Raw(T), } @@ -41,7 +41,7 @@ impl Write for OutputLocation { } } -pub struct ConsoleTestDiscoveryState { +pub(crate) struct ConsoleTestDiscoveryState { pub log_out: Option, pub tests: usize, pub benchmarks: usize, @@ -49,7 +49,7 @@ pub struct ConsoleTestDiscoveryState { } impl ConsoleTestDiscoveryState { - pub fn new(opts: &TestOpts) -> io::Result { + pub(crate) fn new(opts: &TestOpts) -> io::Result { let log_out = match opts.logfile { Some(ref path) => Some(File::create(path)?), None => None, @@ -58,7 +58,7 @@ impl ConsoleTestDiscoveryState { Ok(ConsoleTestDiscoveryState { log_out, tests: 0, benchmarks: 0, ignored: 0 }) } - pub fn write_log(&mut self, msg: F) -> io::Result<()> + pub(crate) fn write_log(&mut self, msg: F) -> io::Result<()> where S: AsRef, F: FnOnce() -> S, @@ -74,7 +74,7 @@ impl ConsoleTestDiscoveryState { } } -pub struct ConsoleTestState { +pub(crate) struct ConsoleTestState { pub log_out: Option, pub total: usize, pub passed: usize, @@ -92,7 +92,7 @@ pub struct ConsoleTestState { } impl ConsoleTestState { - pub fn new(opts: &TestOpts) -> io::Result { + pub(crate) fn new(opts: &TestOpts) -> io::Result { let log_out = match opts.logfile { Some(ref path) => Some(File::create(path)?), None => None, @@ -116,7 +116,7 @@ impl ConsoleTestState { }) } - pub fn write_log(&mut self, msg: F) -> io::Result<()> + pub(crate) fn write_log(&mut self, msg: F) -> io::Result<()> where S: AsRef, F: FnOnce() -> S, @@ -131,7 +131,7 @@ impl ConsoleTestState { } } - pub fn write_log_result( + pub(crate) fn write_log_result( &mut self, test: &TestDesc, result: &TestResult, @@ -170,7 +170,7 @@ impl ConsoleTestState { } // List the tests to console, and optionally to logfile. Filters are honored. -pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Result<()> { +pub(crate) fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Result<()> { let output = match term::stdout() { None => OutputLocation::Raw(io::stdout().lock()), Some(t) => OutputLocation::Pretty(t), diff --git a/test/src/formatters/json.rs b/test/src/formatters/json.rs index aa1c50641cb54..92c1c0716f1f2 100644 --- a/test/src/formatters/json.rs +++ b/test/src/formatters/json.rs @@ -13,7 +13,7 @@ pub(crate) struct JsonFormatter { } impl JsonFormatter { - pub fn new(out: OutputLocation) -> Self { + pub(crate) fn new(out: OutputLocation) -> Self { Self { out } } diff --git a/test/src/formatters/junit.rs b/test/src/formatters/junit.rs index 96b432008404b..57b1b0feceefc 100644 --- a/test/src/formatters/junit.rs +++ b/test/src/formatters/junit.rs @@ -8,13 +8,13 @@ use crate::test_result::TestResult; use crate::time; use crate::types::{TestDesc, TestType}; -pub struct JunitFormatter { +pub(crate) struct JunitFormatter { out: OutputLocation, results: Vec<(TestDesc, TestResult, Duration, Vec)>, } impl JunitFormatter { - pub fn new(out: OutputLocation) -> Self { + pub(crate) fn new(out: OutputLocation) -> Self { Self { out, results: Vec::new() } } diff --git a/test/src/formatters/pretty.rs b/test/src/formatters/pretty.rs index 7089eae4330a0..bf3fc40db4117 100644 --- a/test/src/formatters/pretty.rs +++ b/test/src/formatters/pretty.rs @@ -20,7 +20,7 @@ pub(crate) struct PrettyFormatter { } impl PrettyFormatter { - pub fn new( + pub(crate) fn new( out: OutputLocation, use_color: bool, max_name_len: usize, @@ -31,19 +31,19 @@ impl PrettyFormatter { } #[cfg(test)] - pub fn output_location(&self) -> &OutputLocation { + pub(crate) fn output_location(&self) -> &OutputLocation { &self.out } - pub fn write_ok(&mut self) -> io::Result<()> { + pub(crate) fn write_ok(&mut self) -> io::Result<()> { self.write_short_result("ok", term::color::GREEN) } - pub fn write_failed(&mut self) -> io::Result<()> { + pub(crate) fn write_failed(&mut self) -> io::Result<()> { self.write_short_result("FAILED", term::color::RED) } - pub fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> { + pub(crate) fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> { if let Some(message) = message { self.write_short_result(&format!("ignored, {message}"), term::color::YELLOW) } else { @@ -51,15 +51,15 @@ impl PrettyFormatter { } } - pub fn write_time_failed(&mut self) -> io::Result<()> { + pub(crate) fn write_time_failed(&mut self) -> io::Result<()> { self.write_short_result("FAILED (time limit exceeded)", term::color::RED) } - pub fn write_bench(&mut self) -> io::Result<()> { + pub(crate) fn write_bench(&mut self) -> io::Result<()> { self.write_pretty("bench", term::color::CYAN) } - pub fn write_short_result( + pub(crate) fn write_short_result( &mut self, result: &str, color: term::color::Color, @@ -67,7 +67,7 @@ impl PrettyFormatter { self.write_pretty(result, color) } - pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { + pub(crate) fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { match self.out { OutputLocation::Pretty(ref mut term) => { if self.use_color { @@ -86,7 +86,7 @@ impl PrettyFormatter { } } - pub fn write_plain>(&mut self, s: S) -> io::Result<()> { + pub(crate) fn write_plain>(&mut self, s: S) -> io::Result<()> { let s = s.as_ref(); self.out.write_all(s.as_bytes())?; self.out.flush() @@ -154,15 +154,15 @@ impl PrettyFormatter { Ok(()) } - pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> { + pub(crate) fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> { self.write_results(&state.not_failures, "successes") } - pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { + pub(crate) fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { self.write_results(&state.failures, "failures") } - pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { + pub(crate) fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { self.write_results(&state.time_failures, "failures (time limit exceeded)") } diff --git a/test/src/formatters/terse.rs b/test/src/formatters/terse.rs index 534aa2f33110c..b28120ab56e69 100644 --- a/test/src/formatters/terse.rs +++ b/test/src/formatters/terse.rs @@ -25,7 +25,7 @@ pub(crate) struct TerseFormatter { } impl TerseFormatter { - pub fn new( + pub(crate) fn new( out: OutputLocation, use_color: bool, max_name_len: usize, @@ -42,11 +42,11 @@ impl TerseFormatter { } } - pub fn write_ok(&mut self) -> io::Result<()> { + pub(crate) fn write_ok(&mut self) -> io::Result<()> { self.write_short_result(".", term::color::GREEN) } - pub fn write_failed(&mut self, name: &str) -> io::Result<()> { + pub(crate) fn write_failed(&mut self, name: &str) -> io::Result<()> { // Put failed tests on their own line and include the test name, so that it's faster // to see which test failed without having to wait for them all to run. @@ -62,15 +62,15 @@ impl TerseFormatter { self.write_plain("\n") } - pub fn write_ignored(&mut self) -> io::Result<()> { + pub(crate) fn write_ignored(&mut self) -> io::Result<()> { self.write_short_result("i", term::color::YELLOW) } - pub fn write_bench(&mut self) -> io::Result<()> { + pub(crate) fn write_bench(&mut self) -> io::Result<()> { self.write_pretty("bench", term::color::CYAN) } - pub fn write_short_result( + pub(crate) fn write_short_result( &mut self, result: &str, color: term::color::Color, @@ -95,7 +95,7 @@ impl TerseFormatter { Ok(()) } - pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { + pub(crate) fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { match self.out { OutputLocation::Pretty(ref mut term) => { if self.use_color { @@ -114,13 +114,13 @@ impl TerseFormatter { } } - pub fn write_plain>(&mut self, s: S) -> io::Result<()> { + pub(crate) fn write_plain>(&mut self, s: S) -> io::Result<()> { let s = s.as_ref(); self.out.write_all(s.as_bytes())?; self.out.flush() } - pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> { + pub(crate) fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> { self.write_plain("\nsuccesses:\n")?; let mut successes = Vec::new(); let mut stdouts = String::new(); @@ -146,7 +146,7 @@ impl TerseFormatter { Ok(()) } - pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { + pub(crate) fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { self.write_plain("\nfailures:\n")?; let mut failures = Vec::new(); let mut fail_out = String::new(); diff --git a/test/src/helpers/concurrency.rs b/test/src/helpers/concurrency.rs index b1545cbec438a..6648b669125f7 100644 --- a/test/src/helpers/concurrency.rs +++ b/test/src/helpers/concurrency.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use std::{env, thread}; -pub fn get_concurrency() -> usize { +pub(crate) fn get_concurrency() -> usize { if let Ok(value) = env::var("RUST_TEST_THREADS") { match value.parse::>().ok() { Some(n) => n.get(), diff --git a/test/src/helpers/mod.rs b/test/src/helpers/mod.rs index 3c79b90b16754..2fb29b4c7bee5 100644 --- a/test/src/helpers/mod.rs +++ b/test/src/helpers/mod.rs @@ -1,6 +1,6 @@ //! Module with common helpers not directly related to tests //! but used in `libtest`. -pub mod concurrency; -pub mod metrics; -pub mod shuffle; +pub(crate) mod concurrency; +pub(crate) mod metrics; +pub(crate) mod shuffle; diff --git a/test/src/helpers/shuffle.rs b/test/src/helpers/shuffle.rs index 14389eb0e37af..53d1d0e42d4e8 100644 --- a/test/src/helpers/shuffle.rs +++ b/test/src/helpers/shuffle.rs @@ -4,7 +4,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use crate::cli::TestOpts; use crate::types::{TestDescAndFn, TestId, TestName}; -pub fn get_shuffle_seed(opts: &TestOpts) -> Option { +pub(crate) fn get_shuffle_seed(opts: &TestOpts) -> Option { opts.shuffle_seed.or_else(|| { if opts.shuffle { Some( @@ -19,7 +19,7 @@ pub fn get_shuffle_seed(opts: &TestOpts) -> Option { }) } -pub fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) { +pub(crate) fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) { let test_names: Vec<&TestName> = tests.iter().map(|test| &test.1.desc.name).collect(); let test_names_hash = calculate_hash(&test_names); let mut rng = Rng::new(shuffle_seed, test_names_hash); diff --git a/test/src/lib.rs b/test/src/lib.rs index 47407df909bdf..54f7e4ae79f18 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -27,6 +27,7 @@ #![feature(thread_spawn_hook)] #![allow(internal_features)] #![warn(rustdoc::unescaped_backticks)] +#![warn(unreachable_pub)] pub use cli::TestOpts; diff --git a/test/src/options.rs b/test/src/options.rs index 3eaad59474a12..7a5c55f4e2411 100644 --- a/test/src/options.rs +++ b/test/src/options.rs @@ -2,7 +2,7 @@ /// Number of times to run a benchmarked function #[derive(Clone, PartialEq, Eq)] -pub enum BenchMode { +pub(crate) enum BenchMode { Auto, Single, } diff --git a/test/src/stats/tests.rs b/test/src/stats/tests.rs index 4b209dcf214da..7804ddc929132 100644 --- a/test/src/stats/tests.rs +++ b/test/src/stats/tests.rs @@ -573,13 +573,13 @@ fn test_sum_f64_between_ints_that_sum_to_0() { } #[bench] -pub fn sum_three_items(b: &mut Bencher) { +fn sum_three_items(b: &mut Bencher) { b.iter(|| { [1e20f64, 1.5f64, -1e20f64].sum(); }) } #[bench] -pub fn sum_many_f64(b: &mut Bencher) { +fn sum_many_f64(b: &mut Bencher) { let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60]; let v = (0..500).map(|i| nums[i % 5]).collect::>(); @@ -589,4 +589,4 @@ pub fn sum_many_f64(b: &mut Bencher) { } #[bench] -pub fn no_iter(_: &mut Bencher) {} +fn no_iter(_: &mut Bencher) {} diff --git a/test/src/term.rs b/test/src/term.rs index e736e85d46966..d9880a776406d 100644 --- a/test/src/term.rs +++ b/test/src/term.rs @@ -62,7 +62,7 @@ pub(crate) mod color { /// A terminal with similar capabilities to an ANSI Terminal /// (foreground/background colors etc). -pub trait Terminal: Write { +pub(crate) trait Terminal: Write { /// Sets the foreground color to the given color. /// /// If the color is a bright color, but the terminal only supports 8 colors, diff --git a/test/src/test_result.rs b/test/src/test_result.rs index 79fe07bc1ac5c..73dcc2e2a0cca 100644 --- a/test/src/test_result.rs +++ b/test/src/test_result.rs @@ -12,7 +12,7 @@ use super::types::TestDesc; // Return code for secondary process. // Start somewhere other than 0 so we know the return code means what we think // it means. -pub const TR_OK: i32 = 50; +pub(crate) const TR_OK: i32 = 50; // On Windows we use __fastfail to abort, which is documented to use this // exception code. @@ -39,7 +39,7 @@ pub enum TestResult { /// Creates a `TestResult` depending on the raw result of test execution /// and associated data. -pub fn calc_result<'a>( +pub(crate) fn calc_result<'a>( desc: &TestDesc, task_result: Result<(), &'a (dyn Any + 'static + Send)>, time_opts: Option<&time::TestTimeOptions>, @@ -93,7 +93,7 @@ pub fn calc_result<'a>( } /// Creates a `TestResult` depending on the exit code of test subprocess. -pub fn get_result_from_exit_code( +pub(crate) fn get_result_from_exit_code( desc: &TestDesc, status: ExitStatus, time_opts: Option<&time::TestTimeOptions>, diff --git a/test/src/tests.rs b/test/src/tests.rs index e85e61090a91b..abeb364216979 100644 --- a/test/src/tests.rs +++ b/test/src/tests.rs @@ -78,7 +78,7 @@ fn one_ignored_one_unignored_test() -> Vec { } #[test] -pub fn do_not_run_ignored_tests() { +fn do_not_run_ignored_tests() { fn f() -> Result<(), String> { panic!(); } @@ -106,7 +106,7 @@ pub fn do_not_run_ignored_tests() { } #[test] -pub fn ignored_tests_result_in_ignored() { +fn ignored_tests_result_in_ignored() { fn f() -> Result<(), String> { Ok(()) } @@ -479,7 +479,7 @@ fn parse_include_ignored_flag() { } #[test] -pub fn filter_for_ignored_option() { +fn filter_for_ignored_option() { // When we run ignored tests the test filter should filter out all the // unignored tests and flip the ignore flag on the rest to false @@ -496,7 +496,7 @@ pub fn filter_for_ignored_option() { } #[test] -pub fn run_include_ignored_option() { +fn run_include_ignored_option() { // When we "--include-ignored" tests, the ignore flag should be set to false on // all tests and no test filtered out @@ -513,7 +513,7 @@ pub fn run_include_ignored_option() { } #[test] -pub fn exclude_should_panic_option() { +fn exclude_should_panic_option() { let mut opts = TestOpts::new(); opts.run_tests = true; opts.exclude_should_panic = true; @@ -544,7 +544,7 @@ pub fn exclude_should_panic_option() { } #[test] -pub fn exact_filter_match() { +fn exact_filter_match() { fn tests() -> Vec { ["base", "base::test", "base::test1", "base::test2"] .into_iter() @@ -667,7 +667,7 @@ fn sample_tests() -> Vec { } #[test] -pub fn shuffle_tests() { +fn shuffle_tests() { let mut opts = TestOpts::new(); opts.shuffle = true; @@ -686,7 +686,7 @@ pub fn shuffle_tests() { } #[test] -pub fn shuffle_tests_with_seed() { +fn shuffle_tests_with_seed() { let mut opts = TestOpts::new(); opts.shuffle = true; @@ -704,7 +704,7 @@ pub fn shuffle_tests_with_seed() { } #[test] -pub fn order_depends_on_more_than_seed() { +fn order_depends_on_more_than_seed() { let mut opts = TestOpts::new(); opts.shuffle = true; @@ -732,7 +732,7 @@ pub fn order_depends_on_more_than_seed() { } #[test] -pub fn test_metricmap_compare() { +fn test_metricmap_compare() { let mut m1 = MetricMap::new(); let mut m2 = MetricMap::new(); m1.insert_metric("in-both-noise", 1000.0, 200.0); @@ -755,7 +755,7 @@ pub fn test_metricmap_compare() { } #[test] -pub fn test_bench_once_no_iter() { +fn test_bench_once_no_iter() { fn f(_: &mut Bencher) -> Result<(), String> { Ok(()) } @@ -763,7 +763,7 @@ pub fn test_bench_once_no_iter() { } #[test] -pub fn test_bench_once_iter() { +fn test_bench_once_iter() { fn f(b: &mut Bencher) -> Result<(), String> { b.iter(|| {}); Ok(()) @@ -772,7 +772,7 @@ pub fn test_bench_once_iter() { } #[test] -pub fn test_bench_no_iter() { +fn test_bench_no_iter() { fn f(_: &mut Bencher) -> Result<(), String> { Ok(()) } @@ -799,7 +799,7 @@ pub fn test_bench_no_iter() { } #[test] -pub fn test_bench_iter() { +fn test_bench_iter() { fn f(b: &mut Bencher) -> Result<(), String> { b.iter(|| {}); Ok(()) diff --git a/test/src/time.rs b/test/src/time.rs index 02ae050db55bd..f63b156b3dc5a 100644 --- a/test/src/time.rs +++ b/test/src/time.rs @@ -11,7 +11,7 @@ use std::{env, fmt}; use super::types::{TestDesc, TestType}; -pub const TEST_WARN_TIMEOUT_S: u64 = 60; +pub(crate) const TEST_WARN_TIMEOUT_S: u64 = 60; /// This small module contains constants used by `report-time` option. /// Those constants values will be used if corresponding environment variables are not set. @@ -22,42 +22,42 @@ pub const TEST_WARN_TIMEOUT_S: u64 = 60; /// /// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means /// warn time, and 200 means critical time. -pub mod time_constants { +pub(crate) mod time_constants { use std::time::Duration; use super::TEST_WARN_TIMEOUT_S; /// Environment variable for overriding default threshold for unit-tests. - pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT"; + pub(crate) const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT"; // Unit tests are supposed to be really quick. - pub const UNIT_WARN: Duration = Duration::from_millis(50); - pub const UNIT_CRITICAL: Duration = Duration::from_millis(100); + pub(crate) const UNIT_WARN: Duration = Duration::from_millis(50); + pub(crate) const UNIT_CRITICAL: Duration = Duration::from_millis(100); /// Environment variable for overriding default threshold for unit-tests. - pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION"; + pub(crate) const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION"; // Integration tests may have a lot of work, so they can take longer to execute. - pub const INTEGRATION_WARN: Duration = Duration::from_millis(500); - pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000); + pub(crate) const INTEGRATION_WARN: Duration = Duration::from_millis(500); + pub(crate) const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000); /// Environment variable for overriding default threshold for unit-tests. - pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST"; + pub(crate) const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST"; // Doctests are similar to integration tests, because they can include a lot of // initialization code. - pub const DOCTEST_WARN: Duration = INTEGRATION_WARN; - pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL; + pub(crate) const DOCTEST_WARN: Duration = INTEGRATION_WARN; + pub(crate) const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL; // Do not suppose anything about unknown tests, base limits on the // `TEST_WARN_TIMEOUT_S` constant. - pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S); - pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2); + pub(crate) const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S); + pub(crate) const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2); } /// Returns an `Instance` object denoting when the test should be considered /// timed out. -pub fn get_default_test_timeout() -> Instant { +pub(crate) fn get_default_test_timeout() -> Instant { Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S) } @@ -73,7 +73,7 @@ impl fmt::Display for TestExecTime { /// The measured execution time of the whole test suite. #[derive(Debug, Clone, Default, PartialEq)] -pub struct TestSuiteExecTime(pub Duration); +pub(crate) struct TestSuiteExecTime(pub Duration); impl fmt::Display for TestSuiteExecTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 3f18a488655c53b853d455d058cc6c77259fd500 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Jan 2025 16:54:28 +0100 Subject: [PATCH 347/481] remove pointless allowed_through_unstable_modules on TryFromSliceError --- core/src/array/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index ba61679564a69..28329bb090845 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -156,7 +156,6 @@ pub const fn from_mut(s: &mut T) -> &mut [T; 1] { /// The error type returned when a conversion from a slice to an array fails. #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_allowed_through_unstable_modules] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); From 66b82f68f759074d45a3d33a6cf491f3e77494f2 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 22 Jan 2025 19:57:19 +0300 Subject: [PATCH 348/481] Implement `VecDeque::pop_front_if` & `VecDeque::pop_back_if` --- alloc/src/collections/vec_deque/mod.rs | 46 ++++++++++++++++++++++++++ alloc/tests/lib.rs | 1 + alloc/tests/vec_deque.rs | 39 ++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/alloc/src/collections/vec_deque/mod.rs b/alloc/src/collections/vec_deque/mod.rs index 0b6a55297e1ab..1c33f8f60d824 100644 --- a/alloc/src/collections/vec_deque/mod.rs +++ b/alloc/src/collections/vec_deque/mod.rs @@ -1735,6 +1735,52 @@ impl VecDeque { } } + /// Removes and returns the first element from the deque if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the deque + /// is empty (the predicate will not be called in that case). + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_pop_if)] + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque = vec![0, 1, 2, 3, 4].into(); + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(deque.pop_front_if(pred), Some(0)); + /// assert_eq!(deque, [1, 2, 3, 4]); + /// assert_eq!(deque.pop_front_if(pred), None); + /// ``` + #[unstable(feature = "vec_deque_pop_if", issue = "135889")] + pub fn pop_front_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { + let first = self.front_mut()?; + if predicate(first) { self.pop_front() } else { None } + } + + /// Removes and returns the last element from the deque if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the deque + /// is empty (the predicate will not be called in that case). + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_pop_if)] + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque = vec![0, 1, 2, 3, 4].into(); + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(deque.pop_back_if(pred), Some(4)); + /// assert_eq!(deque, [0, 1, 2, 3]); + /// assert_eq!(deque.pop_back_if(pred), None); + /// ``` + #[unstable(feature = "vec_deque_pop_if", issue = "135889")] + pub fn pop_back_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { + let first = self.back_mut()?; + if predicate(first) { self.pop_back() } else { None } + } + /// Prepends an element to the deque. /// /// # Examples diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs index 393bdfe48b741..d8364d750fa8f 100644 --- a/alloc/tests/lib.rs +++ b/alloc/tests/lib.rs @@ -38,6 +38,7 @@ #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(vec_pop_if)] +#![feature(vec_deque_pop_if)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![allow(internal_features)] diff --git a/alloc/tests/vec_deque.rs b/alloc/tests/vec_deque.rs index 4b8d3c735f72b..1b03c29e5bda1 100644 --- a/alloc/tests/vec_deque.rs +++ b/alloc/tests/vec_deque.rs @@ -80,6 +80,45 @@ fn test_parameterized(a: T, b: T, c: T, d: T) { assert_eq!(deq[3].clone(), d.clone()); } +#[test] +fn test_pop_if() { + let mut deq: VecDeque<_> = vec![0, 1, 2, 3, 4].into(); + let pred = |x: &mut i32| *x % 2 == 0; + + assert_eq!(deq.pop_front_if(pred), Some(0)); + assert_eq!(deq, [1, 2, 3, 4]); + + assert_eq!(deq.pop_front_if(pred), None); + assert_eq!(deq, [1, 2, 3, 4]); + + assert_eq!(deq.pop_back_if(pred), Some(4)); + assert_eq!(deq, [1, 2, 3]); + + assert_eq!(deq.pop_back_if(pred), None); + assert_eq!(deq, [1, 2, 3]); +} + +#[test] +fn test_pop_if_empty() { + let mut deq = VecDeque::::new(); + assert_eq!(deq.pop_front_if(|_| true), None); + assert_eq!(deq.pop_back_if(|_| true), None); + assert!(deq.is_empty()); +} + +#[test] +fn test_pop_if_mutates() { + let mut v: VecDeque<_> = vec![-1, 1].into(); + let pred = |x: &mut i32| { + *x *= 2; + false + }; + assert_eq!(v.pop_front_if(pred), None); + assert_eq!(v, [-2, 1]); + assert_eq!(v.pop_back_if(pred), None); + assert_eq!(v, [-2, 2]); +} + #[test] fn test_push_front_grow() { let mut deq = VecDeque::new(); From cea5d8eb405c6f4a75a133671a4a259d6a63c846 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Fri, 24 Jan 2025 01:07:17 +0300 Subject: [PATCH 349/481] Make `Vec::pop_if` a bit more presentable --- alloc/src/vec/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index cd2afd7a47319..84e1449a50e81 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2511,9 +2511,9 @@ impl Vec { } } - /// Removes and returns the last element in a vector if the predicate + /// Removes and returns the last element from a vector if the predicate /// returns `true`, or [`None`] if the predicate returns false or the vector - /// is empty. + /// is empty (the predicate will not be called in that case). /// /// # Examples /// @@ -2528,12 +2528,9 @@ impl Vec { /// assert_eq!(vec.pop_if(pred), None); /// ``` #[unstable(feature = "vec_pop_if", issue = "122741")] - pub fn pop_if(&mut self, f: F) -> Option - where - F: FnOnce(&mut T) -> bool, - { + pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { let last = self.last_mut()?; - if f(last) { self.pop() } else { None } + if predicate(last) { self.pop() } else { None } } /// Moves all the elements of `other` into `self`, leaving `other` empty. From 42ffe5faddb8a47380173579aa06cc2220344d5c Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 24 Jan 2025 10:45:39 +0100 Subject: [PATCH 350/481] Doc difference between extend and extend_from_slice fixes #97119 --- alloc/src/vec/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 84e1449a50e81..88bd3f414ea16 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -3013,10 +3013,9 @@ impl Vec { /// Iterates over the slice `other`, clones each element, and then appends /// it to this `Vec`. The `other` slice is traversed in-order. /// - /// Note that this function is same as [`extend`] except that it is - /// specialized to work with slices instead. If and when Rust gets - /// specialization this function will likely be deprecated (but still - /// available). + /// Note that this function is the same as [`extend`], + /// except that it also works with slice elements that are Clone but not Copy. + /// If Rust gets specialization this function may be deprecated. /// /// # Examples /// From bccf5cfed2a8a94ee2d2c61f1d643a94fe565e8a Mon Sep 17 00:00:00 2001 From: Harshit Verma Date: Mon, 13 Jan 2025 01:57:57 +0530 Subject: [PATCH 351/481] Add `File already exists` error doc to `hard_link` function If the link path already exists, the error `AlreadyExists` is returned. This commit adds this error to the docs. --- std/src/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/fs.rs b/std/src/fs.rs index 9b752ed14437c..1f8aac48a9a8b 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -2529,6 +2529,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// limited to just these cases: /// /// * The `original` path is not a file or doesn't exist. +/// * The 'link' path already exists. /// /// # Examples /// From 5380aef9b50ff32936ccf6f795a1e799b3168a92 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sun, 19 Jan 2025 14:07:32 +0100 Subject: [PATCH 352/481] document order of items in iterator from drain fixes 135710 --- alloc/src/vec/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 88bd3f414ea16..87a0f70e39110 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2571,9 +2571,11 @@ impl Vec { self.len += count; } - /// Removes the specified range from the vector in bulk, returning all - /// removed elements as an iterator. If the iterator is dropped before - /// being fully consumed, it drops the remaining removed elements. + /// Removes the subslice indicated by the given range from the vector, + /// returning a double-ended iterator over the removed subslice. + /// + /// If the iterator is dropped before being fully consumed, + /// it drops the remaining removed elements. /// /// The returned iterator keeps a mutable borrow on the vector to optimize /// its implementation. From 77cb2c1eb4d2b1d22f709f7a2135464e393ab6fe Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sun, 19 Jan 2025 16:45:07 +0100 Subject: [PATCH 353/481] Fix whitespace --- alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 87a0f70e39110..54673ceb1da81 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2573,7 +2573,7 @@ impl Vec { /// Removes the subslice indicated by the given range from the vector, /// returning a double-ended iterator over the removed subslice. - /// + /// /// If the iterator is dropped before being fully consumed, /// it drops the remaining removed elements. /// From 97f13b0b29af9ba600dfd1adf1f64b181146d963 Mon Sep 17 00:00:00 2001 From: Carl Sverre <82591+carlsverre@users.noreply.github.com> Date: Thu, 23 Jan 2025 08:51:21 -0800 Subject: [PATCH 354/481] Add memory layout documentation to generic NonZero --- core/src/num/nonzero.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index dbce64420ac45..bf7ba3222d0e2 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -90,6 +90,26 @@ impl_zeroable_primitive!( /// /// assert_eq!(size_of::>>(), size_of::()); /// ``` +/// +/// # Layout +/// +/// `NonZero` is guaranteed to have the same layout and bit validity as `T` +/// with the exception that the all-zero bit pattern is not a valid instance. +/// `Option>` is guaranteed to be compatible with `T`, including in +/// FFI. +/// +/// Thanks to the [null pointer optimization], `NonZero` and +/// `Option>` are guaranteed to have the same size and alignment: +/// +/// ``` +/// # use std::mem::{size_of, align_of}; +/// use std::num::NonZero; +/// +/// assert_eq!(size_of::>(), size_of::>>()); +/// assert_eq!(align_of::>(), align_of::>>()); +/// ``` +/// +/// [null pointer optimization]: crate::option#representation #[stable(feature = "generic_nonzero", since = "1.79.0")] #[repr(transparent)] #[rustc_nonnull_optimization_guaranteed] From 3220fc7374660da8aa33ed49a845563f949db740 Mon Sep 17 00:00:00 2001 From: Carl Sverre <82591+carlsverre@users.noreply.github.com> Date: Fri, 24 Jan 2025 09:15:19 -0800 Subject: [PATCH 355/481] Update library/core/src/num/nonzero.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tweak language Co-authored-by: Jonas Böttiger --- core/src/num/nonzero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index bf7ba3222d0e2..8089d6164090d 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -94,7 +94,7 @@ impl_zeroable_primitive!( /// # Layout /// /// `NonZero` is guaranteed to have the same layout and bit validity as `T` -/// with the exception that the all-zero bit pattern is not a valid instance. +/// with the exception that the all-zero bit pattern is invalid. /// `Option>` is guaranteed to be compatible with `T`, including in /// FFI. /// From 43eb10441d38ddf8b7d1da0bed2eaf6a8d01e414 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 24 Jan 2025 01:41:00 -0500 Subject: [PATCH 356/481] Fix `FormattingOptions` instantiation with `Default` The `fill` value by default should be set to `' '` (space), but the current implementation uses `#[derive(Default)]` which sets it to `\0` --- core/src/fmt/mod.rs | 11 ++++++++++- core/tests/fmt/mod.rs | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index a033b8bd30514..a1bf3a4d7a706 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -288,7 +288,7 @@ pub enum DebugAsHex { /// /// `FormattingOptions` is a [`Formatter`] without an attached [`Write`] trait. /// It is mainly used to construct `Formatter` instances. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "formatting_options", issue = "118117")] pub struct FormattingOptions { flags: u32, @@ -508,6 +508,15 @@ impl FormattingOptions { } } +#[unstable(feature = "formatting_options", issue = "118117")] +impl Default for FormattingOptions { + /// Same as [`FormattingOptions::new()`]. + fn default() -> Self { + // The `#[derive(Default)]` implementation would set `fill` to `\0` instead of space. + Self::new() + } +} + /// Configuration for formatting. /// /// A `Formatter` represents various options related to formatting. Users do not diff --git a/core/tests/fmt/mod.rs b/core/tests/fmt/mod.rs index 2c93a9bc80db9..025c69c4f6236 100644 --- a/core/tests/fmt/mod.rs +++ b/core/tests/fmt/mod.rs @@ -51,6 +51,12 @@ fn test_maybe_uninit_short() { assert_eq!(format!("{x:?}"), "MaybeUninit"); } +#[test] +fn formatting_options_ctor() { + use core::fmt::FormattingOptions; + assert_eq!(FormattingOptions::new(), FormattingOptions::default()); +} + #[test] fn formatting_options_flags() { use core::fmt::*; From a60276a0967b554e48a4a70ff3bf4b26f8ac93a3 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Fri, 24 Jan 2025 21:17:49 +0800 Subject: [PATCH 357/481] Fix set_name in thread mod for NuttX Replace `pthread_set_name_np` with `pthread_setname_np` for NuttX in the `set_name` function, this change aligns the implementation with the correct API available on NuttX This patch ensures thread naming works correctly on NuttX platforms. Signed-off-by: Huang Qi --- std/src/sys/pal/unix/thread.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/std/src/sys/pal/unix/thread.rs b/std/src/sys/pal/unix/thread.rs index f657f82e6e368..356669980c7d9 100644 --- a/std/src/sys/pal/unix/thread.rs +++ b/std/src/sys/pal/unix/thread.rs @@ -130,7 +130,12 @@ impl Thread { } } - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"))] + #[cfg(any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "nuttx" + ))] pub fn set_name(name: &CStr) { unsafe { cfg_if::cfg_if! { @@ -139,7 +144,7 @@ impl Thread { const TASK_COMM_LEN: usize = 16; let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); } else { - // FreeBSD and DragonFly BSD do not enforce length limits. + // FreeBSD, DragonFly, FreeBSD and NuttX do not enforce length limits. } }; // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux, @@ -150,7 +155,7 @@ impl Thread { } } - #[cfg(any(target_os = "openbsd", target_os = "nuttx"))] + #[cfg(target_os = "openbsd")] pub fn set_name(name: &CStr) { unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); From ffacc2ae53cc567476e7aef6ceeef934be102200 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 25 Jan 2025 22:15:54 +0200 Subject: [PATCH 358/481] Improve and expand documentation of pipes - Simplify some of the language - Minor grammar fixes - Don't imply that pipes *only* work across multiple processes; instead, *suggest* that they're typically used across two or more separate processes. - Specify that portable applications cannot use multiple readers or multiple writers for messages larger than a byte, due to potential interleaving. - Remove no-longer-referenced footnote URLs. --- std/src/io/mod.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 231c8712ebd55..1fa13e95e6872 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -3252,18 +3252,26 @@ impl Iterator for Lines { } } -/// Create anonymous pipe that is close-on-exec and blocking. +/// Create an anonymous pipe that is close-on-exec and blocking. /// /// # Behavior /// -/// A pipe is a synchronous, unidirectional data channel between two or more processes, like an -/// interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular: +/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is +/// typically used to communicate between two or more separate processes, as there are better, +/// faster ways to communicate within a single process. +/// +/// In particular: /// /// * A read on a [`PipeReader`] blocks until the pipe is non-empty. /// * A write on a [`PipeWriter`] blocks when the pipe is full. /// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] /// returns EOF. -/// * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. +/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but +/// writes (above a target-specific threshold) may have their data interleaved. +/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any +/// given byte will only get consumed by one reader. There are no guarantees about data +/// interleaving. +/// * Portable applications cannot assume any atomicity of messages larger than a single byte. /// /// # Capacity /// @@ -3301,8 +3309,6 @@ impl Iterator for Lines { /// # Ok(()) /// # } /// ``` -/// [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html -/// [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html #[unstable(feature = "anonymous_pipe", issue = "127154")] #[inline] @@ -3310,12 +3316,12 @@ pub fn pipe() -> Result<(PipeReader, PipeWriter)> { pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) } -/// Read end of the anonymous pipe. +/// Read end of an anonymous pipe. #[unstable(feature = "anonymous_pipe", issue = "127154")] #[derive(Debug)] pub struct PipeReader(pub(crate) AnonPipe); -/// Write end of the anonymous pipe. +/// Write end of an anonymous pipe. #[unstable(feature = "anonymous_pipe", issue = "127154")] #[derive(Debug)] pub struct PipeWriter(pub(crate) AnonPipe); From d1b11dcd14759ee11533885426e11952c5c833a2 Mon Sep 17 00:00:00 2001 From: "aaishwarymishra@gmail.com" Date: Fri, 24 Jan 2025 21:50:56 +0530 Subject: [PATCH 359/481] ports last few library files to new intrinsic style --- core/src/ffi/va_list.rs | 34 +- core/src/intrinsics/simd.rs | 1600 ++++++++++++++++++++--------------- 2 files changed, 957 insertions(+), 677 deletions(-) diff --git a/core/src/ffi/va_list.rs b/core/src/ffi/va_list.rs index f67c592d8d8f7..cceb186b31e79 100644 --- a/core/src/ffi/va_list.rs +++ b/core/src/ffi/va_list.rs @@ -302,18 +302,28 @@ impl<'f> Drop for VaListImpl<'f> { } } -extern "rust-intrinsic" { - /// Destroy the arglist `ap` after initialization with `va_start` or - /// `va_copy`. - #[rustc_nounwind] - fn va_end(ap: &mut VaListImpl<'_>); +/// Destroy the arglist `ap` after initialization with `va_start` or +/// `va_copy`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +unsafe fn va_end(_ap: &mut VaListImpl<'_>) { + unreachable!() +} - /// Copies the current location of arglist `src` to the arglist `dst`. - #[rustc_nounwind] - fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); +/// Copies the current location of arglist `src` to the arglist `dst`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +unsafe fn va_copy<'f>(_dest: *mut VaListImpl<'f>, _src: &VaListImpl<'f>) { + unreachable!() +} - /// Loads an argument of type `T` from the `va_list` `ap` and increment the - /// argument `ap` points to. - #[rustc_nounwind] - fn va_arg(ap: &mut VaListImpl<'_>) -> T; +/// Loads an argument of type `T` from the `va_list` `ap` and increment the +/// argument `ap` points to. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +unsafe fn va_arg(_ap: &mut VaListImpl<'_>) -> T { + unreachable!() } diff --git a/core/src/intrinsics/simd.rs b/core/src/intrinsics/simd.rs index d03d801b93652..e59d3aff37999 100644 --- a/core/src/intrinsics/simd.rs +++ b/core/src/intrinsics/simd.rs @@ -2,669 +2,939 @@ //! //! In this module, a "vector" is any `repr(simd)` type. -extern "rust-intrinsic" { - /// Inserts an element into a vector, returning the updated vector. - /// - /// `T` must be a vector with element type `U`. - /// - /// # Safety - /// - /// `idx` must be in-bounds of the vector. - #[rustc_nounwind] - pub fn simd_insert(x: T, idx: u32, val: U) -> T; - - /// Extracts an element from a vector. - /// - /// `T` must be a vector with element type `U`. - /// - /// # Safety - /// - /// `idx` must be in-bounds of the vector. - #[rustc_nounwind] - pub fn simd_extract(x: T, idx: u32) -> U; - - /// Adds two simd vectors elementwise. - /// - /// `T` must be a vector of integer or floating point primitive types. - #[rustc_nounwind] - pub fn simd_add(x: T, y: T) -> T; - - /// Subtracts `rhs` from `lhs` elementwise. - /// - /// `T` must be a vector of integer or floating point primitive types. - #[rustc_nounwind] - pub fn simd_sub(lhs: T, rhs: T) -> T; - - /// Multiplies two simd vectors elementwise. - /// - /// `T` must be a vector of integer or floating point primitive types. - #[rustc_nounwind] - pub fn simd_mul(x: T, y: T) -> T; - - /// Divides `lhs` by `rhs` elementwise. - /// - /// `T` must be a vector of integer or floating point primitive types. - /// - /// # Safety - /// For integers, `rhs` must not contain any zero elements. - /// Additionally for signed integers, `::MIN / -1` is undefined behavior. - #[rustc_nounwind] - pub fn simd_div(lhs: T, rhs: T) -> T; - - /// Returns remainder of two vectors elementwise. - /// - /// `T` must be a vector of integer or floating point primitive types. - /// - /// # Safety - /// For integers, `rhs` must not contain any zero elements. - /// Additionally for signed integers, `::MIN / -1` is undefined behavior. - #[rustc_nounwind] - pub fn simd_rem(lhs: T, rhs: T) -> T; - - /// Shifts vector left elementwise, with UB on overflow. - /// - /// Shifts `lhs` left by `rhs`, shifting in sign bits for signed types. - /// - /// `T` must be a vector of integer primitive types. - /// - /// # Safety - /// - /// Each element of `rhs` must be less than `::BITS`. - #[rustc_nounwind] - pub fn simd_shl(lhs: T, rhs: T) -> T; - - /// Shifts vector right elementwise, with UB on overflow. - /// - /// `T` must be a vector of integer primitive types. - /// - /// Shifts `lhs` right by `rhs`, shifting in sign bits for signed types. - /// - /// # Safety - /// - /// Each element of `rhs` must be less than `::BITS`. - #[rustc_nounwind] - pub fn simd_shr(lhs: T, rhs: T) -> T; - - /// "Ands" vectors elementwise. - /// - /// `T` must be a vector of integer primitive types. - #[rustc_nounwind] - pub fn simd_and(x: T, y: T) -> T; - - /// "Ors" vectors elementwise. - /// - /// `T` must be a vector of integer primitive types. - #[rustc_nounwind] - pub fn simd_or(x: T, y: T) -> T; - - /// "Exclusive ors" vectors elementwise. - /// - /// `T` must be a vector of integer primitive types. - #[rustc_nounwind] - pub fn simd_xor(x: T, y: T) -> T; - - /// Numerically casts a vector, elementwise. - /// - /// `T` and `U` must be vectors of integer or floating point primitive types, and must have the - /// same length. - /// - /// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB. - /// When casting integers to floats, the result is rounded. - /// Otherwise, truncates or extends the value, maintaining the sign for signed integers. - /// - /// # Safety - /// Casting from integer types is always safe. - /// Casting between two float types is also always safe. - /// - /// Casting floats to integers truncates, following the same rules as `to_int_unchecked`. - /// Specifically, each element must: - /// * Not be `NaN` - /// * Not be infinite - /// * Be representable in the return type, after truncating off its fractional part - #[rustc_nounwind] - pub fn simd_cast(x: T) -> U; - - /// Numerically casts a vector, elementwise. - /// - /// `T` and `U` be a vectors of integer or floating point primitive types, and must have the - /// same length. - /// - /// Like `simd_cast`, but saturates float-to-integer conversions (NaN becomes 0). - /// This matches regular `as` and is always safe. - /// - /// When casting floats to integers, the result is truncated. - /// When casting integers to floats, the result is rounded. - /// Otherwise, truncates or extends the value, maintaining the sign for signed integers. - #[rustc_nounwind] - pub fn simd_as(x: T) -> U; - - /// Negates a vector elementwise. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// Rust panics for `-::Min` due to overflow, but it is not UB with this intrinsic. - #[rustc_nounwind] - pub fn simd_neg(x: T) -> T; - - /// Returns absolute value of a vector, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - #[rustc_nounwind] - pub fn simd_fabs(x: T) -> T; - - /// Returns the minimum of two vectors, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// Follows IEEE-754 `minNum` semantics. - #[rustc_nounwind] - pub fn simd_fmin(x: T, y: T) -> T; - - /// Returns the maximum of two vectors, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// Follows IEEE-754 `maxNum` semantics. - #[rustc_nounwind] - pub fn simd_fmax(x: T, y: T) -> T; - - /// Tests elementwise equality of two vectors. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// `U` must be a vector of integers with the same number of elements and element size as `T`. - /// - /// Returns `0` for false and `!0` for true. - #[rustc_nounwind] - pub fn simd_eq(x: T, y: T) -> U; - - /// Tests elementwise inequality equality of two vectors. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// `U` must be a vector of integers with the same number of elements and element size as `T`. - /// - /// Returns `0` for false and `!0` for true. - #[rustc_nounwind] - pub fn simd_ne(x: T, y: T) -> U; - - /// Tests if `x` is less than `y`, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// `U` must be a vector of integers with the same number of elements and element size as `T`. - /// - /// Returns `0` for false and `!0` for true. - #[rustc_nounwind] - pub fn simd_lt(x: T, y: T) -> U; - - /// Tests if `x` is less than or equal to `y`, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// `U` must be a vector of integers with the same number of elements and element size as `T`. - /// - /// Returns `0` for false and `!0` for true. - #[rustc_nounwind] - pub fn simd_le(x: T, y: T) -> U; - - /// Tests if `x` is greater than `y`, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// `U` must be a vector of integers with the same number of elements and element size as `T`. - /// - /// Returns `0` for false and `!0` for true. - #[rustc_nounwind] - pub fn simd_gt(x: T, y: T) -> U; - - /// Tests if `x` is greater than or equal to `y`, elementwise. - /// - /// `T` must be a vector of floating-point primitive types. - /// - /// `U` must be a vector of integers with the same number of elements and element size as `T`. - /// - /// Returns `0` for false and `!0` for true. - #[rustc_nounwind] - pub fn simd_ge(x: T, y: T) -> U; - - /// Shuffles two vectors by const indices. - /// - /// `T` must be a vector. - /// - /// `U` must be a **const** vector of `u32`s. This means it must either refer to a named - /// const or be given as an inline const expression (`const { ... }`). - /// - /// `V` must be a vector with the same element type as `T` and the same length as `U`. - /// - /// Returns a new vector such that element `i` is selected from `xy[idx[i]]`, where `xy` - /// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds - /// of `xy`. - #[rustc_nounwind] - pub fn simd_shuffle(x: T, y: T, idx: U) -> V; - - /// Reads a vector of pointers. - /// - /// `T` must be a vector. - /// - /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. - /// - /// `V` must be a vector of integers with the same length as `T` (but any element size). - /// - /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer. - /// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from - /// `val`. - /// - /// # Safety - /// Unmasked values in `T` must be readable as if by `::read` (e.g. aligned to the element - /// type). - /// - /// `mask` must only contain `0` or `!0` values. - #[rustc_nounwind] - pub fn simd_gather(val: T, ptr: U, mask: V) -> T; - - /// Writes to a vector of pointers. - /// - /// `T` must be a vector. - /// - /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. - /// - /// `V` must be a vector of integers with the same length as `T` (but any element size). - /// - /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the - /// corresponding value in `val` to the pointer. - /// Otherwise if the corresponding value in `mask` is `0`, do nothing. - /// - /// The stores happen in left-to-right order. - /// (This is relevant in case two of the stores overlap.) - /// - /// # Safety - /// Unmasked values in `T` must be writeable as if by `::write` (e.g. aligned to the element - /// type). - /// - /// `mask` must only contain `0` or `!0` values. - #[rustc_nounwind] - pub fn simd_scatter(val: T, ptr: U, mask: V); - - /// Reads a vector of pointers. - /// - /// `T` must be a vector. - /// - /// `U` must be a pointer to the element type of `T` - /// - /// `V` must be a vector of integers with the same length as `T` (but any element size). - /// - /// For each element, if the corresponding value in `mask` is `!0`, read the corresponding - /// pointer offset from `ptr`. - /// The first element is loaded from `ptr`, the second from `ptr.wrapping_offset(1)` and so on. - /// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from - /// `val`. - /// - /// # Safety - /// Unmasked values in `T` must be readable as if by `::read` (e.g. aligned to the element - /// type). - /// - /// `mask` must only contain `0` or `!0` values. - #[rustc_nounwind] - pub fn simd_masked_load(mask: V, ptr: U, val: T) -> T; - - /// Writes to a vector of pointers. - /// - /// `T` must be a vector. - /// - /// `U` must be a pointer to the element type of `T` - /// - /// `V` must be a vector of integers with the same length as `T` (but any element size). - /// - /// For each element, if the corresponding value in `mask` is `!0`, write the corresponding - /// value in `val` to the pointer offset from `ptr`. - /// The first element is written to `ptr`, the second to `ptr.wrapping_offset(1)` and so on. - /// Otherwise if the corresponding value in `mask` is `0`, do nothing. - /// - /// # Safety - /// Unmasked values in `T` must be writeable as if by `::write` (e.g. aligned to the element - /// type). - /// - /// `mask` must only contain `0` or `!0` values. - #[rustc_nounwind] - pub fn simd_masked_store(mask: V, ptr: U, val: T); - - /// Adds two simd vectors elementwise, with saturation. - /// - /// `T` must be a vector of integer primitive types. - #[rustc_nounwind] - pub fn simd_saturating_add(x: T, y: T) -> T; - - /// Subtracts two simd vectors elementwise, with saturation. - /// - /// `T` must be a vector of integer primitive types. - /// - /// Subtract `rhs` from `lhs`. - #[rustc_nounwind] - pub fn simd_saturating_sub(lhs: T, rhs: T) -> T; - - /// Adds elements within a vector from left to right. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - /// - /// Starting with the value `y`, add the elements of `x` and accumulate. - #[rustc_nounwind] - pub fn simd_reduce_add_ordered(x: T, y: U) -> U; - - /// Adds elements within a vector in arbitrary order. May also be re-associated with - /// unordered additions on the inputs/outputs. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - #[rustc_nounwind] - pub fn simd_reduce_add_unordered(x: T) -> U; - - /// Multiplies elements within a vector from left to right. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - /// - /// Starting with the value `y`, multiply the elements of `x` and accumulate. - #[rustc_nounwind] - pub fn simd_reduce_mul_ordered(x: T, y: U) -> U; - - /// Multiplies elements within a vector in arbitrary order. May also be re-associated with - /// unordered additions on the inputs/outputs. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - #[rustc_nounwind] - pub fn simd_reduce_mul_unordered(x: T) -> U; - - /// Checks if all mask values are true. - /// - /// `T` must be a vector of integer primitive types. - /// - /// # Safety - /// `x` must contain only `0` or `!0`. - #[rustc_nounwind] - pub fn simd_reduce_all(x: T) -> bool; - - /// Checks if any mask value is true. - /// - /// `T` must be a vector of integer primitive types. - /// - /// # Safety - /// `x` must contain only `0` or `!0`. - #[rustc_nounwind] - pub fn simd_reduce_any(x: T) -> bool; - - /// Returns the maximum element of a vector. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - /// - /// For floating-point values, uses IEEE-754 `maxNum`. - #[rustc_nounwind] - pub fn simd_reduce_max(x: T) -> U; - - /// Returns the minimum element of a vector. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - /// - /// For floating-point values, uses IEEE-754 `minNum`. - #[rustc_nounwind] - pub fn simd_reduce_min(x: T) -> U; - - /// Logical "ands" all elements together. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - #[rustc_nounwind] - pub fn simd_reduce_and(x: T) -> U; - - /// Logical "ors" all elements together. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - #[rustc_nounwind] - pub fn simd_reduce_or(x: T) -> U; - - /// Logical "exclusive ors" all elements together. - /// - /// `T` must be a vector of integer or floating-point primitive types. - /// - /// `U` must be the element type of `T`. - #[rustc_nounwind] - pub fn simd_reduce_xor(x: T) -> U; - - /// Truncates an integer vector to a bitmask. - /// - /// `T` must be an integer vector. - /// - /// `U` must be either the smallest unsigned integer with at least as many bits as the length - /// of `T`, or the smallest array of `u8` with at least as many bits as the length of `T`. - /// - /// Each element is truncated to a single bit and packed into the result. - /// - /// No matter whether the output is an array or an unsigned integer, it is treated as a single - /// contiguous list of bits. The bitmask is always packed on the least-significant side of the - /// output, and padded with 0s in the most-significant bits. The order of the bits depends on - /// endianness: - /// - /// * On little endian, the least significant bit corresponds to the first vector element. - /// * On big endian, the least significant bit corresponds to the last vector element. - /// - /// For example, `[!0, 0, !0, !0]` packs to - /// - `0b1101u8` or `[0b1101]` on little endian, and - /// - `0b1011u8` or `[0b1011]` on big endian. - /// - /// To consider a larger example, - /// `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs to - /// - `0b0100001100000001u16` or `[0b00000001, 0b01000011]` on little endian, and - /// - `0b1000000011000010u16` or `[0b10000000, 0b11000010]` on big endian. - /// - /// And finally, a non-power-of-2 example with multiple bytes: - /// `[!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]` packs to - /// - `0b0101001011u16` or `[0b01001011, 0b01]` on little endian, and - /// - `0b1101001010u16` or `[0b11, 0b01001010]` on big endian. - /// - /// # Safety - /// `x` must contain only `0` and `!0`. - #[rustc_nounwind] - pub fn simd_bitmask(x: T) -> U; - - /// Selects elements from a mask. - /// - /// `M` must be an integer vector. - /// - /// `T` must be a vector with the same number of elements as `M`. - /// - /// For each element, if the corresponding value in `mask` is `!0`, select the element from - /// `if_true`. If the corresponding value in `mask` is `0`, select the element from - /// `if_false`. - /// - /// # Safety - /// `mask` must only contain `0` and `!0`. - #[rustc_nounwind] - pub fn simd_select(mask: M, if_true: T, if_false: T) -> T; - - /// Selects elements from a bitmask. - /// - /// `M` must be an unsigned integer or array of `u8`, matching `simd_bitmask`. - /// - /// `T` must be a vector. - /// - /// For each element, if the bit in `mask` is `1`, select the element from - /// `if_true`. If the corresponding bit in `mask` is `0`, select the element from - /// `if_false`. - /// - /// The bitmask bit order matches `simd_bitmask`. - /// - /// # Safety - /// Padding bits must be all zero. - #[rustc_nounwind] - pub fn simd_select_bitmask(m: M, yes: T, no: T) -> T; - - /// Calculates the offset from a pointer vector elementwise, potentially - /// wrapping. - /// - /// `T` must be a vector of pointers. - /// - /// `U` must be a vector of `isize` or `usize` with the same number of elements as `T`. - /// - /// Operates as if by `::wrapping_offset`. - #[rustc_nounwind] - pub fn simd_arith_offset(ptr: T, offset: U) -> T; - - /// Casts a vector of pointers. - /// - /// `T` and `U` must be vectors of pointers with the same number of elements. - #[rustc_nounwind] - pub fn simd_cast_ptr(ptr: T) -> U; - - /// Exposes a vector of pointers as a vector of addresses. - /// - /// `T` must be a vector of pointers. - /// - /// `U` must be a vector of `usize` with the same length as `T`. - #[rustc_nounwind] - pub fn simd_expose_provenance(ptr: T) -> U; - - /// Creates a vector of pointers from a vector of addresses. - /// - /// `T` must be a vector of `usize`. - /// - /// `U` must be a vector of pointers, with the same length as `T`. - #[rustc_nounwind] - pub fn simd_with_exposed_provenance(addr: T) -> U; - - /// Swaps bytes of each element. - /// - /// `T` must be a vector of integers. - #[rustc_nounwind] - pub fn simd_bswap(x: T) -> T; - - /// Reverses bits of each element. - /// - /// `T` must be a vector of integers. - #[rustc_nounwind] - pub fn simd_bitreverse(x: T) -> T; - - /// Counts the leading zeros of each element. - /// - /// `T` must be a vector of integers. - #[rustc_nounwind] - pub fn simd_ctlz(x: T) -> T; - - /// Counts the number of ones in each element. - /// - /// `T` must be a vector of integers. - #[rustc_nounwind] - pub fn simd_ctpop(x: T) -> T; - - /// Counts the trailing zeros of each element. - /// - /// `T` must be a vector of integers. - #[rustc_nounwind] - pub fn simd_cttz(x: T) -> T; - - /// Rounds up each element to the next highest integer-valued float. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_ceil(x: T) -> T; - - /// Rounds down each element to the next lowest integer-valued float. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_floor(x: T) -> T; - - /// Rounds each element to the closest integer-valued float. - /// Ties are resolved by rounding away from 0. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_round(x: T) -> T; - - /// Returns the integer part of each element as an integer-valued float. - /// In other words, non-integer values are truncated towards zero. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_trunc(x: T) -> T; - - /// Takes the square root of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_fsqrt(x: T) -> T; - - /// Computes `(x*y) + z` for each element, but without any intermediate rounding. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_fma(x: T, y: T, z: T) -> T; - - /// Computes `(x*y) + z` for each element, non-deterministically executing either - /// a fused multiply-add or two operations with rounding of the intermediate result. - /// - /// The operation is fused if the code generator determines that target instruction - /// set has support for a fused operation, and that the fused operation is more efficient - /// than the equivalent, separate pair of mul and add instructions. It is unspecified - /// whether or not a fused operation is selected, and that may depend on optimization - /// level and context, for example. It may even be the case that some SIMD lanes get fused - /// and others do not. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_relaxed_fma(x: T, y: T, z: T) -> T; - - // Computes the sine of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_fsin(a: T) -> T; - - // Computes the cosine of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_fcos(a: T) -> T; - - // Computes the exponential function of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_fexp(a: T) -> T; - - // Computes 2 raised to the power of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_fexp2(a: T) -> T; - - // Computes the base 10 logarithm of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_flog10(a: T) -> T; - - // Computes the base 2 logarithm of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_flog2(a: T) -> T; - - // Computes the natural logarithm of each element. - /// - /// `T` must be a vector of floats. - #[rustc_nounwind] - pub fn simd_flog(a: T) -> T; +/// Inserts an element into a vector, returning the updated vector. +/// +/// `T` must be a vector with element type `U`. +/// +/// # Safety +/// +/// `idx` must be in-bounds of the vector. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_insert(_x: T, _idx: u32, _val: U) -> T { + unreachable!() +} + +/// Extracts an element from a vector. +/// +/// `T` must be a vector with element type `U`. +/// +/// # Safety +/// +/// `idx` must be in-bounds of the vector. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_extract(_x: T, _idx: u32) -> U { + unreachable!() +} + +/// Adds two simd vectors elementwise. +/// +/// `T` must be a vector of integer or floating point primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_add(_x: T, _y: T) -> T { + unreachable!() +} + +/// Subtracts `rhs` from `lhs` elementwise. +/// +/// `T` must be a vector of integer or floating point primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_sub(_lhs: T, _rhs: T) -> T { + unreachable!() +} + +/// Multiplies two simd vectors elementwise. +/// +/// `T` must be a vector of integer or floating point primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_mul(_x: T, _y: T) -> T { + unreachable!() +} + +/// Divides `lhs` by `rhs` elementwise. +/// +/// `T` must be a vector of integer or floating point primitive types. +/// +/// # Safety +/// For integers, `rhs` must not contain any zero elements. +/// Additionally for signed integers, `::MIN / -1` is undefined behavior. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_div(_lhs: T, _rhs: T) -> T { + unreachable!() +} + +/// Returns remainder of two vectors elementwise. +/// +/// `T` must be a vector of integer or floating point primitive types. +/// +/// # Safety +/// For integers, `rhs` must not contain any zero elements. +/// Additionally for signed integers, `::MIN / -1` is undefined behavior. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_rem(_lhs: T, _rhs: T) -> T { + unreachable!() +} + +/// Shifts vector left elementwise, with UB on overflow. +/// +/// Shifts `lhs` left by `rhs`, shifting in sign bits for signed types. +/// +/// `T` must be a vector of integer primitive types. +/// +/// # Safety +/// +/// Each element of `rhs` must be less than `::BITS`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_shl(_lhs: T, _rhs: T) -> T { + unreachable!() +} + +/// Shifts vector right elementwise, with UB on overflow. +/// +/// `T` must be a vector of integer primitive types. +/// +/// Shifts `lhs` right by `rhs`, shifting in sign bits for signed types. +/// +/// # Safety +/// +/// Each element of `rhs` must be less than `::BITS`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_shr(_lhs: T, _rhs: T) -> T { + unreachable!() +} + +/// "Ands" vectors elementwise. +/// +/// `T` must be a vector of integer primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_and(_x: T, _y: T) -> T { + unreachable!() +} + +/// "Ors" vectors elementwise. +/// +/// `T` must be a vector of integer primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_or(_x: T, _y: T) -> T { + unreachable!() +} + +/// "Exclusive ors" vectors elementwise. +/// +/// `T` must be a vector of integer primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_xor(_x: T, _y: T) -> T { + unreachable!() +} + +/// Numerically casts a vector, elementwise. +/// +/// `T` and `U` must be vectors of integer or floating point primitive types, and must have the +/// same length. +/// +/// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB. +/// When casting integers to floats, the result is rounded. +/// Otherwise, truncates or extends the value, maintaining the sign for signed integers. +/// +/// # Safety +/// Casting from integer types is always safe. +/// Casting between two float types is also always safe. +/// +/// Casting floats to integers truncates, following the same rules as `to_int_unchecked`. +/// Specifically, each element must: +/// * Not be `NaN` +/// * Not be infinite +/// * Be representable in the return type, after truncating off its fractional part +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_cast(_x: T) -> U { + unreachable!() +} + +/// Numerically casts a vector, elementwise. +/// +/// `T` and `U` be a vectors of integer or floating point primitive types, and must have the +/// same length. +/// +/// Like `simd_cast`, but saturates float-to-integer conversions (NaN becomes 0). +/// This matches regular `as` and is always safe. +/// +/// When casting floats to integers, the result is truncated. +/// When casting integers to floats, the result is rounded. +/// Otherwise, truncates or extends the value, maintaining the sign for signed integers. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_as(_x: T) -> U { + unreachable!() +} + +/// Negates a vector elementwise. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// Rust panics for `-::Min` due to overflow, but it is not UB with this intrinsic. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_neg(_x: T) -> T { + unreachable!() +} + +/// Returns absolute value of a vector, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fabs(_x: T) -> T { + unreachable!() +} + +/// Returns the minimum of two vectors, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// Follows IEEE-754 `minNum` semantics. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fmin(_x: T, _y: T) -> T { + unreachable!() +} + +/// Returns the maximum of two vectors, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// Follows IEEE-754 `maxNum` semantics. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fmax(_x: T, _y: T) -> T { + unreachable!() +} + +/// Tests elementwise equality of two vectors. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// `U` must be a vector of integers with the same number of elements and element size as `T`. +/// +/// Returns `0` for false and `!0` for true. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_eq(_x: T, _y: T) -> U { + unreachable!() +} + +/// Tests elementwise inequality equality of two vectors. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// `U` must be a vector of integers with the same number of elements and element size as `T`. +/// +/// Returns `0` for false and `!0` for true. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_ne(_x: T, _y: T) -> U { + unreachable!() +} + +/// Tests if `x` is less than `y`, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// `U` must be a vector of integers with the same number of elements and element size as `T`. +/// +/// Returns `0` for false and `!0` for true. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_lt(_x: T, _y: T) -> U { + unreachable!() +} + +/// Tests if `x` is less than or equal to `y`, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// `U` must be a vector of integers with the same number of elements and element size as `T`. +/// +/// Returns `0` for false and `!0` for true. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_le(_x: T, _y: T) -> U { + unreachable!() +} + +/// Tests if `x` is greater than `y`, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// `U` must be a vector of integers with the same number of elements and element size as `T`. +/// +/// Returns `0` for false and `!0` for true. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_gt(_x: T, _y: T) -> U { + unreachable!() +} + +/// Tests if `x` is greater than or equal to `y`, elementwise. +/// +/// `T` must be a vector of floating-point primitive types. +/// +/// `U` must be a vector of integers with the same number of elements and element size as `T`. +/// +/// Returns `0` for false and `!0` for true. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_ge(_x: T, _y: T) -> U { + unreachable!() +} + +/// Shuffles two vectors by const indices. +/// +/// `T` must be a vector. +/// +/// `U` must be a **const** vector of `u32`s. This means it must either refer to a named +/// const or be given as an inline const expression (`const { ... }`). +/// +/// `V` must be a vector with the same element type as `T` and the same length as `U`. +/// +/// Returns a new vector such that element `i` is selected from `xy[idx[i]]`, where `xy` +/// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds +/// of `xy`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_shuffle(_x: T, _y: T, _idx: U) -> V { + unreachable!() +} + +/// Reads a vector of pointers. +/// +/// `T` must be a vector. +/// +/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. +/// +/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// +/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer. +/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from +/// `val`. +/// +/// # Safety +/// Unmasked values in `T` must be readable as if by `::read` (e.g. aligned to the element +/// type). +/// +/// `mask` must only contain `0` or `!0` values. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_gather(_val: T, _ptr: U, _mask: V) -> T { + unreachable!() +} + +/// Writes to a vector of pointers. +/// +/// `T` must be a vector. +/// +/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. +/// +/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// +/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the +/// corresponding value in `val` to the pointer. +/// Otherwise if the corresponding value in `mask` is `0`, do nothing. +/// +/// The stores happen in left-to-right order. +/// (This is relevant in case two of the stores overlap.) +/// +/// # Safety +/// Unmasked values in `T` must be writeable as if by `::write` (e.g. aligned to the element +/// type). +/// +/// `mask` must only contain `0` or `!0` values. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_scatter(_val: T, _ptr: U, _mask: V) { + unreachable!() +} + +/// Reads a vector of pointers. +/// +/// `T` must be a vector. +/// +/// `U` must be a pointer to the element type of `T` +/// +/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// +/// For each element, if the corresponding value in `mask` is `!0`, read the corresponding +/// pointer offset from `ptr`. +/// The first element is loaded from `ptr`, the second from `ptr.wrapping_offset(1)` and so on. +/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from +/// `val`. +/// +/// # Safety +/// Unmasked values in `T` must be readable as if by `::read` (e.g. aligned to the element +/// type). +/// +/// `mask` must only contain `0` or `!0` values. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_masked_load(_mask: V, _ptr: U, _val: T) -> T { + unreachable!() +} + +/// Writes to a vector of pointers. +/// +/// `T` must be a vector. +/// +/// `U` must be a pointer to the element type of `T` +/// +/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// +/// For each element, if the corresponding value in `mask` is `!0`, write the corresponding +/// value in `val` to the pointer offset from `ptr`. +/// The first element is written to `ptr`, the second to `ptr.wrapping_offset(1)` and so on. +/// Otherwise if the corresponding value in `mask` is `0`, do nothing. +/// +/// # Safety +/// Unmasked values in `T` must be writeable as if by `::write` (e.g. aligned to the element +/// type). +/// +/// `mask` must only contain `0` or `!0` values. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_masked_store(_mask: V, _ptr: U, _val: T) { + unreachable!() +} + +/// Adds two simd vectors elementwise, with saturation. +/// +/// `T` must be a vector of integer primitive types. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_saturating_add(_x: T, _y: T) -> T { + unreachable!() +} + +/// Subtracts two simd vectors elementwise, with saturation. +/// +/// `T` must be a vector of integer primitive types. +/// +/// Subtract `rhs` from `lhs`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_saturating_sub(_lhs: T, _rhs: T) -> T { + unreachable!() +} + +/// Adds elements within a vector from left to right. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +/// +/// Starting with the value `y`, add the elements of `x` and accumulate. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_add_ordered(_x: T, _y: U) -> U { + unreachable!() +} + +/// Adds elements within a vector in arbitrary order. May also be re-associated with +/// unordered additions on the inputs/outputs. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_add_unordered(_x: T) -> U { + unreachable!() +} + +/// Multiplies elements within a vector from left to right. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +/// +/// Starting with the value `y`, multiply the elements of `x` and accumulate. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_mul_ordered(_x: T, _y: U) -> U { + unreachable!() +} + +/// Multiplies elements within a vector in arbitrary order. May also be re-associated with +/// unordered additions on the inputs/outputs. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_mul_unordered(_x: T) -> U { + unreachable!() +} + +/// Checks if all mask values are true. +/// +/// `T` must be a vector of integer primitive types. +/// +/// # Safety +/// `x` must contain only `0` or `!0`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_all(_x: T) -> bool { + unreachable!() +} + +/// Checks if any mask value is true. +/// +/// `T` must be a vector of integer primitive types. +/// +/// # Safety +/// `x` must contain only `0` or `!0`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_any(_x: T) -> bool { + unreachable!() +} + +/// Returns the maximum element of a vector. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +/// +/// For floating-point values, uses IEEE-754 `maxNum`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_max(_x: T) -> U { + unreachable!() +} + +/// Returns the minimum element of a vector. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +/// +/// For floating-point values, uses IEEE-754 `minNum`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_min(_x: T) -> U { + unreachable!() +} + +/// Logical "ands" all elements together. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_and(_x: T) -> U { + unreachable!() +} + +/// Logical "ors" all elements together. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_or(_x: T) -> U { + unreachable!() +} + +/// Logical "exclusive ors" all elements together. +/// +/// `T` must be a vector of integer or floating-point primitive types. +/// +/// `U` must be the element type of `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_reduce_xor(_x: T) -> U { + unreachable!() +} + +/// Truncates an integer vector to a bitmask. +/// +/// `T` must be an integer vector. +/// +/// `U` must be either the smallest unsigned integer with at least as many bits as the length +/// of `T`, or the smallest array of `u8` with at least as many bits as the length of `T`. +/// +/// Each element is truncated to a single bit and packed into the result. +/// +/// No matter whether the output is an array or an unsigned integer, it is treated as a single +/// contiguous list of bits. The bitmask is always packed on the least-significant side of the +/// output, and padded with 0s in the most-significant bits. The order of the bits depends on +/// endianness: +/// +/// * On little endian, the least significant bit corresponds to the first vector element. +/// * On big endian, the least significant bit corresponds to the last vector element. +/// +/// For example, `[!0, 0, !0, !0]` packs to +/// - `0b1101u8` or `[0b1101]` on little endian, and +/// - `0b1011u8` or `[0b1011]` on big endian. +/// +/// To consider a larger example, +/// `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs to +/// - `0b0100001100000001u16` or `[0b00000001, 0b01000011]` on little endian, and +/// - `0b1000000011000010u16` or `[0b10000000, 0b11000010]` on big endian. +/// +/// And finally, a non-power-of-2 example with multiple bytes: +/// `[!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]` packs to +/// - `0b0101001011u16` or `[0b01001011, 0b01]` on little endian, and +/// - `0b1101001010u16` or `[0b11, 0b01001010]` on big endian. +/// +/// # Safety +/// `x` must contain only `0` and `!0`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_bitmask(_x: T) -> U { + unreachable!() +} + +/// Selects elements from a mask. +/// +/// `M` must be an integer vector. +/// +/// `T` must be a vector with the same number of elements as `M`. +/// +/// For each element, if the corresponding value in `mask` is `!0`, select the element from +/// `if_true`. If the corresponding value in `mask` is `0`, select the element from +/// `if_false`. +/// +/// # Safety +/// `mask` must only contain `0` and `!0`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_select(_mask: M, _if_true: T, _if_false: T) -> T { + unreachable!() +} + +/// Selects elements from a bitmask. +/// +/// `M` must be an unsigned integer or array of `u8`, matching `simd_bitmask`. +/// +/// `T` must be a vector. +/// +/// For each element, if the bit in `mask` is `1`, select the element from +/// `if_true`. If the corresponding bit in `mask` is `0`, select the element from +/// `if_false`. +/// +/// The bitmask bit order matches `simd_bitmask`. +/// +/// # Safety +/// Padding bits must be all zero. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_select_bitmask(_m: M, _yes: T, _no: T) -> T { + unreachable!() +} + +/// Calculates the offset from a pointer vector elementwise, potentially +/// wrapping. +/// +/// `T` must be a vector of pointers. +/// +/// `U` must be a vector of `isize` or `usize` with the same number of elements as `T`. +/// +/// Operates as if by `::wrapping_offset`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_arith_offset(_ptr: T, _offset: U) -> T { + unreachable!() +} + +/// Casts a vector of pointers. +/// +/// `T` and `U` must be vectors of pointers with the same number of elements. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_cast_ptr(_ptr: T) -> U { + unreachable!() +} + +/// Exposes a vector of pointers as a vector of addresses. +/// +/// `T` must be a vector of pointers. +/// +/// `U` must be a vector of `usize` with the same length as `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_expose_provenance(_ptr: T) -> U { + unreachable!() +} + +/// Creates a vector of pointers from a vector of addresses. +/// +/// `T` must be a vector of `usize`. +/// +/// `U` must be a vector of pointers, with the same length as `T`. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_with_exposed_provenance(_addr: T) -> U { + unreachable!() +} + +/// Swaps bytes of each element. +/// +/// `T` must be a vector of integers. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_bswap(_x: T) -> T { + unreachable!() +} + +/// Reverses bits of each element. +/// +/// `T` must be a vector of integers. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_bitreverse(_x: T) -> T { + unreachable!() +} + +/// Counts the leading zeros of each element. +/// +/// `T` must be a vector of integers. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_ctlz(_x: T) -> T { + unreachable!() +} + +/// Counts the number of ones in each element. +/// +/// `T` must be a vector of integers. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_ctpop(_x: T) -> T { + unreachable!() +} + +/// Counts the trailing zeros of each element. +/// +/// `T` must be a vector of integers. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_cttz(_x: T) -> T { + unreachable!() +} + +/// Rounds up each element to the next highest integer-valued float. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_ceil(_x: T) -> T { + unreachable!() +} + +/// Rounds down each element to the next lowest integer-valued float. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_floor(_x: T) -> T { + unreachable!() +} + +/// Rounds each element to the closest integer-valued float. +/// Ties are resolved by rounding away from 0. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_round(_x: T) -> T { + unreachable!() +} + +/// Returns the integer part of each element as an integer-valued float. +/// In other words, non-integer values are truncated towards zero. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_trunc(_x: T) -> T { + unreachable!() +} + +/// Takes the square root of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fsqrt(_x: T) -> T { + unreachable!() +} + +/// Computes `(x*y) + z` for each element, but without any intermediate rounding. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fma(_x: T, _y: T, _z: T) -> T { + unreachable!() +} + +/// Computes `(x*y) + z` for each element, non-deterministically executing either +/// a fused multiply-add or two operations with rounding of the intermediate result. +/// +/// The operation is fused if the code generator determines that target instruction +/// set has support for a fused operation, and that the fused operation is more efficient +/// than the equivalent, separate pair of mul and add instructions. It is unspecified +/// whether or not a fused operation is selected, and that may depend on optimization +/// level and context, for example. It may even be the case that some SIMD lanes get fused +/// and others do not. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_relaxed_fma(_x: T, _y: T, _z: T) -> T { + unreachable!() +} + +// Computes the sine of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fsin(_a: T) -> T { + unreachable!() +} + +// Computes the cosine of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fcos(_a: T) -> T { + unreachable!() +} + +// Computes the exponential function of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fexp(_a: T) -> T { + unreachable!() +} + +// Computes 2 raised to the power of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_fexp2(_a: T) -> T { + unreachable!() +} + +// Computes the base 10 logarithm of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_flog10(_a: T) -> T { + unreachable!() +} + +// Computes the base 2 logarithm of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_flog2(_a: T) -> T { + unreachable!() +} + +// Computes the natural logarithm of each element. +/// +/// `T` must be a vector of floats. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +pub unsafe fn simd_flog(_a: T) -> T { + unreachable!() } From 71f270a4f85418bcba7ce94c4cbd6c884be0a4d8 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Fri, 24 Jan 2025 23:26:02 -0700 Subject: [PATCH 360/481] docs: fix typo in std::pin overview --- core/src/pin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/pin.rs b/core/src/pin.rs index 71044190f0c88..2a0bf89fcf7a9 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -156,8 +156,8 @@ //! //! In order to implement the second option, we must in some way enforce its key invariant, //! *i.e.* prevent the value from being *moved* or otherwise invalidated (you may notice this -//! sounds an awful lot like the definition of *pinning* a value). There a few ways one might be -//! able to enforce this invariant in Rust: +//! sounds an awful lot like the definition of *pinning* a value). There are a few ways one might +//! 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 From f7ad46a1c7e95b0186963f7ed9f1a36f28dd7239 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 13 Dec 2024 14:49:40 -0600 Subject: [PATCH 361/481] fix(libtest): Deprecate '--logfile' rust-lang/testing-devex-team#9 proposed changing the behavior of `--logfile`. The given reasons were: (1) Bazel can't programmatically process stdout. This seems like a limitation in Bazel and we recommend focusing on that. If we look at the wider Rust ecosystem, Rustc and Cargo don't support any such mechanism and the Cargo team rejected having one. Expecting this in libtest when its not supported elsewhere seems too specialized. (2) Tests that leak out non-programmatic output that intermixes with programmatic output. We acknowledge this is a problem to be evaluated but we need to make sure we are stepping back and gathering requirements, rather than assuming `--logfile` will fit the needs. Independent of the motive, regarding using or changing `--logfile` (1) Most ways to do it would be a breaking change, like if we respect any stable `--format`. As suggested above, we could specialize this to new `--format` values but that would be confusing for some values to apply but not others. (2) Other ways of solving this add new features to lib`test` when we are instead wanting to limit the feature set it has to minimize the compatibility surface that has to be maintained and the burden it would put on third party harnesses which are a focus area. Examples include `--format compact` or a `--log-format` flag (3) The existence of `--logfile` dates back quite a ways (https://github.com/rust-lang/rust/commit/5cc050b265509c19717e11e12dd785d8c73f5b11, rust-lang/rust#2127) and the history gives the impression this more of slipped through rather than being an intended feature (see also https://github.com/rust-lang/rust/pull/82350#discussion_r579732071). Deprecation would better match to how it has been treated. By deprecating this, we do not expect custom test harnesses (rust-lang/testing-devex-team#2) to implement this. T-testing-devex held an FCP for deprecating in rust-lang/testing-devex-team#9 though according to [RFC #3455](https://rust-lang.github.io/rfcs/3455-t-test.html), this is still subject to final approval from T-libs-api. --- test/src/cli.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/src/cli.rs b/test/src/cli.rs index 52c8091762346..ef6786f431670 100644 --- a/test/src/cli.rs +++ b/test/src/cli.rs @@ -1,7 +1,7 @@ //! Module converting command-line arguments into test configuration. use std::env; -use std::io::{self, IsTerminal}; +use std::io::{self, IsTerminal, Write}; use std::path::PathBuf; use super::options::{ColorConfig, Options, OutputFormat, RunIgnored}; @@ -58,7 +58,7 @@ fn optgroups() -> getopts::Options { .optflag("", "bench", "Run benchmarks instead of tests") .optflag("", "list", "List all tests and benchmarks") .optflag("h", "help", "Display this message") - .optopt("", "logfile", "Write logs to the specified file", "PATH") + .optopt("", "logfile", "Write logs to the specified file (deprecated)", "PATH") .optflag( "", "nocapture", @@ -281,6 +281,10 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { let options = Options::new().display_output(matches.opt_present("show-output")); + if logfile.is_some() { + let _ = write!(io::stderr(), "warning: `--logfile` is deprecated"); + } + let test_opts = TestOpts { list, filters, From da7e12358ba3aca52591b3cf0773b07b4adab84d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 19:01:47 +0000 Subject: [PATCH 362/481] Fix testing of the standard library with Emscripten This does need EMCC_CFLAGS="-s MAXIMUM_MEMORY=2GB" avoid several OOMs. --- alloc/benches/btree/map.rs | 1 + alloc/benches/slice.rs | 11 +++++++++++ alloc/benches/vec.rs | 5 +++++ alloc/tests/sort/tests.rs | 9 ++++++++- alloc/tests/sync.rs | 1 + std/src/io/copy/tests.rs | 1 + std/tests/pipe_subprocess.rs | 2 +- std/tests/process_spawning.rs | 3 ++- 8 files changed, 30 insertions(+), 3 deletions(-) diff --git a/alloc/benches/btree/map.rs b/alloc/benches/btree/map.rs index b8119c9f0ebf4..5b15aaeddbc40 100644 --- a/alloc/benches/btree/map.rs +++ b/alloc/benches/btree/map.rs @@ -353,6 +353,7 @@ pub fn iter_10k(b: &mut Bencher) { } #[bench] +#[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM pub fn iter_1m(b: &mut Bencher) { bench_iter(b, 1_000, 1_000_000); } diff --git a/alloc/benches/slice.rs b/alloc/benches/slice.rs index 48c74c4491dc8..c45c372271297 100644 --- a/alloc/benches/slice.rs +++ b/alloc/benches/slice.rs @@ -366,14 +366,25 @@ rotate!(rotate_medium_half, gen_random, 9158, 9158 / 2); rotate!(rotate_medium_half_plus_one, gen_random, 9158, 9158 / 2 + 1); // Intended to use more RAM than the machine has cache +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by1, gen_random, 5 * 1024 * 1024, 1); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by9199_u64, gen_random, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by9199_bytes, gen_random_bytes, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by9199_strings, gen_strings, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by9199_big, gen_big_random, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by1234577_u64, gen_random, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by1234577_bytes, gen_random_bytes, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by1234577_strings, gen_strings, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_by1234577_big, gen_big_random, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_half, gen_random, 5 * 1024 * 1024, 5 * 1024 * 1024 / 2); +#[cfg(not(target_os = "emscripten"))] // hits an OOM rotate!(rotate_huge_half_plus_one, gen_random, 5 * 1024 * 1024, 5 * 1024 * 1024 / 2 + 1); diff --git a/alloc/benches/vec.rs b/alloc/benches/vec.rs index d29ffae9d70b1..a725ad6894b9c 100644 --- a/alloc/benches/vec.rs +++ b/alloc/benches/vec.rs @@ -547,6 +547,11 @@ fn bench_in_place_collect_droppable(b: &mut Bencher) { }) } +// node.js gives out of memory error to use with length 1_100_000 +#[cfg(target_os = "emscripten")] +const LEN: usize = 4096; + +#[cfg(not(target_os = "emscripten"))] const LEN: usize = 16384; #[bench] diff --git a/alloc/tests/sort/tests.rs b/alloc/tests/sort/tests.rs index 4cc79010e8fed..d321f8df51898 100644 --- a/alloc/tests/sort/tests.rs +++ b/alloc/tests/sort/tests.rs @@ -11,7 +11,14 @@ use crate::sort::{Sort, known_good_stable_sort, patterns}; #[cfg(miri)] const TEST_LENGTHS: &[usize] = &[2, 3, 4, 7, 10, 15, 20, 24, 33, 50, 100, 171, 300]; -#[cfg(not(miri))] +// node.js gives out of memory error to use with length 1_100_000 +#[cfg(all(not(miri), target_os = "emscripten"))] +const TEST_LENGTHS: &[usize] = &[ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, + 2_048, 5_000, 10_000, 100_000, +]; + +#[cfg(all(not(miri), not(target_os = "emscripten")))] const TEST_LENGTHS: &[usize] = &[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, 2_048, 5_000, 10_000, 100_000, 1_100_000, diff --git a/alloc/tests/sync.rs b/alloc/tests/sync.rs index 7a9a4abfdc672..6d3ab1b1d11e1 100644 --- a/alloc/tests/sync.rs +++ b/alloc/tests/sync.rs @@ -128,6 +128,7 @@ fn try_unwrap() { } #[test] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn into_inner() { for _ in 0..100 // ^ Increase chances of hitting potential race conditions diff --git a/std/src/io/copy/tests.rs b/std/src/io/copy/tests.rs index 2e0eb6cdce666..25b1ece2745b9 100644 --- a/std/src/io/copy/tests.rs +++ b/std/src/io/copy/tests.rs @@ -126,6 +126,7 @@ mod io_benches { use crate::io::prelude::*; #[bench] + #[cfg_attr(target_os = "emscripten", ignore)] // no /dev fn bench_copy_buf_reader(b: &mut Bencher) { let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed"); // use dyn to avoid specializations unrelated to readbuf diff --git a/std/tests/pipe_subprocess.rs b/std/tests/pipe_subprocess.rs index df946cdcf2b70..00d99a578d580 100644 --- a/std/tests/pipe_subprocess.rs +++ b/std/tests/pipe_subprocess.rs @@ -1,7 +1,7 @@ #![feature(anonymous_pipe)] fn main() { - #[cfg(all(not(miri), any(unix, windows)))] + #[cfg(all(not(miri), any(unix, windows), not(target_os = "emscripten")))] { use std::io::{Read, pipe}; use std::{env, process}; diff --git a/std/tests/process_spawning.rs b/std/tests/process_spawning.rs index 3e72e371ade19..43b45cb2d2b5c 100644 --- a/std/tests/process_spawning.rs +++ b/std/tests/process_spawning.rs @@ -5,7 +5,8 @@ use std::{env, fs, process, str}; mod common; #[test] -#[cfg_attr(any(miri, target_os = "wasi"), ignore)] // Process spawning not supported by Miri and wasi +// Process spawning not supported by Miri, Emscripten and wasi +#[cfg_attr(any(miri, target_os = "emscripten", target_os = "wasi"), ignore)] fn issue_15149() { // If we're the parent, copy our own binary to a new directory. let my_path = env::current_exe().unwrap(); From f5c42c83f3e0e930b43912e3706c94d939af9c7c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 19:03:12 +0000 Subject: [PATCH 363/481] Remove a bunch of emscripten test ignores They are either outdated as emscripten now supports i128 or they are subsumed by #[cfg_attr(not(panic = "unwind"), ignore] --- alloc/tests/collections/binary_heap.rs | 2 - alloc/tests/lib.rs | 3 -- alloc/tests/slice.rs | 1 - alloc/tests/vec.rs | 4 -- core/tests/hash/mod.rs | 3 -- core/tests/num/flt2dec/random.rs | 6 --- core/tests/num/ops.rs | 52 ++++++++++++++------------ core/tests/num/wrapping.rs | 2 - std/src/f64/tests.rs | 3 -- std/src/io/tests.rs | 2 - test/src/tests.rs | 10 ----- 11 files changed, 29 insertions(+), 59 deletions(-) diff --git a/alloc/tests/collections/binary_heap.rs b/alloc/tests/collections/binary_heap.rs index 55405ffe8c4f6..95f4c3e614f5e 100644 --- a/alloc/tests/collections/binary_heap.rs +++ b/alloc/tests/collections/binary_heap.rs @@ -502,9 +502,7 @@ fn test_retain_catch_unwind() { // even if the order might not be correct. // // Destructors must be called exactly once per element. -// FIXME: re-enable emscripten once it can unwind again #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_safe() { use std::cmp; diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs index d8364d750fa8f..391ff04a4b8e4 100644 --- a/alloc/tests/lib.rs +++ b/alloc/tests/lib.rs @@ -94,9 +94,6 @@ fn test_rng() -> rand_xorshift::XorShiftRng { rand::SeedableRng::from_seed(seed) } -// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten. -// See https://github.com/kripken/emscripten-fastcomp/issues/169 -#[cfg(not(target_os = "emscripten"))] #[test] fn test_boxed_hasher() { let ordinary_hash = hash(&5u32); diff --git a/alloc/tests/slice.rs b/alloc/tests/slice.rs index 9625e3d2b5e08..f990a41b679fa 100644 --- a/alloc/tests/slice.rs +++ b/alloc/tests/slice.rs @@ -1414,7 +1414,6 @@ fn test_box_slice_clone() { #[test] #[allow(unused_must_use)] // here, we care about the side effects of `.clone()` -#[cfg_attr(target_os = "emscripten", ignore)] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_box_slice_clone_panics() { use std::sync::Arc; diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index b24daec2968e0..fe1db56414e0c 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1587,9 +1587,7 @@ fn extract_if_complex() { } } -// FIXME: re-enable emscripten once it can unwind again #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn extract_if_consumed_panic() { use std::rc::Rc; @@ -1640,9 +1638,7 @@ fn extract_if_consumed_panic() { } } -// FIXME: Re-enable emscripten once it can catch panics #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn extract_if_unconsumed_panic() { use std::rc::Rc; diff --git a/core/tests/hash/mod.rs b/core/tests/hash/mod.rs index 9f14995f73fe2..1f10a4733b053 100644 --- a/core/tests/hash/mod.rs +++ b/core/tests/hash/mod.rs @@ -141,9 +141,6 @@ fn test_custom_state() { // const { assert!(hash(&Custom { hash: 6 }) == 6) }; } -// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten. -// See https://github.com/kripken/emscripten-fastcomp/issues/169 -#[cfg(not(target_os = "emscripten"))] #[test] fn test_indirect_hasher() { let mut hasher = MyHasher { hash: 0 }; diff --git a/core/tests/num/flt2dec/random.rs b/core/tests/num/flt2dec/random.rs index 99fc23af7ea9d..90042ae03bf7d 100644 --- a/core/tests/num/flt2dec/random.rs +++ b/core/tests/num/flt2dec/random.rs @@ -84,9 +84,6 @@ where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { - if cfg!(target_os = "emscripten") { - return; // using rng pulls in i128 support, which doesn't work - } let mut rng = crate::test_rng(); let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000); iterate("f32_random_equivalence_test", k, n, f, g, |_| { @@ -100,9 +97,6 @@ where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { - if cfg!(target_os = "emscripten") { - return; // using rng pulls in i128 support, which doesn't work - } let mut rng = crate::test_rng(); let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); iterate("f64_random_equivalence_test", k, n, f, g, |_| { diff --git a/core/tests/num/ops.rs b/core/tests/num/ops.rs index ae8b938250ec9..7b2aad4897808 100644 --- a/core/tests/num/ops.rs +++ b/core/tests/num/ops.rs @@ -51,9 +51,7 @@ macro_rules! test_op { }; } -test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, f32, f64); -#[cfg(not(target_os = "emscripten"))] -test_op!(test_neg_defined_128, Neg::neg(0), 0, i128); +test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, i128, f32, f64); test_op!(test_not_defined_bool, Not::not(true), false, bool); @@ -69,17 +67,17 @@ macro_rules! test_arith_op { i16, i32, i64, + i128, isize, u8, u16, u32, u64, + u128, usize, f32, f64 ); - #[cfg(not(target_os = "emscripten"))] - impls_defined!($op, $method($lhs, $rhs), 0, i128, u128); } }; ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal)) => { @@ -93,17 +91,17 @@ macro_rules! test_arith_op { i16, i32, i64, + i128, isize, u8, u16, u32, u64, + u128, usize, f32, f64 ); - #[cfg(not(target_os = "emscripten"))] - impls_defined!($op, $method(&mut $lhs, $rhs), 0, i128, u128); } }; } @@ -131,15 +129,15 @@ macro_rules! test_bitop { i16, i32, i64, + i128, isize, u8, u16, u32, u64, + u128, usize ); - #[cfg(not(target_os = "emscripten"))] - impls_defined!($op, $method(0, 0), 0, i128, u128); impls_defined!($op, $method(false, false), false, bool); } }; @@ -156,15 +154,15 @@ macro_rules! test_bitop_assign { i16, i32, i64, + i128, isize, u8, u16, u32, u64, + u128, usize ); - #[cfg(not(target_os = "emscripten"))] - impls_defined!($op, $method(&mut 0, 0), 0, i128, u128); impls_defined!($op, $method(&mut false, false), false, bool); } }; @@ -182,9 +180,11 @@ macro_rules! test_shift_inner { $(impl_defined!($op, $method(0,0), 0, $lt, $rt);)+ }; ($op:ident::$method:ident, $lt:ty) => { - test_shift_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); - #[cfg(not(target_os = "emscripten"))] - test_shift_inner!($op::$method, $lt, i128, u128); + test_shift_inner!( + $op::$method, $lt, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); }; } @@ -195,9 +195,11 @@ macro_rules! test_shift { ($test_name:ident, $op:ident::$method:ident) => { #[test] fn $test_name() { - test_shift!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); - #[cfg(not(target_os = "emscripten"))] - test_shift!($op::$method, i128, u128); + test_shift!( + $op::$method, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); } }; } @@ -207,9 +209,11 @@ macro_rules! test_shift_assign_inner { $(impl_defined!($op, $method(&mut 0,0), 0, $lt, $rt);)+ }; ($op:ident::$method:ident, $lt:ty) => { - test_shift_assign_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); - #[cfg(not(target_os = "emscripten"))] - test_shift_assign_inner!($op::$method, $lt, i128, u128); + test_shift_assign_inner!( + $op::$method, $lt, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); }; } @@ -220,9 +224,11 @@ macro_rules! test_shift_assign { ($test_name:ident, $op:ident::$method:ident) => { #[test] fn $test_name() { - test_shift_assign!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); - #[cfg(not(target_os = "emscripten"))] - test_shift_assign!($op::$method, i128, u128); + test_shift_assign!( + $op::$method, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); } }; } diff --git a/core/tests/num/wrapping.rs b/core/tests/num/wrapping.rs index c5a7198839517..0b9fca8455b81 100644 --- a/core/tests/num/wrapping.rs +++ b/core/tests/num/wrapping.rs @@ -64,14 +64,12 @@ wrapping_test!(test_wrapping_i8, i8, i8::MIN, i8::MAX); wrapping_test!(test_wrapping_i16, i16, i16::MIN, i16::MAX); wrapping_test!(test_wrapping_i32, i32, i32::MIN, i32::MAX); wrapping_test!(test_wrapping_i64, i64, i64::MIN, i64::MAX); -#[cfg(not(target_os = "emscripten"))] wrapping_test!(test_wrapping_i128, i128, i128::MIN, i128::MAX); wrapping_test!(test_wrapping_isize, isize, isize::MIN, isize::MAX); wrapping_test!(test_wrapping_u8, u8, u8::MIN, u8::MAX); wrapping_test!(test_wrapping_u16, u16, u16::MIN, u16::MAX); wrapping_test!(test_wrapping_u32, u32, u32::MIN, u32::MAX); wrapping_test!(test_wrapping_u64, u64, u64::MIN, u64::MAX); -#[cfg(not(target_os = "emscripten"))] wrapping_test!(test_wrapping_u128, u128, u128::MIN, u128::MAX); wrapping_test!(test_wrapping_usize, usize, usize::MIN, usize::MAX); diff --git a/std/src/f64/tests.rs b/std/src/f64/tests.rs index 3fac2efe0d76c..f5ba2c7b594e9 100644 --- a/std/src/f64/tests.rs +++ b/std/src/f64/tests.rs @@ -112,7 +112,6 @@ fn test_neg_zero() { assert_eq!(Fp::Zero, neg_zero.classify()); } -#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_one() { let one: f64 = 1.0f64; @@ -165,7 +164,6 @@ fn test_is_finite() { assert!((-109.2f64).is_finite()); } -#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_is_normal() { let nan: f64 = f64::NAN; @@ -183,7 +181,6 @@ fn test_is_normal() { assert!(!1e-308f64.is_normal()); } -#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_classify() { let nan: f64 = f64::NAN; diff --git a/std/src/io/tests.rs b/std/src/io/tests.rs index 85098b3bb181f..226cc6011bcab 100644 --- a/std/src/io/tests.rs +++ b/std/src/io/tests.rs @@ -7,7 +7,6 @@ use crate::mem::MaybeUninit; use crate::ops::Deref; #[test] -#[cfg_attr(target_os = "emscripten", ignore)] fn read_until() { let mut buf = Cursor::new(&b"12"[..]); let mut v = Vec::new(); @@ -359,7 +358,6 @@ fn chain_zero_length_read_is_not_eof() { } #[bench] -#[cfg_attr(target_os = "emscripten", ignore)] #[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_read_to_end(b: &mut test::Bencher) { b.iter(|| { diff --git a/test/src/tests.rs b/test/src/tests.rs index abeb364216979..47f581fefae1f 100644 --- a/test/src/tests.rs +++ b/test/src/tests.rs @@ -133,9 +133,7 @@ fn ignored_tests_result_in_ignored() { assert_eq!(result, TrIgnored); } -// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic() { fn f() -> Result<(), String> { @@ -164,9 +162,7 @@ fn test_should_panic() { assert_eq!(result, TrOk); } -// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_good_message() { fn f() -> Result<(), String> { @@ -195,9 +191,7 @@ fn test_should_panic_good_message() { assert_eq!(result, TrOk); } -// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_bad_message() { use crate::tests::TrFailedMsg; @@ -231,9 +225,7 @@ fn test_should_panic_bad_message() { assert_eq!(result, TrFailedMsg(failed_msg.to_string())); } -// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_non_string_message_type() { use std::any::TypeId; @@ -272,9 +264,7 @@ fn test_should_panic_non_string_message_type() { assert_eq!(result, TrFailedMsg(failed_msg)); } -// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] -#[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_but_succeeds() { let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")]; From ba00e46a313fbbbe52ba9fa7d91f93e74703902f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 19:07:24 +0000 Subject: [PATCH 364/481] Update a bunch of comments from before wasi support was added --- std/src/sys/alloc/wasm.rs | 4 ++-- std/src/sys/pal/wasi/mod.rs | 3 +-- std/src/sys/pal/wasm/mod.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/std/src/sys/alloc/wasm.rs b/std/src/sys/alloc/wasm.rs index a308fafc68b15..53fbc9529e590 100644 --- a/std/src/sys/alloc/wasm.rs +++ b/std/src/sys/alloc/wasm.rs @@ -1,6 +1,6 @@ //! This is an implementation of a global allocator on wasm targets when -//! emscripten is not in use. In that situation there's no actual runtime for us -//! to lean on for allocation, so instead we provide our own! +//! emscripten or wasi is not in use. In that situation there's no actual runtime +//! for us to lean on for allocation, so instead we provide our own! //! //! The wasm instruction set has two instructions for getting the current //! amount of memory and growing the amount of memory. These instructions are the diff --git a/std/src/sys/pal/wasi/mod.rs b/std/src/sys/pal/wasi/mod.rs index 5d54c7903065c..361802d101dfb 100644 --- a/std/src/sys/pal/wasi/mod.rs +++ b/std/src/sys/pal/wasi/mod.rs @@ -1,8 +1,7 @@ //! System bindings for the wasm/web platform //! //! This module contains the facade (aka platform-specific) implementations of -//! OS level functionality for wasm. Note that this wasm is *not* the emscripten -//! wasm, so we have no runtime here. +//! OS level functionality for wasm. //! //! This is all super highly experimental and not actually intended for //! wide/production use yet, it's still all in the experimental category. This diff --git a/std/src/sys/pal/wasm/mod.rs b/std/src/sys/pal/wasm/mod.rs index 8141bfac49aad..41fe019f11027 100644 --- a/std/src/sys/pal/wasm/mod.rs +++ b/std/src/sys/pal/wasm/mod.rs @@ -2,7 +2,7 @@ //! //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for wasm. Note that this wasm is *not* the emscripten -//! wasm, so we have no runtime here. +//! or wasi wasm, so we have no runtime here. //! //! This is all super highly experimental and not actually intended for //! wide/production use yet, it's still all in the experimental category. This From 92b70d2dbb096d377ee36c98dd7eb4779bbf94c3 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Thu, 28 Nov 2024 14:06:34 +0100 Subject: [PATCH 365/481] Add new target for supporting Neutrino QNX 6.1 with `io-socket` network stack on aarch64 Signed-off-by: Florian Bartels --- std/Cargo.toml | 3 ++- std/src/sys/pal/unix/process/process_unix.rs | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index da58d7c13bd12..b91b89b7761bc 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -139,7 +139,8 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock"))', + 'cfg(target_env, values("nto71_iosock"))', # 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/std/src/sys/pal/unix/process/process_unix.rs b/std/src/sys/pal/unix/process/process_unix.rs index ec4965c1d7196..cc22b3ecbd0f6 100644 --- a/std/src/sys/pal/unix/process/process_unix.rs +++ b/std/src/sys/pal/unix/process/process_unix.rs @@ -20,7 +20,7 @@ use crate::{fmt, mem, sys}; cfg_if::cfg_if! { // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - if #[cfg(any(target_env = "nto70", target_env = "nto71"))] { + if #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; @@ -191,7 +191,8 @@ impl Command { target_os = "watchos", target_os = "tvos", target_env = "nto70", - target_env = "nto71" + target_env = "nto71", + target_env = "nto71_iosock", )))] unsafe fn do_fork(&mut self) -> Result { cvt(libc::fork()) @@ -202,7 +203,7 @@ impl Command { // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - #[cfg(any(target_env = "nto70", target_env = "nto71"))] + #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] unsafe fn do_fork(&mut self) -> Result { use crate::sys::os::errno; From f5aa09d4b833979a8a77d4f53691cb851139a80e Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Fri, 29 Nov 2024 18:15:05 +0100 Subject: [PATCH 366/481] Add support for QNX 7.1 with io-sock on x64 Signed-off-by: Florian Bartels --- std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index b91b89b7761bc..16e7cb5c3a8bb 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -139,7 +139,7 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock"))', 'cfg(target_env, values("nto71_iosock"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list From 6fa708617286f675e29d08311faea080459f26e6 Mon Sep 17 00:00:00 2001 From: AkhilTThomas Date: Fri, 6 Dec 2024 11:38:25 +0100 Subject: [PATCH 367/481] add nto80 x86-64 and aarch64 target Signed-off-by: Florian Bartels --- std/Cargo.toml | 4 ++-- std/src/sys/pal/unix/process/process_unix.rs | 14 +++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 16e7cb5c3a8bb..9eab75b06961f 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -139,8 +139,8 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock"))', - 'cfg(target_env, values("nto71_iosock"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock", "x86_64-pc-nto-qnx800","aarch64-unknown-nto-qnx800"))', + 'cfg(target_env, values("nto71_iosock", "nto80"))', # 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/std/src/sys/pal/unix/process/process_unix.rs b/std/src/sys/pal/unix/process/process_unix.rs index cc22b3ecbd0f6..2bff192a5bd83 100644 --- a/std/src/sys/pal/unix/process/process_unix.rs +++ b/std/src/sys/pal/unix/process/process_unix.rs @@ -19,8 +19,7 @@ use crate::sys::process::process_common::*; use crate::{fmt, mem, sys}; cfg_if::cfg_if! { - // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - if #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] { + if #[cfg(target_os = "nto")] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; @@ -187,13 +186,7 @@ impl Command { // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. - #[cfg(not(any( - target_os = "watchos", - target_os = "tvos", - target_env = "nto70", - target_env = "nto71", - target_env = "nto71_iosock", - )))] + #[cfg(not(any(target_os = "watchos", target_os = "tvos", target_os = "nto")))] unsafe fn do_fork(&mut self) -> Result { cvt(libc::fork()) } @@ -202,8 +195,7 @@ impl Command { // or closed a file descriptor while the fork() was occurring". // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html - // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] + #[cfg(target_os = "nto")] unsafe fn do_fork(&mut self) -> Result { use crate::sys::os::errno; From a629c50dd4717c2f02b8a728b5d602fccae2e85b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 24 Jan 2025 09:51:59 -0800 Subject: [PATCH 368/481] Add an `unchecked_div` alias to the `Div>` impls --- core/src/num/nonzero.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 8089d6164090d..61e83ebfad7de 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -1185,8 +1185,12 @@ macro_rules! nonzero_integer_signedness_dependent_impls { impl Div> for $Int { type Output = $Int; + /// Same as `self / other.get()`, but because `other` is a `NonZero<_>`, + /// there's never a runtime check for division-by-zero. + /// /// This operation rounds towards zero, truncating any fractional /// part of the exact result, and cannot panic. + #[doc(alias = "unchecked_div")] #[inline] fn div(self, other: NonZero<$Int>) -> $Int { // SAFETY: Division by zero is checked because `other` is non-zero, @@ -1197,6 +1201,9 @@ macro_rules! nonzero_integer_signedness_dependent_impls { #[stable(feature = "nonzero_div_assign", since = "1.79.0")] impl DivAssign> for $Int { + /// Same as `self /= other.get()`, but because `other` is a `NonZero<_>`, + /// there's never a runtime check for division-by-zero. + /// /// This operation rounds towards zero, truncating any fractional /// part of the exact result, and cannot panic. #[inline] From e1c898e8e5be4c733609ab41884e33b1c91d2a01 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:07:14 +0000 Subject: [PATCH 369/481] Put all coretests in a separate crate --- Cargo.lock | 4 +++ Cargo.toml | 1 + core/Cargo.toml | 13 --------- coretests/Cargo.toml | 27 +++++++++++++++++++ {core => coretests}/benches/any.rs | 0 {core => coretests}/benches/array.rs | 0 {core => coretests}/benches/ascii.rs | 0 {core => coretests}/benches/ascii/is_ascii.rs | 0 {core => coretests}/benches/char/methods.rs | 0 {core => coretests}/benches/char/mod.rs | 0 {core => coretests}/benches/fmt.rs | 0 {core => coretests}/benches/hash/mod.rs | 0 {core => coretests}/benches/hash/sip.rs | 0 {core => coretests}/benches/iter.rs | 0 {core => coretests}/benches/lib.rs | 0 .../benches/net/addr_parser.rs | 0 {core => coretests}/benches/net/mod.rs | 0 .../benches/num/dec2flt/mod.rs | 0 .../benches/num/flt2dec/mod.rs | 0 .../benches/num/flt2dec/strategy/dragon.rs | 0 .../benches/num/flt2dec/strategy/grisu.rs | 0 .../benches/num/int_log/mod.rs | 0 .../benches/num/int_pow/mod.rs | 0 .../benches/num/int_sqrt/mod.rs | 0 {core => coretests}/benches/num/mod.rs | 0 {core => coretests}/benches/ops.rs | 0 {core => coretests}/benches/pattern.rs | 0 {core => coretests}/benches/slice.rs | 0 {core => coretests}/benches/str.rs | 0 {core => coretests}/benches/str/char_count.rs | 0 {core => coretests}/benches/str/corpora.rs | 0 {core => coretests}/benches/str/debug.rs | 0 {core => coretests}/benches/str/iter.rs | 0 {core => coretests}/benches/tuple.rs | 0 coretests/lib.rs | 1 + {core => coretests}/tests/alloc.rs | 0 {core => coretests}/tests/any.rs | 0 {core => coretests}/tests/array.rs | 0 {core => coretests}/tests/ascii.rs | 0 {core => coretests}/tests/ascii_char.rs | 0 {core => coretests}/tests/asserting.rs | 0 {core => coretests}/tests/async_iter/mod.rs | 0 {core => coretests}/tests/atomic.rs | 0 {core => coretests}/tests/bool.rs | 0 {core => coretests}/tests/bstr.rs | 0 {core => coretests}/tests/cell.rs | 0 {core => coretests}/tests/char.rs | 0 {core => coretests}/tests/clone.rs | 0 {core => coretests}/tests/cmp.rs | 0 {core => coretests}/tests/const_ptr.rs | 0 {core => coretests}/tests/convert.rs | 0 {core => coretests}/tests/error.rs | 0 {core => coretests}/tests/ffi.rs | 0 {core => coretests}/tests/ffi/cstr.rs | 0 {core => coretests}/tests/fmt/builders.rs | 0 {core => coretests}/tests/fmt/float.rs | 0 {core => coretests}/tests/fmt/mod.rs | 0 {core => coretests}/tests/fmt/num.rs | 0 {core => coretests}/tests/future.rs | 0 {core => coretests}/tests/hash/mod.rs | 0 {core => coretests}/tests/hash/sip.rs | 0 {core => coretests}/tests/intrinsics.rs | 0 {core => coretests}/tests/io/borrowed_buf.rs | 0 {core => coretests}/tests/io/mod.rs | 0 .../tests/iter/adapters/array_chunks.rs | 0 .../tests/iter/adapters/by_ref_sized.rs | 0 .../tests/iter/adapters/chain.rs | 0 .../tests/iter/adapters/cloned.rs | 0 .../tests/iter/adapters/copied.rs | 0 .../tests/iter/adapters/cycle.rs | 0 .../tests/iter/adapters/enumerate.rs | 0 .../tests/iter/adapters/filter.rs | 0 .../tests/iter/adapters/filter_map.rs | 0 .../tests/iter/adapters/flat_map.rs | 0 .../tests/iter/adapters/flatten.rs | 0 .../tests/iter/adapters/fuse.rs | 0 .../tests/iter/adapters/inspect.rs | 0 .../tests/iter/adapters/intersperse.rs | 0 .../tests/iter/adapters/map.rs | 0 .../tests/iter/adapters/map_windows.rs | 0 .../tests/iter/adapters/mod.rs | 0 .../tests/iter/adapters/peekable.rs | 0 .../tests/iter/adapters/scan.rs | 0 .../tests/iter/adapters/skip.rs | 0 .../tests/iter/adapters/skip_while.rs | 0 .../tests/iter/adapters/step_by.rs | 0 .../tests/iter/adapters/take.rs | 0 .../tests/iter/adapters/take_while.rs | 0 .../tests/iter/adapters/zip.rs | 0 {core => coretests}/tests/iter/mod.rs | 0 {core => coretests}/tests/iter/range.rs | 0 {core => coretests}/tests/iter/sources.rs | 0 .../tests/iter/traits/accum.rs | 0 .../tests/iter/traits/double_ended.rs | 0 .../tests/iter/traits/iterator.rs | 0 {core => coretests}/tests/iter/traits/mod.rs | 0 {core => coretests}/tests/iter/traits/step.rs | 0 {core => coretests}/tests/lazy.rs | 0 {core => coretests}/tests/lib.rs | 0 {core => coretests}/tests/macros.rs | 0 {core => coretests}/tests/macros_bootstrap.rs | 0 {core => coretests}/tests/manually_drop.rs | 0 {core => coretests}/tests/mem.rs | 0 {core => coretests}/tests/net/ip_addr.rs | 0 {core => coretests}/tests/net/mod.rs | 0 {core => coretests}/tests/net/parser.rs | 0 {core => coretests}/tests/net/socket_addr.rs | 0 {core => coretests}/tests/nonzero.rs | 0 {core => coretests}/tests/num/bignum.rs | 0 {core => coretests}/tests/num/const_from.rs | 0 .../tests/num/dec2flt/float.rs | 0 .../tests/num/dec2flt/lemire.rs | 0 {core => coretests}/tests/num/dec2flt/mod.rs | 0 .../tests/num/dec2flt/parse.rs | 0 .../tests/num/float_iter_sum_identity.rs | 0 .../tests/num/flt2dec/estimator.rs | 0 {core => coretests}/tests/num/flt2dec/mod.rs | 0 .../tests/num/flt2dec/random.rs | 0 .../tests/num/flt2dec/strategy/dragon.rs | 0 .../tests/num/flt2dec/strategy/grisu.rs | 0 {core => coretests}/tests/num/i128.rs | 0 {core => coretests}/tests/num/i16.rs | 0 {core => coretests}/tests/num/i32.rs | 0 {core => coretests}/tests/num/i64.rs | 0 {core => coretests}/tests/num/i8.rs | 0 {core => coretests}/tests/num/ieee754.rs | 0 {core => coretests}/tests/num/int_log.rs | 0 {core => coretests}/tests/num/int_macros.rs | 0 {core => coretests}/tests/num/int_sqrt.rs | 0 {core => coretests}/tests/num/midpoint.rs | 0 {core => coretests}/tests/num/mod.rs | 0 {core => coretests}/tests/num/nan.rs | 0 {core => coretests}/tests/num/ops.rs | 0 {core => coretests}/tests/num/u128.rs | 0 {core => coretests}/tests/num/u16.rs | 0 {core => coretests}/tests/num/u32.rs | 0 {core => coretests}/tests/num/u64.rs | 0 {core => coretests}/tests/num/u8.rs | 0 {core => coretests}/tests/num/uint_macros.rs | 0 {core => coretests}/tests/num/wrapping.rs | 0 {core => coretests}/tests/ops.rs | 0 {core => coretests}/tests/ops/control_flow.rs | 0 .../tests/ops/from_residual.rs | 0 {core => coretests}/tests/option.rs | 0 {core => coretests}/tests/panic.rs | 0 {core => coretests}/tests/panic/location.rs | 0 {core => coretests}/tests/pattern.rs | 0 {core => coretests}/tests/pin.rs | 0 {core => coretests}/tests/pin_macro.rs | 0 {core => coretests}/tests/ptr.rs | 0 {core => coretests}/tests/result.rs | 0 {core => coretests}/tests/simd.rs | 0 {core => coretests}/tests/slice.rs | 0 {core => coretests}/tests/str.rs | 0 {core => coretests}/tests/str_lossy.rs | 0 {core => coretests}/tests/task.rs | 0 {core => coretests}/tests/time.rs | 0 {core => coretests}/tests/tuple.rs | 0 {core => coretests}/tests/unicode.rs | 0 {core => coretests}/tests/waker.rs | 0 160 files changed, 33 insertions(+), 13 deletions(-) create mode 100644 coretests/Cargo.toml rename {core => coretests}/benches/any.rs (100%) rename {core => coretests}/benches/array.rs (100%) rename {core => coretests}/benches/ascii.rs (100%) rename {core => coretests}/benches/ascii/is_ascii.rs (100%) rename {core => coretests}/benches/char/methods.rs (100%) rename {core => coretests}/benches/char/mod.rs (100%) rename {core => coretests}/benches/fmt.rs (100%) rename {core => coretests}/benches/hash/mod.rs (100%) rename {core => coretests}/benches/hash/sip.rs (100%) rename {core => coretests}/benches/iter.rs (100%) rename {core => coretests}/benches/lib.rs (100%) rename {core => coretests}/benches/net/addr_parser.rs (100%) rename {core => coretests}/benches/net/mod.rs (100%) rename {core => coretests}/benches/num/dec2flt/mod.rs (100%) rename {core => coretests}/benches/num/flt2dec/mod.rs (100%) rename {core => coretests}/benches/num/flt2dec/strategy/dragon.rs (100%) rename {core => coretests}/benches/num/flt2dec/strategy/grisu.rs (100%) rename {core => coretests}/benches/num/int_log/mod.rs (100%) rename {core => coretests}/benches/num/int_pow/mod.rs (100%) rename {core => coretests}/benches/num/int_sqrt/mod.rs (100%) rename {core => coretests}/benches/num/mod.rs (100%) rename {core => coretests}/benches/ops.rs (100%) rename {core => coretests}/benches/pattern.rs (100%) rename {core => coretests}/benches/slice.rs (100%) rename {core => coretests}/benches/str.rs (100%) rename {core => coretests}/benches/str/char_count.rs (100%) rename {core => coretests}/benches/str/corpora.rs (100%) rename {core => coretests}/benches/str/debug.rs (100%) rename {core => coretests}/benches/str/iter.rs (100%) rename {core => coretests}/benches/tuple.rs (100%) create mode 100644 coretests/lib.rs rename {core => coretests}/tests/alloc.rs (100%) rename {core => coretests}/tests/any.rs (100%) rename {core => coretests}/tests/array.rs (100%) rename {core => coretests}/tests/ascii.rs (100%) rename {core => coretests}/tests/ascii_char.rs (100%) rename {core => coretests}/tests/asserting.rs (100%) rename {core => coretests}/tests/async_iter/mod.rs (100%) rename {core => coretests}/tests/atomic.rs (100%) rename {core => coretests}/tests/bool.rs (100%) rename {core => coretests}/tests/bstr.rs (100%) rename {core => coretests}/tests/cell.rs (100%) rename {core => coretests}/tests/char.rs (100%) rename {core => coretests}/tests/clone.rs (100%) rename {core => coretests}/tests/cmp.rs (100%) rename {core => coretests}/tests/const_ptr.rs (100%) rename {core => coretests}/tests/convert.rs (100%) rename {core => coretests}/tests/error.rs (100%) rename {core => coretests}/tests/ffi.rs (100%) rename {core => coretests}/tests/ffi/cstr.rs (100%) rename {core => coretests}/tests/fmt/builders.rs (100%) rename {core => coretests}/tests/fmt/float.rs (100%) rename {core => coretests}/tests/fmt/mod.rs (100%) rename {core => coretests}/tests/fmt/num.rs (100%) rename {core => coretests}/tests/future.rs (100%) rename {core => coretests}/tests/hash/mod.rs (100%) rename {core => coretests}/tests/hash/sip.rs (100%) rename {core => coretests}/tests/intrinsics.rs (100%) rename {core => coretests}/tests/io/borrowed_buf.rs (100%) rename {core => coretests}/tests/io/mod.rs (100%) rename {core => coretests}/tests/iter/adapters/array_chunks.rs (100%) rename {core => coretests}/tests/iter/adapters/by_ref_sized.rs (100%) rename {core => coretests}/tests/iter/adapters/chain.rs (100%) rename {core => coretests}/tests/iter/adapters/cloned.rs (100%) rename {core => coretests}/tests/iter/adapters/copied.rs (100%) rename {core => coretests}/tests/iter/adapters/cycle.rs (100%) rename {core => coretests}/tests/iter/adapters/enumerate.rs (100%) rename {core => coretests}/tests/iter/adapters/filter.rs (100%) rename {core => coretests}/tests/iter/adapters/filter_map.rs (100%) rename {core => coretests}/tests/iter/adapters/flat_map.rs (100%) rename {core => coretests}/tests/iter/adapters/flatten.rs (100%) rename {core => coretests}/tests/iter/adapters/fuse.rs (100%) rename {core => coretests}/tests/iter/adapters/inspect.rs (100%) rename {core => coretests}/tests/iter/adapters/intersperse.rs (100%) rename {core => coretests}/tests/iter/adapters/map.rs (100%) rename {core => coretests}/tests/iter/adapters/map_windows.rs (100%) rename {core => coretests}/tests/iter/adapters/mod.rs (100%) rename {core => coretests}/tests/iter/adapters/peekable.rs (100%) rename {core => coretests}/tests/iter/adapters/scan.rs (100%) rename {core => coretests}/tests/iter/adapters/skip.rs (100%) rename {core => coretests}/tests/iter/adapters/skip_while.rs (100%) rename {core => coretests}/tests/iter/adapters/step_by.rs (100%) rename {core => coretests}/tests/iter/adapters/take.rs (100%) rename {core => coretests}/tests/iter/adapters/take_while.rs (100%) rename {core => coretests}/tests/iter/adapters/zip.rs (100%) rename {core => coretests}/tests/iter/mod.rs (100%) rename {core => coretests}/tests/iter/range.rs (100%) rename {core => coretests}/tests/iter/sources.rs (100%) rename {core => coretests}/tests/iter/traits/accum.rs (100%) rename {core => coretests}/tests/iter/traits/double_ended.rs (100%) rename {core => coretests}/tests/iter/traits/iterator.rs (100%) rename {core => coretests}/tests/iter/traits/mod.rs (100%) rename {core => coretests}/tests/iter/traits/step.rs (100%) rename {core => coretests}/tests/lazy.rs (100%) rename {core => coretests}/tests/lib.rs (100%) rename {core => coretests}/tests/macros.rs (100%) rename {core => coretests}/tests/macros_bootstrap.rs (100%) rename {core => coretests}/tests/manually_drop.rs (100%) rename {core => coretests}/tests/mem.rs (100%) rename {core => coretests}/tests/net/ip_addr.rs (100%) rename {core => coretests}/tests/net/mod.rs (100%) rename {core => coretests}/tests/net/parser.rs (100%) rename {core => coretests}/tests/net/socket_addr.rs (100%) rename {core => coretests}/tests/nonzero.rs (100%) rename {core => coretests}/tests/num/bignum.rs (100%) rename {core => coretests}/tests/num/const_from.rs (100%) rename {core => coretests}/tests/num/dec2flt/float.rs (100%) rename {core => coretests}/tests/num/dec2flt/lemire.rs (100%) rename {core => coretests}/tests/num/dec2flt/mod.rs (100%) rename {core => coretests}/tests/num/dec2flt/parse.rs (100%) rename {core => coretests}/tests/num/float_iter_sum_identity.rs (100%) rename {core => coretests}/tests/num/flt2dec/estimator.rs (100%) rename {core => coretests}/tests/num/flt2dec/mod.rs (100%) rename {core => coretests}/tests/num/flt2dec/random.rs (100%) rename {core => coretests}/tests/num/flt2dec/strategy/dragon.rs (100%) rename {core => coretests}/tests/num/flt2dec/strategy/grisu.rs (100%) rename {core => coretests}/tests/num/i128.rs (100%) rename {core => coretests}/tests/num/i16.rs (100%) rename {core => coretests}/tests/num/i32.rs (100%) rename {core => coretests}/tests/num/i64.rs (100%) rename {core => coretests}/tests/num/i8.rs (100%) rename {core => coretests}/tests/num/ieee754.rs (100%) rename {core => coretests}/tests/num/int_log.rs (100%) rename {core => coretests}/tests/num/int_macros.rs (100%) rename {core => coretests}/tests/num/int_sqrt.rs (100%) rename {core => coretests}/tests/num/midpoint.rs (100%) rename {core => coretests}/tests/num/mod.rs (100%) rename {core => coretests}/tests/num/nan.rs (100%) rename {core => coretests}/tests/num/ops.rs (100%) rename {core => coretests}/tests/num/u128.rs (100%) rename {core => coretests}/tests/num/u16.rs (100%) rename {core => coretests}/tests/num/u32.rs (100%) rename {core => coretests}/tests/num/u64.rs (100%) rename {core => coretests}/tests/num/u8.rs (100%) rename {core => coretests}/tests/num/uint_macros.rs (100%) rename {core => coretests}/tests/num/wrapping.rs (100%) rename {core => coretests}/tests/ops.rs (100%) rename {core => coretests}/tests/ops/control_flow.rs (100%) rename {core => coretests}/tests/ops/from_residual.rs (100%) rename {core => coretests}/tests/option.rs (100%) rename {core => coretests}/tests/panic.rs (100%) rename {core => coretests}/tests/panic/location.rs (100%) rename {core => coretests}/tests/pattern.rs (100%) rename {core => coretests}/tests/pin.rs (100%) rename {core => coretests}/tests/pin_macro.rs (100%) rename {core => coretests}/tests/ptr.rs (100%) rename {core => coretests}/tests/result.rs (100%) rename {core => coretests}/tests/simd.rs (100%) rename {core => coretests}/tests/slice.rs (100%) rename {core => coretests}/tests/str.rs (100%) rename {core => coretests}/tests/str_lossy.rs (100%) rename {core => coretests}/tests/task.rs (100%) rename {core => coretests}/tests/time.rs (100%) rename {core => coretests}/tests/tuple.rs (100%) rename {core => coretests}/tests/unicode.rs (100%) rename {core => coretests}/tests/waker.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 7b9081d46a056..30875482dc06e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,10 @@ dependencies = [ [[package]] name = "core" version = "0.0.0" + +[[package]] +name = "coretests" +version = "0.0.0" dependencies = [ "rand", "rand_xorshift", diff --git a/Cargo.toml b/Cargo.toml index e59aa518804f3..1205f7c9ed6b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "1" members = [ "std", "sysroot", + "coretests", ] exclude = [ diff --git a/core/Cargo.toml b/core/Cargo.toml index 46c55c437cce5..b7c6db6c78dde 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -15,19 +15,6 @@ edition = "2021" test = false bench = false -[[test]] -name = "coretests" -path = "tests/lib.rs" - -[[bench]] -name = "corebenches" -path = "benches/lib.rs" -test = true - -[dev-dependencies] -rand = { version = "0.8.5", default-features = false } -rand_xorshift = { version = "0.3.0", default-features = false } - [features] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = [] diff --git a/coretests/Cargo.toml b/coretests/Cargo.toml new file mode 100644 index 0000000000000..ec940abea1171 --- /dev/null +++ b/coretests/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "coretests" +version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "Tests for the Rust Core Library" +autotests = false +autobenches = false +edition = "2021" + +[lib] +path = "lib.rs" +test = false +bench = false + +[[test]] +name = "coretests" +path = "tests/lib.rs" + +[[bench]] +name = "corebenches" +path = "benches/lib.rs" +test = true + +[dev-dependencies] +rand = { version = "0.8.5", default-features = false } +rand_xorshift = { version = "0.3.0", default-features = false } diff --git a/core/benches/any.rs b/coretests/benches/any.rs similarity index 100% rename from core/benches/any.rs rename to coretests/benches/any.rs diff --git a/core/benches/array.rs b/coretests/benches/array.rs similarity index 100% rename from core/benches/array.rs rename to coretests/benches/array.rs diff --git a/core/benches/ascii.rs b/coretests/benches/ascii.rs similarity index 100% rename from core/benches/ascii.rs rename to coretests/benches/ascii.rs diff --git a/core/benches/ascii/is_ascii.rs b/coretests/benches/ascii/is_ascii.rs similarity index 100% rename from core/benches/ascii/is_ascii.rs rename to coretests/benches/ascii/is_ascii.rs diff --git a/core/benches/char/methods.rs b/coretests/benches/char/methods.rs similarity index 100% rename from core/benches/char/methods.rs rename to coretests/benches/char/methods.rs diff --git a/core/benches/char/mod.rs b/coretests/benches/char/mod.rs similarity index 100% rename from core/benches/char/mod.rs rename to coretests/benches/char/mod.rs diff --git a/core/benches/fmt.rs b/coretests/benches/fmt.rs similarity index 100% rename from core/benches/fmt.rs rename to coretests/benches/fmt.rs diff --git a/core/benches/hash/mod.rs b/coretests/benches/hash/mod.rs similarity index 100% rename from core/benches/hash/mod.rs rename to coretests/benches/hash/mod.rs diff --git a/core/benches/hash/sip.rs b/coretests/benches/hash/sip.rs similarity index 100% rename from core/benches/hash/sip.rs rename to coretests/benches/hash/sip.rs diff --git a/core/benches/iter.rs b/coretests/benches/iter.rs similarity index 100% rename from core/benches/iter.rs rename to coretests/benches/iter.rs diff --git a/core/benches/lib.rs b/coretests/benches/lib.rs similarity index 100% rename from core/benches/lib.rs rename to coretests/benches/lib.rs diff --git a/core/benches/net/addr_parser.rs b/coretests/benches/net/addr_parser.rs similarity index 100% rename from core/benches/net/addr_parser.rs rename to coretests/benches/net/addr_parser.rs diff --git a/core/benches/net/mod.rs b/coretests/benches/net/mod.rs similarity index 100% rename from core/benches/net/mod.rs rename to coretests/benches/net/mod.rs diff --git a/core/benches/num/dec2flt/mod.rs b/coretests/benches/num/dec2flt/mod.rs similarity index 100% rename from core/benches/num/dec2flt/mod.rs rename to coretests/benches/num/dec2flt/mod.rs diff --git a/core/benches/num/flt2dec/mod.rs b/coretests/benches/num/flt2dec/mod.rs similarity index 100% rename from core/benches/num/flt2dec/mod.rs rename to coretests/benches/num/flt2dec/mod.rs diff --git a/core/benches/num/flt2dec/strategy/dragon.rs b/coretests/benches/num/flt2dec/strategy/dragon.rs similarity index 100% rename from core/benches/num/flt2dec/strategy/dragon.rs rename to coretests/benches/num/flt2dec/strategy/dragon.rs diff --git a/core/benches/num/flt2dec/strategy/grisu.rs b/coretests/benches/num/flt2dec/strategy/grisu.rs similarity index 100% rename from core/benches/num/flt2dec/strategy/grisu.rs rename to coretests/benches/num/flt2dec/strategy/grisu.rs diff --git a/core/benches/num/int_log/mod.rs b/coretests/benches/num/int_log/mod.rs similarity index 100% rename from core/benches/num/int_log/mod.rs rename to coretests/benches/num/int_log/mod.rs diff --git a/core/benches/num/int_pow/mod.rs b/coretests/benches/num/int_pow/mod.rs similarity index 100% rename from core/benches/num/int_pow/mod.rs rename to coretests/benches/num/int_pow/mod.rs diff --git a/core/benches/num/int_sqrt/mod.rs b/coretests/benches/num/int_sqrt/mod.rs similarity index 100% rename from core/benches/num/int_sqrt/mod.rs rename to coretests/benches/num/int_sqrt/mod.rs diff --git a/core/benches/num/mod.rs b/coretests/benches/num/mod.rs similarity index 100% rename from core/benches/num/mod.rs rename to coretests/benches/num/mod.rs diff --git a/core/benches/ops.rs b/coretests/benches/ops.rs similarity index 100% rename from core/benches/ops.rs rename to coretests/benches/ops.rs diff --git a/core/benches/pattern.rs b/coretests/benches/pattern.rs similarity index 100% rename from core/benches/pattern.rs rename to coretests/benches/pattern.rs diff --git a/core/benches/slice.rs b/coretests/benches/slice.rs similarity index 100% rename from core/benches/slice.rs rename to coretests/benches/slice.rs diff --git a/core/benches/str.rs b/coretests/benches/str.rs similarity index 100% rename from core/benches/str.rs rename to coretests/benches/str.rs diff --git a/core/benches/str/char_count.rs b/coretests/benches/str/char_count.rs similarity index 100% rename from core/benches/str/char_count.rs rename to coretests/benches/str/char_count.rs diff --git a/core/benches/str/corpora.rs b/coretests/benches/str/corpora.rs similarity index 100% rename from core/benches/str/corpora.rs rename to coretests/benches/str/corpora.rs diff --git a/core/benches/str/debug.rs b/coretests/benches/str/debug.rs similarity index 100% rename from core/benches/str/debug.rs rename to coretests/benches/str/debug.rs diff --git a/core/benches/str/iter.rs b/coretests/benches/str/iter.rs similarity index 100% rename from core/benches/str/iter.rs rename to coretests/benches/str/iter.rs diff --git a/core/benches/tuple.rs b/coretests/benches/tuple.rs similarity index 100% rename from core/benches/tuple.rs rename to coretests/benches/tuple.rs diff --git a/coretests/lib.rs b/coretests/lib.rs new file mode 100644 index 0000000000000..b49208cd4eb3a --- /dev/null +++ b/coretests/lib.rs @@ -0,0 +1 @@ +// Intentionally left empty. diff --git a/core/tests/alloc.rs b/coretests/tests/alloc.rs similarity index 100% rename from core/tests/alloc.rs rename to coretests/tests/alloc.rs diff --git a/core/tests/any.rs b/coretests/tests/any.rs similarity index 100% rename from core/tests/any.rs rename to coretests/tests/any.rs diff --git a/core/tests/array.rs b/coretests/tests/array.rs similarity index 100% rename from core/tests/array.rs rename to coretests/tests/array.rs diff --git a/core/tests/ascii.rs b/coretests/tests/ascii.rs similarity index 100% rename from core/tests/ascii.rs rename to coretests/tests/ascii.rs diff --git a/core/tests/ascii_char.rs b/coretests/tests/ascii_char.rs similarity index 100% rename from core/tests/ascii_char.rs rename to coretests/tests/ascii_char.rs diff --git a/core/tests/asserting.rs b/coretests/tests/asserting.rs similarity index 100% rename from core/tests/asserting.rs rename to coretests/tests/asserting.rs diff --git a/core/tests/async_iter/mod.rs b/coretests/tests/async_iter/mod.rs similarity index 100% rename from core/tests/async_iter/mod.rs rename to coretests/tests/async_iter/mod.rs diff --git a/core/tests/atomic.rs b/coretests/tests/atomic.rs similarity index 100% rename from core/tests/atomic.rs rename to coretests/tests/atomic.rs diff --git a/core/tests/bool.rs b/coretests/tests/bool.rs similarity index 100% rename from core/tests/bool.rs rename to coretests/tests/bool.rs diff --git a/core/tests/bstr.rs b/coretests/tests/bstr.rs similarity index 100% rename from core/tests/bstr.rs rename to coretests/tests/bstr.rs diff --git a/core/tests/cell.rs b/coretests/tests/cell.rs similarity index 100% rename from core/tests/cell.rs rename to coretests/tests/cell.rs diff --git a/core/tests/char.rs b/coretests/tests/char.rs similarity index 100% rename from core/tests/char.rs rename to coretests/tests/char.rs diff --git a/core/tests/clone.rs b/coretests/tests/clone.rs similarity index 100% rename from core/tests/clone.rs rename to coretests/tests/clone.rs diff --git a/core/tests/cmp.rs b/coretests/tests/cmp.rs similarity index 100% rename from core/tests/cmp.rs rename to coretests/tests/cmp.rs diff --git a/core/tests/const_ptr.rs b/coretests/tests/const_ptr.rs similarity index 100% rename from core/tests/const_ptr.rs rename to coretests/tests/const_ptr.rs diff --git a/core/tests/convert.rs b/coretests/tests/convert.rs similarity index 100% rename from core/tests/convert.rs rename to coretests/tests/convert.rs diff --git a/core/tests/error.rs b/coretests/tests/error.rs similarity index 100% rename from core/tests/error.rs rename to coretests/tests/error.rs diff --git a/core/tests/ffi.rs b/coretests/tests/ffi.rs similarity index 100% rename from core/tests/ffi.rs rename to coretests/tests/ffi.rs diff --git a/core/tests/ffi/cstr.rs b/coretests/tests/ffi/cstr.rs similarity index 100% rename from core/tests/ffi/cstr.rs rename to coretests/tests/ffi/cstr.rs diff --git a/core/tests/fmt/builders.rs b/coretests/tests/fmt/builders.rs similarity index 100% rename from core/tests/fmt/builders.rs rename to coretests/tests/fmt/builders.rs diff --git a/core/tests/fmt/float.rs b/coretests/tests/fmt/float.rs similarity index 100% rename from core/tests/fmt/float.rs rename to coretests/tests/fmt/float.rs diff --git a/core/tests/fmt/mod.rs b/coretests/tests/fmt/mod.rs similarity index 100% rename from core/tests/fmt/mod.rs rename to coretests/tests/fmt/mod.rs diff --git a/core/tests/fmt/num.rs b/coretests/tests/fmt/num.rs similarity index 100% rename from core/tests/fmt/num.rs rename to coretests/tests/fmt/num.rs diff --git a/core/tests/future.rs b/coretests/tests/future.rs similarity index 100% rename from core/tests/future.rs rename to coretests/tests/future.rs diff --git a/core/tests/hash/mod.rs b/coretests/tests/hash/mod.rs similarity index 100% rename from core/tests/hash/mod.rs rename to coretests/tests/hash/mod.rs diff --git a/core/tests/hash/sip.rs b/coretests/tests/hash/sip.rs similarity index 100% rename from core/tests/hash/sip.rs rename to coretests/tests/hash/sip.rs diff --git a/core/tests/intrinsics.rs b/coretests/tests/intrinsics.rs similarity index 100% rename from core/tests/intrinsics.rs rename to coretests/tests/intrinsics.rs diff --git a/core/tests/io/borrowed_buf.rs b/coretests/tests/io/borrowed_buf.rs similarity index 100% rename from core/tests/io/borrowed_buf.rs rename to coretests/tests/io/borrowed_buf.rs diff --git a/core/tests/io/mod.rs b/coretests/tests/io/mod.rs similarity index 100% rename from core/tests/io/mod.rs rename to coretests/tests/io/mod.rs diff --git a/core/tests/iter/adapters/array_chunks.rs b/coretests/tests/iter/adapters/array_chunks.rs similarity index 100% rename from core/tests/iter/adapters/array_chunks.rs rename to coretests/tests/iter/adapters/array_chunks.rs diff --git a/core/tests/iter/adapters/by_ref_sized.rs b/coretests/tests/iter/adapters/by_ref_sized.rs similarity index 100% rename from core/tests/iter/adapters/by_ref_sized.rs rename to coretests/tests/iter/adapters/by_ref_sized.rs diff --git a/core/tests/iter/adapters/chain.rs b/coretests/tests/iter/adapters/chain.rs similarity index 100% rename from core/tests/iter/adapters/chain.rs rename to coretests/tests/iter/adapters/chain.rs diff --git a/core/tests/iter/adapters/cloned.rs b/coretests/tests/iter/adapters/cloned.rs similarity index 100% rename from core/tests/iter/adapters/cloned.rs rename to coretests/tests/iter/adapters/cloned.rs diff --git a/core/tests/iter/adapters/copied.rs b/coretests/tests/iter/adapters/copied.rs similarity index 100% rename from core/tests/iter/adapters/copied.rs rename to coretests/tests/iter/adapters/copied.rs diff --git a/core/tests/iter/adapters/cycle.rs b/coretests/tests/iter/adapters/cycle.rs similarity index 100% rename from core/tests/iter/adapters/cycle.rs rename to coretests/tests/iter/adapters/cycle.rs diff --git a/core/tests/iter/adapters/enumerate.rs b/coretests/tests/iter/adapters/enumerate.rs similarity index 100% rename from core/tests/iter/adapters/enumerate.rs rename to coretests/tests/iter/adapters/enumerate.rs diff --git a/core/tests/iter/adapters/filter.rs b/coretests/tests/iter/adapters/filter.rs similarity index 100% rename from core/tests/iter/adapters/filter.rs rename to coretests/tests/iter/adapters/filter.rs diff --git a/core/tests/iter/adapters/filter_map.rs b/coretests/tests/iter/adapters/filter_map.rs similarity index 100% rename from core/tests/iter/adapters/filter_map.rs rename to coretests/tests/iter/adapters/filter_map.rs diff --git a/core/tests/iter/adapters/flat_map.rs b/coretests/tests/iter/adapters/flat_map.rs similarity index 100% rename from core/tests/iter/adapters/flat_map.rs rename to coretests/tests/iter/adapters/flat_map.rs diff --git a/core/tests/iter/adapters/flatten.rs b/coretests/tests/iter/adapters/flatten.rs similarity index 100% rename from core/tests/iter/adapters/flatten.rs rename to coretests/tests/iter/adapters/flatten.rs diff --git a/core/tests/iter/adapters/fuse.rs b/coretests/tests/iter/adapters/fuse.rs similarity index 100% rename from core/tests/iter/adapters/fuse.rs rename to coretests/tests/iter/adapters/fuse.rs diff --git a/core/tests/iter/adapters/inspect.rs b/coretests/tests/iter/adapters/inspect.rs similarity index 100% rename from core/tests/iter/adapters/inspect.rs rename to coretests/tests/iter/adapters/inspect.rs diff --git a/core/tests/iter/adapters/intersperse.rs b/coretests/tests/iter/adapters/intersperse.rs similarity index 100% rename from core/tests/iter/adapters/intersperse.rs rename to coretests/tests/iter/adapters/intersperse.rs diff --git a/core/tests/iter/adapters/map.rs b/coretests/tests/iter/adapters/map.rs similarity index 100% rename from core/tests/iter/adapters/map.rs rename to coretests/tests/iter/adapters/map.rs diff --git a/core/tests/iter/adapters/map_windows.rs b/coretests/tests/iter/adapters/map_windows.rs similarity index 100% rename from core/tests/iter/adapters/map_windows.rs rename to coretests/tests/iter/adapters/map_windows.rs diff --git a/core/tests/iter/adapters/mod.rs b/coretests/tests/iter/adapters/mod.rs similarity index 100% rename from core/tests/iter/adapters/mod.rs rename to coretests/tests/iter/adapters/mod.rs diff --git a/core/tests/iter/adapters/peekable.rs b/coretests/tests/iter/adapters/peekable.rs similarity index 100% rename from core/tests/iter/adapters/peekable.rs rename to coretests/tests/iter/adapters/peekable.rs diff --git a/core/tests/iter/adapters/scan.rs b/coretests/tests/iter/adapters/scan.rs similarity index 100% rename from core/tests/iter/adapters/scan.rs rename to coretests/tests/iter/adapters/scan.rs diff --git a/core/tests/iter/adapters/skip.rs b/coretests/tests/iter/adapters/skip.rs similarity index 100% rename from core/tests/iter/adapters/skip.rs rename to coretests/tests/iter/adapters/skip.rs diff --git a/core/tests/iter/adapters/skip_while.rs b/coretests/tests/iter/adapters/skip_while.rs similarity index 100% rename from core/tests/iter/adapters/skip_while.rs rename to coretests/tests/iter/adapters/skip_while.rs diff --git a/core/tests/iter/adapters/step_by.rs b/coretests/tests/iter/adapters/step_by.rs similarity index 100% rename from core/tests/iter/adapters/step_by.rs rename to coretests/tests/iter/adapters/step_by.rs diff --git a/core/tests/iter/adapters/take.rs b/coretests/tests/iter/adapters/take.rs similarity index 100% rename from core/tests/iter/adapters/take.rs rename to coretests/tests/iter/adapters/take.rs diff --git a/core/tests/iter/adapters/take_while.rs b/coretests/tests/iter/adapters/take_while.rs similarity index 100% rename from core/tests/iter/adapters/take_while.rs rename to coretests/tests/iter/adapters/take_while.rs diff --git a/core/tests/iter/adapters/zip.rs b/coretests/tests/iter/adapters/zip.rs similarity index 100% rename from core/tests/iter/adapters/zip.rs rename to coretests/tests/iter/adapters/zip.rs diff --git a/core/tests/iter/mod.rs b/coretests/tests/iter/mod.rs similarity index 100% rename from core/tests/iter/mod.rs rename to coretests/tests/iter/mod.rs diff --git a/core/tests/iter/range.rs b/coretests/tests/iter/range.rs similarity index 100% rename from core/tests/iter/range.rs rename to coretests/tests/iter/range.rs diff --git a/core/tests/iter/sources.rs b/coretests/tests/iter/sources.rs similarity index 100% rename from core/tests/iter/sources.rs rename to coretests/tests/iter/sources.rs diff --git a/core/tests/iter/traits/accum.rs b/coretests/tests/iter/traits/accum.rs similarity index 100% rename from core/tests/iter/traits/accum.rs rename to coretests/tests/iter/traits/accum.rs diff --git a/core/tests/iter/traits/double_ended.rs b/coretests/tests/iter/traits/double_ended.rs similarity index 100% rename from core/tests/iter/traits/double_ended.rs rename to coretests/tests/iter/traits/double_ended.rs diff --git a/core/tests/iter/traits/iterator.rs b/coretests/tests/iter/traits/iterator.rs similarity index 100% rename from core/tests/iter/traits/iterator.rs rename to coretests/tests/iter/traits/iterator.rs diff --git a/core/tests/iter/traits/mod.rs b/coretests/tests/iter/traits/mod.rs similarity index 100% rename from core/tests/iter/traits/mod.rs rename to coretests/tests/iter/traits/mod.rs diff --git a/core/tests/iter/traits/step.rs b/coretests/tests/iter/traits/step.rs similarity index 100% rename from core/tests/iter/traits/step.rs rename to coretests/tests/iter/traits/step.rs diff --git a/core/tests/lazy.rs b/coretests/tests/lazy.rs similarity index 100% rename from core/tests/lazy.rs rename to coretests/tests/lazy.rs diff --git a/core/tests/lib.rs b/coretests/tests/lib.rs similarity index 100% rename from core/tests/lib.rs rename to coretests/tests/lib.rs diff --git a/core/tests/macros.rs b/coretests/tests/macros.rs similarity index 100% rename from core/tests/macros.rs rename to coretests/tests/macros.rs diff --git a/core/tests/macros_bootstrap.rs b/coretests/tests/macros_bootstrap.rs similarity index 100% rename from core/tests/macros_bootstrap.rs rename to coretests/tests/macros_bootstrap.rs diff --git a/core/tests/manually_drop.rs b/coretests/tests/manually_drop.rs similarity index 100% rename from core/tests/manually_drop.rs rename to coretests/tests/manually_drop.rs diff --git a/core/tests/mem.rs b/coretests/tests/mem.rs similarity index 100% rename from core/tests/mem.rs rename to coretests/tests/mem.rs diff --git a/core/tests/net/ip_addr.rs b/coretests/tests/net/ip_addr.rs similarity index 100% rename from core/tests/net/ip_addr.rs rename to coretests/tests/net/ip_addr.rs diff --git a/core/tests/net/mod.rs b/coretests/tests/net/mod.rs similarity index 100% rename from core/tests/net/mod.rs rename to coretests/tests/net/mod.rs diff --git a/core/tests/net/parser.rs b/coretests/tests/net/parser.rs similarity index 100% rename from core/tests/net/parser.rs rename to coretests/tests/net/parser.rs diff --git a/core/tests/net/socket_addr.rs b/coretests/tests/net/socket_addr.rs similarity index 100% rename from core/tests/net/socket_addr.rs rename to coretests/tests/net/socket_addr.rs diff --git a/core/tests/nonzero.rs b/coretests/tests/nonzero.rs similarity index 100% rename from core/tests/nonzero.rs rename to coretests/tests/nonzero.rs diff --git a/core/tests/num/bignum.rs b/coretests/tests/num/bignum.rs similarity index 100% rename from core/tests/num/bignum.rs rename to coretests/tests/num/bignum.rs diff --git a/core/tests/num/const_from.rs b/coretests/tests/num/const_from.rs similarity index 100% rename from core/tests/num/const_from.rs rename to coretests/tests/num/const_from.rs diff --git a/core/tests/num/dec2flt/float.rs b/coretests/tests/num/dec2flt/float.rs similarity index 100% rename from core/tests/num/dec2flt/float.rs rename to coretests/tests/num/dec2flt/float.rs diff --git a/core/tests/num/dec2flt/lemire.rs b/coretests/tests/num/dec2flt/lemire.rs similarity index 100% rename from core/tests/num/dec2flt/lemire.rs rename to coretests/tests/num/dec2flt/lemire.rs diff --git a/core/tests/num/dec2flt/mod.rs b/coretests/tests/num/dec2flt/mod.rs similarity index 100% rename from core/tests/num/dec2flt/mod.rs rename to coretests/tests/num/dec2flt/mod.rs diff --git a/core/tests/num/dec2flt/parse.rs b/coretests/tests/num/dec2flt/parse.rs similarity index 100% rename from core/tests/num/dec2flt/parse.rs rename to coretests/tests/num/dec2flt/parse.rs diff --git a/core/tests/num/float_iter_sum_identity.rs b/coretests/tests/num/float_iter_sum_identity.rs similarity index 100% rename from core/tests/num/float_iter_sum_identity.rs rename to coretests/tests/num/float_iter_sum_identity.rs diff --git a/core/tests/num/flt2dec/estimator.rs b/coretests/tests/num/flt2dec/estimator.rs similarity index 100% rename from core/tests/num/flt2dec/estimator.rs rename to coretests/tests/num/flt2dec/estimator.rs diff --git a/core/tests/num/flt2dec/mod.rs b/coretests/tests/num/flt2dec/mod.rs similarity index 100% rename from core/tests/num/flt2dec/mod.rs rename to coretests/tests/num/flt2dec/mod.rs diff --git a/core/tests/num/flt2dec/random.rs b/coretests/tests/num/flt2dec/random.rs similarity index 100% rename from core/tests/num/flt2dec/random.rs rename to coretests/tests/num/flt2dec/random.rs diff --git a/core/tests/num/flt2dec/strategy/dragon.rs b/coretests/tests/num/flt2dec/strategy/dragon.rs similarity index 100% rename from core/tests/num/flt2dec/strategy/dragon.rs rename to coretests/tests/num/flt2dec/strategy/dragon.rs diff --git a/core/tests/num/flt2dec/strategy/grisu.rs b/coretests/tests/num/flt2dec/strategy/grisu.rs similarity index 100% rename from core/tests/num/flt2dec/strategy/grisu.rs rename to coretests/tests/num/flt2dec/strategy/grisu.rs diff --git a/core/tests/num/i128.rs b/coretests/tests/num/i128.rs similarity index 100% rename from core/tests/num/i128.rs rename to coretests/tests/num/i128.rs diff --git a/core/tests/num/i16.rs b/coretests/tests/num/i16.rs similarity index 100% rename from core/tests/num/i16.rs rename to coretests/tests/num/i16.rs diff --git a/core/tests/num/i32.rs b/coretests/tests/num/i32.rs similarity index 100% rename from core/tests/num/i32.rs rename to coretests/tests/num/i32.rs diff --git a/core/tests/num/i64.rs b/coretests/tests/num/i64.rs similarity index 100% rename from core/tests/num/i64.rs rename to coretests/tests/num/i64.rs diff --git a/core/tests/num/i8.rs b/coretests/tests/num/i8.rs similarity index 100% rename from core/tests/num/i8.rs rename to coretests/tests/num/i8.rs diff --git a/core/tests/num/ieee754.rs b/coretests/tests/num/ieee754.rs similarity index 100% rename from core/tests/num/ieee754.rs rename to coretests/tests/num/ieee754.rs diff --git a/core/tests/num/int_log.rs b/coretests/tests/num/int_log.rs similarity index 100% rename from core/tests/num/int_log.rs rename to coretests/tests/num/int_log.rs diff --git a/core/tests/num/int_macros.rs b/coretests/tests/num/int_macros.rs similarity index 100% rename from core/tests/num/int_macros.rs rename to coretests/tests/num/int_macros.rs diff --git a/core/tests/num/int_sqrt.rs b/coretests/tests/num/int_sqrt.rs similarity index 100% rename from core/tests/num/int_sqrt.rs rename to coretests/tests/num/int_sqrt.rs diff --git a/core/tests/num/midpoint.rs b/coretests/tests/num/midpoint.rs similarity index 100% rename from core/tests/num/midpoint.rs rename to coretests/tests/num/midpoint.rs diff --git a/core/tests/num/mod.rs b/coretests/tests/num/mod.rs similarity index 100% rename from core/tests/num/mod.rs rename to coretests/tests/num/mod.rs diff --git a/core/tests/num/nan.rs b/coretests/tests/num/nan.rs similarity index 100% rename from core/tests/num/nan.rs rename to coretests/tests/num/nan.rs diff --git a/core/tests/num/ops.rs b/coretests/tests/num/ops.rs similarity index 100% rename from core/tests/num/ops.rs rename to coretests/tests/num/ops.rs diff --git a/core/tests/num/u128.rs b/coretests/tests/num/u128.rs similarity index 100% rename from core/tests/num/u128.rs rename to coretests/tests/num/u128.rs diff --git a/core/tests/num/u16.rs b/coretests/tests/num/u16.rs similarity index 100% rename from core/tests/num/u16.rs rename to coretests/tests/num/u16.rs diff --git a/core/tests/num/u32.rs b/coretests/tests/num/u32.rs similarity index 100% rename from core/tests/num/u32.rs rename to coretests/tests/num/u32.rs diff --git a/core/tests/num/u64.rs b/coretests/tests/num/u64.rs similarity index 100% rename from core/tests/num/u64.rs rename to coretests/tests/num/u64.rs diff --git a/core/tests/num/u8.rs b/coretests/tests/num/u8.rs similarity index 100% rename from core/tests/num/u8.rs rename to coretests/tests/num/u8.rs diff --git a/core/tests/num/uint_macros.rs b/coretests/tests/num/uint_macros.rs similarity index 100% rename from core/tests/num/uint_macros.rs rename to coretests/tests/num/uint_macros.rs diff --git a/core/tests/num/wrapping.rs b/coretests/tests/num/wrapping.rs similarity index 100% rename from core/tests/num/wrapping.rs rename to coretests/tests/num/wrapping.rs diff --git a/core/tests/ops.rs b/coretests/tests/ops.rs similarity index 100% rename from core/tests/ops.rs rename to coretests/tests/ops.rs diff --git a/core/tests/ops/control_flow.rs b/coretests/tests/ops/control_flow.rs similarity index 100% rename from core/tests/ops/control_flow.rs rename to coretests/tests/ops/control_flow.rs diff --git a/core/tests/ops/from_residual.rs b/coretests/tests/ops/from_residual.rs similarity index 100% rename from core/tests/ops/from_residual.rs rename to coretests/tests/ops/from_residual.rs diff --git a/core/tests/option.rs b/coretests/tests/option.rs similarity index 100% rename from core/tests/option.rs rename to coretests/tests/option.rs diff --git a/core/tests/panic.rs b/coretests/tests/panic.rs similarity index 100% rename from core/tests/panic.rs rename to coretests/tests/panic.rs diff --git a/core/tests/panic/location.rs b/coretests/tests/panic/location.rs similarity index 100% rename from core/tests/panic/location.rs rename to coretests/tests/panic/location.rs diff --git a/core/tests/pattern.rs b/coretests/tests/pattern.rs similarity index 100% rename from core/tests/pattern.rs rename to coretests/tests/pattern.rs diff --git a/core/tests/pin.rs b/coretests/tests/pin.rs similarity index 100% rename from core/tests/pin.rs rename to coretests/tests/pin.rs diff --git a/core/tests/pin_macro.rs b/coretests/tests/pin_macro.rs similarity index 100% rename from core/tests/pin_macro.rs rename to coretests/tests/pin_macro.rs diff --git a/core/tests/ptr.rs b/coretests/tests/ptr.rs similarity index 100% rename from core/tests/ptr.rs rename to coretests/tests/ptr.rs diff --git a/core/tests/result.rs b/coretests/tests/result.rs similarity index 100% rename from core/tests/result.rs rename to coretests/tests/result.rs diff --git a/core/tests/simd.rs b/coretests/tests/simd.rs similarity index 100% rename from core/tests/simd.rs rename to coretests/tests/simd.rs diff --git a/core/tests/slice.rs b/coretests/tests/slice.rs similarity index 100% rename from core/tests/slice.rs rename to coretests/tests/slice.rs diff --git a/core/tests/str.rs b/coretests/tests/str.rs similarity index 100% rename from core/tests/str.rs rename to coretests/tests/str.rs diff --git a/core/tests/str_lossy.rs b/coretests/tests/str_lossy.rs similarity index 100% rename from core/tests/str_lossy.rs rename to coretests/tests/str_lossy.rs diff --git a/core/tests/task.rs b/coretests/tests/task.rs similarity index 100% rename from core/tests/task.rs rename to coretests/tests/task.rs diff --git a/core/tests/time.rs b/coretests/tests/time.rs similarity index 100% rename from core/tests/time.rs rename to coretests/tests/time.rs diff --git a/core/tests/tuple.rs b/coretests/tests/tuple.rs similarity index 100% rename from core/tests/tuple.rs rename to coretests/tests/tuple.rs diff --git a/core/tests/unicode.rs b/coretests/tests/unicode.rs similarity index 100% rename from core/tests/unicode.rs rename to coretests/tests/unicode.rs diff --git a/core/tests/waker.rs b/coretests/tests/waker.rs similarity index 100% rename from core/tests/waker.rs rename to coretests/tests/waker.rs From a9f86b4b3438b3d22470c16d7c8d26673cac5c4c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:12:22 +0000 Subject: [PATCH 370/481] Update comment --- core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 01ed3cc69a2cc..c18e0405f7293 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -44,7 +44,7 @@ //! called. The `lang` attribute is called `eh_personality`. // Since core defines many fundamental lang items, all tests live in a -// separate crate, libcoretest (library/core/tests), to avoid bizarre issues. +// separate crate, coretests (library/coretests), to avoid bizarre issues. // // Here we explicitly #[cfg]-out this whole crate when testing. If we don't do // this, both the generated test artifact and the linked libtest (which From a2a0b8f4391910890e760ce453224dfedac1b1af Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 26 Jan 2025 10:24:32 +0000 Subject: [PATCH 371/481] Actually run the bstr test It previously didn't get run because of a missing mod bstr. --- coretests/tests/bstr.rs | 4 +--- coretests/tests/lib.rs | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coretests/tests/bstr.rs b/coretests/tests/bstr.rs index 5fecd0a4084c7..cd4d69d6b337d 100644 --- a/coretests/tests/bstr.rs +++ b/coretests/tests/bstr.rs @@ -1,6 +1,4 @@ -#![feature(bstr)] - -use core::ByteStr; +use core::bstr::ByteStr; #[test] fn test_debug() { diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index a8980c5f30aec..0607d508a48e5 100644 --- a/coretests/tests/lib.rs +++ b/coretests/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(async_iter_from_iter)] #![feature(async_iterator)] #![feature(bigint_helper_methods)] +#![feature(bstr)] #![feature(cell_update)] #![feature(clone_to_uninit)] #![feature(const_black_box)] @@ -139,6 +140,7 @@ mod asserting; mod async_iter; mod atomic; mod bool; +mod bstr; mod cell; mod char; mod clone; From 7770689c64efa07378873e0598235d666d218057 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 17 Jan 2025 16:55:10 +0100 Subject: [PATCH 372/481] Move `std::io::pipe` code into its own file --- std/src/io/mod.rs | 258 +-------------------------------------- std/src/io/pipe.rs | 256 ++++++++++++++++++++++++++++++++++++++ std/src/io/pipe/tests.rs | 18 +++ std/src/io/tests.rs | 17 --- 4 files changed, 277 insertions(+), 272 deletions(-) create mode 100644 std/src/io/pipe.rs create mode 100644 std/src/io/pipe/tests.rs diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 1fa13e95e6872..cfd03b8e3d6d0 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -310,6 +310,8 @@ pub use self::error::RawOsError; pub use self::error::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use self::error::const_error; +#[unstable(feature = "anonymous_pipe", issue = "127154")] +pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; pub(crate) use self::stdio::attempt_print_to_stderr; @@ -330,7 +332,6 @@ pub use self::{ }; use crate::mem::take; use crate::ops::{Deref, DerefMut}; -use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::{cmp, fmt, slice, str, sys}; mod buffered; @@ -338,6 +339,7 @@ pub(crate) mod copy; mod cursor; mod error; mod impls; +mod pipe; pub mod prelude; mod stdio; mod util; @@ -3251,257 +3253,3 @@ impl Iterator for Lines { } } } - -/// Create an anonymous pipe that is close-on-exec and blocking. -/// -/// # Behavior -/// -/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is -/// typically used to communicate between two or more separate processes, as there are better, -/// faster ways to communicate within a single process. -/// -/// In particular: -/// -/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. -/// * A write on a [`PipeWriter`] blocks when the pipe is full. -/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] -/// returns EOF. -/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but -/// writes (above a target-specific threshold) may have their data interleaved. -/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any -/// given byte will only get consumed by one reader. There are no guarantees about data -/// interleaving. -/// * Portable applications cannot assume any atomicity of messages larger than a single byte. -/// -/// # Capacity -/// -/// Pipe capacity is platform dependent. To quote the Linux [man page]: -/// -/// > Different implementations have different limits for the pipe capacity. Applications should -/// > not rely on a particular capacity: an application should be designed so that a reading process -/// > consumes data as soon as it is available, so that a writing process does not remain blocked. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(anonymous_pipe)] -/// # #[cfg(miri)] fn main() {} -/// # #[cfg(not(miri))] -/// # fn main() -> std::io::Result<()> { -/// # use std::process::Command; -/// # use std::io::{Read, Write}; -/// let (ping_rx, mut ping_tx) = std::io::pipe()?; -/// let (mut pong_rx, pong_tx) = std::io::pipe()?; -/// -/// // Spawn a process that echoes its input. -/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; -/// -/// ping_tx.write_all(b"hello")?; -/// // Close to unblock echo_server's reader. -/// drop(ping_tx); -/// -/// let mut buf = String::new(); -/// // Block until echo_server's writer is closed. -/// pong_rx.read_to_string(&mut buf)?; -/// assert_eq!(&buf, "hello"); -/// -/// echo_server.wait()?; -/// # Ok(()) -/// # } -/// ``` -/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[inline] -pub fn pipe() -> Result<(PipeReader, PipeWriter)> { - pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) -} - -/// Read end of an anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeReader(pub(crate) AnonPipe); - -/// Write end of an anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeWriter(pub(crate) AnonPipe); - -impl PipeReader { - /// Create a new [`PipeReader`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::fs; - /// # use std::io::Write; - /// # use std::process::Command; - /// const NUM_SLOT: u8 = 2; - /// const NUM_PROC: u8 = 5; - /// const OUTPUT: &str = "work.txt"; - /// - /// let mut jobs = vec![]; - /// let (reader, mut writer) = std::io::pipe()?; - /// - /// // Write NUM_SLOT characters the pipe. - /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; - /// - /// // Spawn several processes that read a character from the pipe, do some work, then - /// // write back to the pipe. When the pipe is empty, the processes block, so only - /// // NUM_SLOT processes can be working at any given time. - /// for _ in 0..NUM_PROC { - /// jobs.push( - /// Command::new("bash") - /// .args(["-c", - /// &format!( - /// "read -n 1\n\ - /// echo -n 'x' >> '{OUTPUT}'\n\ - /// echo -n '|'", - /// ), - /// ]) - /// .stdin(reader.try_clone()?) - /// .stdout(writer.try_clone()?) - /// .spawn()?, - /// ); - /// } - /// - /// // Wait for all jobs to finish. - /// for mut job in jobs { - /// job.wait()?; - /// } - /// - /// // Check our work and clean up. - /// let xs = fs::read_to_string(OUTPUT)?; - /// fs::remove_file(OUTPUT)?; - /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> Result { - self.0.try_clone().map(Self) - } -} - -impl PipeWriter { - /// Create a new [`PipeWriter`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::process::Command; - /// # use std::io::Read; - /// let (mut reader, writer) = std::io::pipe()?; - /// - /// // Spawn a process that writes to stdout and stderr. - /// let mut peer = Command::new("bash") - /// .args([ - /// "-c", - /// "echo -n foo\n\ - /// echo -n bar >&2" - /// ]) - /// .stdout(writer.try_clone()?) - /// .stderr(writer) - /// .spawn()?; - /// - /// // Read and check the result. - /// let mut msg = String::new(); - /// reader.read_to_string(&mut msg)?; - /// assert_eq!(&msg, "foobar"); - /// - /// peer.wait()?; - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> Result { - self.0.try_clone().map(Self) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Read for &PipeReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Read for PipeReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Write for &PipeWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Write for PipeWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} diff --git a/std/src/io/pipe.rs b/std/src/io/pipe.rs new file mode 100644 index 0000000000000..cd33294b2710d --- /dev/null +++ b/std/src/io/pipe.rs @@ -0,0 +1,256 @@ +use crate::io; +use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; + +/// Create an anonymous pipe that is close-on-exec and blocking. +/// +/// # Behavior +/// +/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is +/// typically used to communicate between two or more separate processes, as there are better, +/// faster ways to communicate within a single process. +/// +/// In particular: +/// +/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. +/// * A write on a [`PipeWriter`] blocks when the pipe is full. +/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] +/// returns EOF. +/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but +/// writes (above a target-specific threshold) may have their data interleaved. +/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any +/// given byte will only get consumed by one reader. There are no guarantees about data +/// interleaving. +/// * Portable applications cannot assume any atomicity of messages larger than a single byte. +/// +/// # Capacity +/// +/// Pipe capacity is platform dependent. To quote the Linux [man page]: +/// +/// > Different implementations have different limits for the pipe capacity. Applications should +/// > not rely on a particular capacity: an application should be designed so that a reading process +/// > consumes data as soon as it is available, so that a writing process does not remain blocked. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(anonymous_pipe)] +/// # #[cfg(miri)] fn main() {} +/// # #[cfg(not(miri))] +/// # fn main() -> std::io::Result<()> { +/// # use std::process::Command; +/// # use std::io::{Read, Write}; +/// let (ping_rx, mut ping_tx) = std::io::pipe()?; +/// let (mut pong_rx, pong_tx) = std::io::pipe()?; +/// +/// // Spawn a process that echoes its input. +/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; +/// +/// ping_tx.write_all(b"hello")?; +/// // Close to unblock echo_server's reader. +/// drop(ping_tx); +/// +/// let mut buf = String::new(); +/// // Block until echo_server's writer is closed. +/// pong_rx.read_to_string(&mut buf)?; +/// assert_eq!(&buf, "hello"); +/// +/// echo_server.wait()?; +/// # Ok(()) +/// # } +/// ``` +/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[inline] +pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { + pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) +} + +/// Read end of an anonymous pipe. +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[derive(Debug)] +pub struct PipeReader(pub(crate) AnonPipe); + +/// Write end of an anonymous pipe. +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[derive(Debug)] +pub struct PipeWriter(pub(crate) AnonPipe); + +impl PipeReader { + /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::fs; + /// # use std::io::Write; + /// # use std::process::Command; + /// const NUM_SLOT: u8 = 2; + /// const NUM_PROC: u8 = 5; + /// const OUTPUT: &str = "work.txt"; + /// + /// let mut jobs = vec![]; + /// let (reader, mut writer) = std::io::pipe()?; + /// + /// // Write NUM_SLOT characters the pipe. + /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; + /// + /// // Spawn several processes that read a character from the pipe, do some work, then + /// // write back to the pipe. When the pipe is empty, the processes block, so only + /// // NUM_SLOT processes can be working at any given time. + /// for _ in 0..NUM_PROC { + /// jobs.push( + /// Command::new("bash") + /// .args(["-c", + /// &format!( + /// "read -n 1\n\ + /// echo -n 'x' >> '{OUTPUT}'\n\ + /// echo -n '|'", + /// ), + /// ]) + /// .stdin(reader.try_clone()?) + /// .stdout(writer.try_clone()?) + /// .spawn()?, + /// ); + /// } + /// + /// // Wait for all jobs to finish. + /// for mut job in jobs { + /// job.wait()?; + /// } + /// + /// // Check our work and clean up. + /// let xs = fs::read_to_string(OUTPUT)?; + /// fs::remove_file(OUTPUT)?; + /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "anonymous_pipe", issue = "127154")] + pub fn try_clone(&self) -> io::Result { + self.0.try_clone().map(Self) + } +} + +impl PipeWriter { + /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::process::Command; + /// # use std::io::Read; + /// let (mut reader, writer) = std::io::pipe()?; + /// + /// // Spawn a process that writes to stdout and stderr. + /// let mut peer = Command::new("bash") + /// .args([ + /// "-c", + /// "echo -n foo\n\ + /// echo -n bar >&2" + /// ]) + /// .stdout(writer.try_clone()?) + /// .stderr(writer) + /// .spawn()?; + /// + /// // Read and check the result. + /// let mut msg = String::new(); + /// reader.read_to_string(&mut msg)?; + /// assert_eq!(&msg, "foobar"); + /// + /// peer.wait()?; + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "anonymous_pipe", issue = "127154")] + pub fn try_clone(&self) -> io::Result { + self.0.try_clone().map(Self) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Read for &PipeReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Read for PipeReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Write for &PipeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Write for PipeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } +} diff --git a/std/src/io/pipe/tests.rs b/std/src/io/pipe/tests.rs new file mode 100644 index 0000000000000..c1f3f192ca2d7 --- /dev/null +++ b/std/src/io/pipe/tests.rs @@ -0,0 +1,18 @@ +use crate::io::{Read, Write, pipe}; + +#[test] +#[cfg(all(windows, unix, not(miri)))] +fn pipe_creation_clone_and_rw() { + let (rx, tx) = pipe().unwrap(); + + tx.try_clone().unwrap().write_all(b"12345").unwrap(); + drop(tx); + + let mut rx2 = rx.try_clone().unwrap(); + drop(rx); + + let mut s = String::new(); + rx2.read_to_string(&mut s).unwrap(); + drop(rx2); + assert_eq!(s, "12345"); +} diff --git a/std/src/io/tests.rs b/std/src/io/tests.rs index 226cc6011bcab..f64f034cce779 100644 --- a/std/src/io/tests.rs +++ b/std/src/io/tests.rs @@ -821,20 +821,3 @@ fn try_oom_error() { let io_err = io::Error::from(reserve_err); assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind()); } - -#[test] -#[cfg(all(windows, unix, not(miri)))] -fn pipe_creation_clone_and_rw() { - let (rx, tx) = std::io::pipe().unwrap(); - - tx.try_clone().unwrap().write_all(b"12345").unwrap(); - drop(tx); - - let mut rx2 = rx.try_clone().unwrap(); - drop(rx); - - let mut s = String::new(); - rx2.read_to_string(&mut s).unwrap(); - drop(rx2); - assert_eq!(s, "12345"); -} From 846217a4b47ba0ea682219f88770c7e8a4b66450 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 17 Jan 2025 17:11:08 +0100 Subject: [PATCH 373/481] Update `std::io::{pipe, PipeReader, PipeWriter}` docs the new location Also create a section "Platform-specific behavior", don't hide required imports for code examples. --- std/src/io/pipe.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/std/src/io/pipe.rs b/std/src/io/pipe.rs index cd33294b2710d..266c7bc96389b 100644 --- a/std/src/io/pipe.rs +++ b/std/src/io/pipe.rs @@ -1,7 +1,7 @@ use crate::io; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; -/// Create an anonymous pipe that is close-on-exec and blocking. +/// Create an anonymous pipe. /// /// # Behavior /// @@ -22,6 +22,13 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// interleaving. /// * Portable applications cannot assume any atomicity of messages larger than a single byte. /// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `pipe` function on Unix and the +/// `CreatePipe` function on Windows. +/// +/// Note that this [may change in the future][changes]. +/// /// # Capacity /// /// Pipe capacity is platform dependent. To quote the Linux [man page]: @@ -37,10 +44,10 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { -/// # use std::process::Command; -/// # use std::io::{Read, Write}; -/// let (ping_rx, mut ping_tx) = std::io::pipe()?; -/// let (mut pong_rx, pong_tx) = std::io::pipe()?; +/// use std::process::Command; +/// use std::io::{pipe, Read, Write}; +/// let (ping_rx, mut ping_tx) = pipe()?; +/// let (mut pong_rx, pong_tx) = pipe()?; /// /// // Spawn a process that echoes its input. /// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; @@ -58,6 +65,7 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// # Ok(()) /// # } /// ``` +/// [changes]: io#platform-specific-behavior /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html #[unstable(feature = "anonymous_pipe", issue = "127154")] #[inline] @@ -85,15 +93,15 @@ impl PipeReader { /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { - /// # use std::fs; - /// # use std::io::Write; - /// # use std::process::Command; + /// use std::fs; + /// use std::io::{pipe, Write}; + /// use std::process::Command; /// const NUM_SLOT: u8 = 2; /// const NUM_PROC: u8 = 5; /// const OUTPUT: &str = "work.txt"; /// /// let mut jobs = vec![]; - /// let (reader, mut writer) = std::io::pipe()?; + /// let (reader, mut writer) = pipe()?; /// /// // Write NUM_SLOT characters the pipe. /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; @@ -145,9 +153,9 @@ impl PipeWriter { /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { - /// # use std::process::Command; - /// # use std::io::Read; - /// let (mut reader, writer) = std::io::pipe()?; + /// use std::process::Command; + /// use std::io::{pipe, Read}; + /// let (mut reader, writer) = pipe()?; /// /// // Spawn a process that writes to stdout and stderr. /// let mut peer = Command::new("bash") @@ -224,11 +232,9 @@ impl io::Write for &PipeWriter { fn flush(&mut self) -> io::Result<()> { Ok(()) } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } - #[inline] fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() @@ -244,11 +250,9 @@ impl io::Write for PipeWriter { fn flush(&mut self) -> io::Result<()> { Ok(()) } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } - #[inline] fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() From d282a0dae909c75d865af1aae3cff0eefef5cbef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jan 2025 19:09:50 -0700 Subject: [PATCH 374/481] compiler_fence: fix example --- core/src/sync/atomic.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index fda26a672990a..859ac1632305b 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -3727,33 +3727,33 @@ pub fn fence(order: Ordering) { /// /// # Examples /// -/// Without `compiler_fence`, the `assert_eq!` in following code -/// is *not* guaranteed to succeed, despite everything happening in a single thread. -/// To see why, remember that the compiler is free to swap the stores to -/// `IMPORTANT_VARIABLE` and `IS_READY` since they are both -/// `Ordering::Relaxed`. If it does, and the signal handler is invoked right -/// after `IS_READY` is updated, then the signal handler will see -/// `IS_READY=1`, but `IMPORTANT_VARIABLE=0`. -/// Using a `compiler_fence` remedies this situation. +/// Without the two `compiler_fence` calls, the read of `IMPORTANT_VARIABLE` in `signal_handler` +/// is *undefined behavior* due to a data race, despite everything happening in a single thread. +/// This is because the signal handler is considered to run concurrently with its associated +/// thread, and explicit synchronization is required to pass data between a thread and its +/// signal handler. The code below uses two `compiler_fence` calls to establish the usual +/// release-acquire synchronization pattern (see [`fence`] for an image). /// /// ``` -/// use std::sync::atomic::{AtomicBool, AtomicUsize}; +/// use std::sync::atomic::AtomicBool; /// use std::sync::atomic::Ordering; /// use std::sync::atomic::compiler_fence; /// -/// static IMPORTANT_VARIABLE: AtomicUsize = AtomicUsize::new(0); +/// static mut IMPORTANT_VARIABLE: usize = 0; /// static IS_READY: AtomicBool = AtomicBool::new(false); /// /// fn main() { -/// IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); -/// // prevent earlier writes from being moved beyond this point +/// unsafe { IMPORTANT_VARIABLE = 42 }; +/// // Marks earlier writes as being released with future relaxed stores. /// compiler_fence(Ordering::Release); /// IS_READY.store(true, Ordering::Relaxed); /// } /// /// fn signal_handler() { /// if IS_READY.load(Ordering::Relaxed) { -/// assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); +/// // Acquires writes that were released with relaxed stores that we read from. +/// compiler_fence(Ordering::Acquire); +/// assert_eq!(unsafe { IMPORTANT_VARIABLE }, 42); /// } /// } /// ``` From c53cc9d3d04d490adb61b4e0d360a65b34edc923 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 20 Jan 2025 15:37:52 +0100 Subject: [PATCH 375/481] Clarify WindowsMut (Lending)Iterator fixes 133628 --- core/src/slice/mod.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index ba5746d0adea1..1993a7491e108 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -1099,10 +1099,15 @@ impl [T] { /// assert!(iter.next().is_none()); /// ``` /// - /// There's no `windows_mut`, as that existing would let safe code violate the - /// "only one `&mut` at a time to the same thing" rule. However, you can sometimes - /// use [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in - /// conjunction with `windows` to accomplish something similar: + /// Because the [Iterator] trait cannot represent the required lifetimes, + /// there is no `windows_mut` analog to `windows`; + /// `[0,1,2].windows_mut(2).collect()` would violate [the rules of references] + /// (though a [LendingIterator] analog is possible). You can sometimes use + /// [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in + /// conjunction with `windows` instead: + /// + /// [the rules of references]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references + /// [LendingIterator]: https://blog.rust-lang.org/2022/10/28/gats-stabilization.html /// ``` /// use std::cell::Cell; /// From 5e7ee87ad3e31aa0355f89dd18ab63dd0a327de2 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 21 Jan 2025 08:45:03 +0000 Subject: [PATCH 376/481] Implement phantom variance markers --- core/src/marker.rs | 7 + core/src/marker/variance.rs | 260 ++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 core/src/marker/variance.rs diff --git a/core/src/marker.rs b/core/src/marker.rs index 01af964a83e26..a793fc2aa2e55 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -6,6 +6,13 @@ #![stable(feature = "rust1", since = "1.0.0")] +mod variance; + +#[unstable(feature = "phantom_variance_markers", issue = "135806")] +pub use self::variance::{ + PhantomContravariant, PhantomContravariantLifetime, PhantomCovariant, PhantomCovariantLifetime, + PhantomInvariant, PhantomInvariantLifetime, Variance, variance, +}; use crate::cell::UnsafeCell; use crate::cmp; use crate::fmt::Debug; diff --git a/core/src/marker/variance.rs b/core/src/marker/variance.rs new file mode 100644 index 0000000000000..23334e6575ddf --- /dev/null +++ b/core/src/marker/variance.rs @@ -0,0 +1,260 @@ +#![unstable(feature = "phantom_variance_markers", issue = "135806")] + +use super::PhantomData; +use crate::any::type_name; +use crate::cmp::Ordering; +use crate::fmt; +use crate::hash::{Hash, Hasher}; + +macro_rules! first_token { + ($first:tt $($rest:tt)*) => { + $first + }; +} + +macro_rules! phantom_type { + ($( + $(#[$attr:meta])* + pub struct $name:ident <$t:ident> ($($inner:tt)*); + )*) => {$( + $(#[$attr])* + pub struct $name<$t>($($inner)*) where T: ?Sized; + + impl $name + where T: ?Sized + { + /// Constructs a new instance of the variance marker. + pub const fn new() -> Self { + Self(PhantomData) + } + } + + impl self::sealed::Sealed for $name where T: ?Sized { + const VALUE: Self = Self::new(); + } + impl Variance for $name where T: ?Sized {} + + impl Default for $name + where T: ?Sized + { + fn default() -> Self { + Self(PhantomData) + } + } + + impl fmt::Debug for $name + where T: ?Sized + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}<{}>", stringify!($name), type_name::()) + } + } + + impl Clone for $name + where T: ?Sized + { + fn clone(&self) -> Self { + *self + } + } + + impl Copy for $name where T: ?Sized {} + + impl PartialEq for $name + where T: ?Sized + { + fn eq(&self, _: &Self) -> bool { + true + } + } + + impl Eq for $name where T: ?Sized {} + + impl PartialOrd for $name + where T: ?Sized + { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } + } + + impl Ord for $name + where T: ?Sized + { + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal + } + } + + impl Hash for $name + where T: ?Sized + { + fn hash(&self, _: &mut H) {} + } + )*}; +} + +macro_rules! phantom_lifetime { + ($( + $(#[$attr:meta])* + pub struct $name:ident <$lt:lifetime> ($($inner:tt)*); + )*) => {$( + $(#[$attr])* + #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $name<$lt>($($inner)*); + + impl $name<'_> { + /// Constructs a new instance of the variance marker. + pub const fn new() -> Self { + Self(first_token!($($inner)*)(PhantomData)) + } + } + + impl self::sealed::Sealed for $name<'_> { + const VALUE: Self = Self::new(); + } + impl Variance for $name<'_> {} + + impl fmt::Debug for $name<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", stringify!($name)) + } + } + )*}; +} + +phantom_lifetime! { + /// Zero-sized type used to mark a lifetime as covariant. + /// + /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more + /// information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `'a`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>); + /// Zero-sized type used to mark a lifetime as contravariant. + /// + /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for + /// more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `'a`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>); + /// Zero-sized type used to mark a lifetime as invariant. + /// + /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer. + /// See [the reference][1] for more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `'a`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); +} + +phantom_type! { + /// Zero-sized type used to mark a type parameter as covariant. + /// + /// Types used as part of the return value from a function are covariant. If the type is _also_ + /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for + /// more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `T`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + pub struct PhantomCovariant(PhantomData T>); + /// Zero-sized type used to mark a type parameter as contravariant. + /// + /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the + /// return value from a function then it is [invariant][PhantomInvariant]. See [the + /// reference][1] for more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `T`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + pub struct PhantomContravariant(PhantomData); + /// Zero-sized type used to mark a type parameter as invariant. + /// + /// Types that are both passed as an argument _and_ used as part of the return value from a + /// function are invariant. See [the reference][1] for more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `T`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + pub struct PhantomInvariant(PhantomData T>); +} + +mod sealed { + pub trait Sealed { + const VALUE: Self; + } +} + +/// A marker trait for phantom variance types. +pub trait Variance: sealed::Sealed + Default {} + +/// Construct a variance marker; equivalent to [`Default::default`]. +/// +/// This type can be any of the following. You generally should not need to explicitly name the +/// type, however. +/// +/// - [`PhantomCovariant`] +/// - [`PhantomContravariant`] +/// - [`PhantomInvariant`] +/// - [`PhantomCovariantLifetime`] +/// - [`PhantomContravariantLifetime`] +/// - [`PhantomInvariantLifetime`] +/// +/// # Example +/// +/// ```rust +/// #![feature(phantom_variance_markers)] +/// +/// use core::marker::{PhantomCovariant, variance}; +/// +/// struct BoundFn +/// where +/// F: Fn(P) -> R, +/// { +/// function: F, +/// parameter: P, +/// return_value: PhantomCovariant, +/// } +/// +/// let bound_fn = BoundFn { +/// function: core::convert::identity, +/// parameter: 5u8, +/// return_value: variance(), +/// }; +/// ``` +pub const fn variance() -> T +where + T: Variance, +{ + T::VALUE +} From 1c9ac12d2ec67cd38b4b7fa7753c55281e0b3c6a Mon Sep 17 00:00:00 2001 From: usamoi Date: Wed, 22 Jan 2025 20:11:24 +0800 Subject: [PATCH 377/481] fix doc for std::sync::mpmc --- std/src/sync/mpmc/mod.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/std/src/sync/mpmc/mod.rs b/std/src/sync/mpmc/mod.rs index 0cf4902d6d59b..00966ee3ecffd 100644 --- a/std/src/sync/mpmc/mod.rs +++ b/std/src/sync/mpmc/mod.rs @@ -18,7 +18,7 @@ //! infinite buffer. //! //! 2. A synchronous, bounded channel. The [`sync_channel`] function will -//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! return a `(Sender, Receiver)` tuple where the storage for pending //! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note //! that a bound of 0 is allowed, causing the channel to become a "rendezvous" @@ -360,9 +360,17 @@ impl Sender { /// that a return value of [`Err`] means that the data will never be /// received, but a return value of [`Ok`] does *not* mean that the data /// will be received. It is possible for the corresponding receiver to - /// hang up immediately after this function returns [`Ok`]. + /// hang up immediately after this function returns [`Ok`]. However, if + /// the channel is zero-capacity, it acts as a rendezvous channel and a + /// return value of [`Ok`] means that the data has been received. /// - /// This method will never block the current thread. + /// If the channel is full and not disconnected, this call will block until + /// the send operation can proceed. If the channel becomes disconnected, + /// this call will wake up and return an error. The returned error contains + /// the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive + /// operation to appear on the other side of the channel. /// /// # Examples /// @@ -650,7 +658,7 @@ impl fmt::Debug for Sender { } /// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type. -/// Different threads can share this [`Sender`] by cloning it. +/// Different threads can share this [`Receiver`] by cloning it. /// /// Messages sent to the channel can be retrieved using [`recv`]. /// From bb0a9a3ae44d532ebc9c044abb8a028ee02933bd Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 4 Dec 2024 01:42:35 +0300 Subject: [PATCH 378/481] Implement `AtomicT::update` & `AtomicT::try_update` --- core/src/sync/atomic.rs | 377 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 374 insertions(+), 3 deletions(-) diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 859ac1632305b..9b56abbd330d1 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -1164,7 +1164,7 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. + /// This method is not magic; it is not provided by the hardware. /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. /// In particular, this method will not circumvent the [ABA Problem]. /// @@ -1203,6 +1203,125 @@ impl AtomicBool { } Err(prev) } + + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function + /// returned `Some(_)`, else `Err(previous_value)`. + /// + /// See also: [`update`](`AtomicBool::update`). + /// + /// Note: This may call the function multiple times if the value has been + /// changed from other threads in the meantime, as long as the function + /// returns `Some(_)`, but the function will have been applied only once to + /// the stored value. + /// + /// `try_update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicBool::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part of this + /// operation [`Relaxed`], and using [`Release`] makes the final successful + /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], + /// [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on `u8`. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let x = AtomicBool::new(false); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(false)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(false)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(true)); + /// assert_eq!(x.load(Ordering::SeqCst), false); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn try_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + f: impl FnMut(bool) -> Option, + ) -> Result { + // FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`; + // when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`. + self.fetch_update(set_order, fetch_order, f) + } + + /// Fetches the value, applies a function to it that it return a new value. + /// The new value is stored and the old value is returned. + /// + /// See also: [`try_update`](`AtomicBool::try_update`). + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, but the function will have been applied only once to the stored value. + /// + /// `update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicBool::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic operations on `u8`. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let x = AtomicBool::new(false); + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| !x), false); + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| !x), true); + /// assert_eq!(x.load(Ordering::SeqCst), false); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: impl FnMut(bool) -> bool, + ) -> bool { + let mut prev = self.load(fetch_order); + loop { + match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) { + Ok(x) => break x, + Err(next_prev) => prev = next_prev, + } + } + } } #[cfg(target_has_atomic_load_store = "ptr")] @@ -1684,7 +1803,7 @@ impl AtomicPtr { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. + /// This method is not magic; it is not provided by the hardware. /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. /// In particular, this method will not circumvent the [ABA Problem]. /// @@ -1732,6 +1851,137 @@ impl AtomicPtr { } Err(prev) } + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function + /// returned `Some(_)`, else `Err(previous_value)`. + /// + /// See also: [`update`](`AtomicPtr::update`). + /// + /// Note: This may call the function multiple times if the value has been + /// changed from other threads in the meantime, as long as the function + /// returns `Some(_)`, but the function will have been applied only once to + /// the stored value. + /// + /// `try_update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicPtr::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part of this + /// operation [`Relaxed`], and using [`Release`] makes the final successful + /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], + /// [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on pointers. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr: *mut _ = &mut 5; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let new: *mut _ = &mut 10; + /// assert_eq!(some_ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr)); + /// let result = some_ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| { + /// if x == ptr { + /// Some(new) + /// } else { + /// None + /// } + /// }); + /// assert_eq!(result, Ok(ptr)); + /// assert_eq!(some_ptr.load(Ordering::SeqCst), new); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn try_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + f: impl FnMut(*mut T) -> Option<*mut T>, + ) -> Result<*mut T, *mut T> { + // FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`; + // when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`. + self.fetch_update(set_order, fetch_order, f) + } + + /// Fetches the value, applies a function to it that it return a new value. + /// The new value is stored and the old value is returned. + /// + /// See also: [`try_update`](`AtomicPtr::try_update`). + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, but the function will have been applied only once to the stored value. + /// + /// `update` takes two [`Ordering`] arguments to describe the memory + /// ordering of this operation. The first describes the required ordering for + /// when the operation finally succeeds while the second describes the + /// required ordering for loads. These correspond to the success and failure + /// orderings of [`AtomicPtr::compare_exchange`] respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on pointers. + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + /// + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr: *mut _ = &mut 5; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let new: *mut _ = &mut 10; + /// let result = some_ptr.update(Ordering::SeqCst, Ordering::SeqCst, |_| new); + /// assert_eq!(result, ptr); + /// assert_eq!(some_ptr.load(Ordering::SeqCst), new); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[cfg(target_has_atomic = "8")] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: impl FnMut(*mut T) -> *mut T, + ) -> *mut T { + let mut prev = self.load(fetch_order); + loop { + match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) { + Ok(x) => break x, + Err(next_prev) => prev = next_prev, + } + } + } /// Offsets the pointer's address by adding `val` (in units of `T`), /// returning the previous pointer. @@ -2875,7 +3125,7 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. + /// This method is not magic; it is not provided by the hardware. /// It is implemented in terms of #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] /// and suffers from the same drawbacks. @@ -2913,6 +3163,127 @@ macro_rules! atomic_int { Err(prev) } + /// Fetches the value, and applies a function to it that returns an optional + /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else + /// `Err(previous_value)`. + /// + #[doc = concat!("See also: [`update`](`", stringify!($atomic_type), "::update`).")] + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied + /// only once to the stored value. + /// + /// `try_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. + /// The first describes the required ordering for when the operation finally succeeds while the second + /// describes the required ordering for loads. These correspond to the success and failure orderings of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")] + /// respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic operations on + #[doc = concat!("[`", $s_int_type, "`].")] + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] + /// and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] + /// + #[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")] + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7)); + /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8)); + /// assert_eq!(x.load(Ordering::SeqCst), 9); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn try_update( + &self, + set_order: Ordering, + fetch_order: Ordering, + f: impl FnMut($int_type) -> Option<$int_type>, + ) -> Result<$int_type, $int_type> { + // FIXME(atomic_try_update): this is currently an unstable alias to `fetch_update`; + // when stabilizing, turn `fetch_update` into a deprecated alias to `try_update`. + self.fetch_update(set_order, fetch_order, f) + } + + /// Fetches the value, applies a function to it that it return a new value. + /// The new value is stored and the old value is returned. + /// + #[doc = concat!("See also: [`try_update`](`", stringify!($atomic_type), "::try_update`).")] + /// + /// Note: This may call the function multiple times if the value has been changed from other threads in + /// the meantime, but the function will have been applied only once to the stored value. + /// + /// `update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. + /// The first describes the required ordering for when the operation finally succeeds while the second + /// describes the required ordering for loads. These correspond to the success and failure orderings of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")] + /// respectively. + /// + /// Using [`Acquire`] as success ordering makes the store part + /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load + /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic operations on + #[doc = concat!("[`", $s_int_type, "`].")] + /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] + /// and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// + /// # Examples + /// + /// ```rust + /// #![feature(atomic_try_update)] + #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] + /// + #[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")] + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 7); + /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 8); + /// assert_eq!(x.load(Ordering::SeqCst), 9); + /// ``` + #[inline] + #[unstable(feature = "atomic_try_update", issue = "135894")] + #[$cfg_cas] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub fn update( + &self, + set_order: Ordering, + fetch_order: Ordering, + mut f: impl FnMut($int_type) -> $int_type, + ) -> $int_type { + let mut prev = self.load(fetch_order); + loop { + match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) { + Ok(x) => break x, + Err(next_prev) => prev = next_prev, + } + } + } + /// Maximum with the current value. /// /// Finds the maximum of the current value and the argument `val`, and From fd9c57c7664894194ef53c082fb98497a59274ae Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 11 Jan 2025 12:01:31 +0100 Subject: [PATCH 379/481] alloc: add `#![warn(unreachable_pub)]` --- alloc/src/collections/btree/append.rs | 10 +- alloc/src/collections/btree/borrow.rs | 10 +- .../collections/btree/dedup_sorted_iter.rs | 4 +- alloc/src/collections/btree/fix.rs | 13 +- alloc/src/collections/btree/mem.rs | 4 +- alloc/src/collections/btree/merge_iter.rs | 8 +- alloc/src/collections/btree/mod.rs | 4 +- alloc/src/collections/btree/navigate.rs | 72 +++--- alloc/src/collections/btree/node.rs | 209 ++++++++++-------- alloc/src/collections/btree/node/tests.rs | 4 +- alloc/src/collections/btree/remove.rs | 2 +- alloc/src/collections/btree/search.rs | 21 +- alloc/src/collections/btree/split.rs | 8 +- alloc/src/collections/linked_list/tests.rs | 2 +- alloc/src/lib.rs | 3 +- alloc/src/raw_vec.rs | 44 ++-- alloc/src/slice.rs | 1 + alloc/src/testing/crash_test.rs | 20 +- alloc/src/testing/mod.rs | 6 +- alloc/src/testing/ord_chaos.rs | 10 +- alloc/src/testing/rng.rs | 6 +- 21 files changed, 251 insertions(+), 210 deletions(-) diff --git a/alloc/src/collections/btree/append.rs b/alloc/src/collections/btree/append.rs index d137d2721ee4f..091376d5d685b 100644 --- a/alloc/src/collections/btree/append.rs +++ b/alloc/src/collections/btree/append.rs @@ -16,7 +16,7 @@ impl Root { /// a `BTreeMap`, both iterators should produce keys in strictly ascending /// order, each greater than all keys in the tree, including any keys /// already in the tree upon entry. - pub fn append_from_sorted_iters( + pub(super) fn append_from_sorted_iters( &mut self, left: I, right: I, @@ -36,8 +36,12 @@ impl Root { /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. - pub fn bulk_push(&mut self, iter: I, length: &mut usize, alloc: A) - where + pub(super) fn bulk_push( + &mut self, + iter: I, + length: &mut usize, + alloc: A, + ) where I: Iterator, { let mut cur_node = self.borrow_mut().last_leaf_edge().into_node(); diff --git a/alloc/src/collections/btree/borrow.rs b/alloc/src/collections/btree/borrow.rs index 000b9bd0fab42..e848ac3f2d192 100644 --- a/alloc/src/collections/btree/borrow.rs +++ b/alloc/src/collections/btree/borrow.rs @@ -11,7 +11,7 @@ use core::ptr::NonNull; /// the compiler to follow. A `DormantMutRef` allows you to check borrowing /// yourself, while still expressing its stacked nature, and encapsulating /// the raw pointer code needed to do this without undefined behavior. -pub struct DormantMutRef<'a, T> { +pub(super) struct DormantMutRef<'a, T> { ptr: NonNull, _marker: PhantomData<&'a mut T>, } @@ -23,7 +23,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// Capture a unique borrow, and immediately reborrow it. For the compiler, /// the lifetime of the new reference is the same as the lifetime of the /// original reference, but you promise to use it for a shorter period. - pub fn new(t: &'a mut T) -> (&'a mut T, Self) { + pub(super) fn new(t: &'a mut T) -> (&'a mut T, Self) { let ptr = NonNull::from(t); // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose // only this reference, so it is unique. @@ -37,7 +37,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn awaken(self) -> &'a mut T { + pub(super) unsafe fn awaken(self) -> &'a mut T { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &mut *self.ptr.as_ptr() } } @@ -48,7 +48,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn reborrow(&mut self) -> &'a mut T { + pub(super) unsafe fn reborrow(&mut self) -> &'a mut T { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &mut *self.ptr.as_ptr() } } @@ -59,7 +59,7 @@ impl<'a, T> DormantMutRef<'a, T> { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn reborrow_shared(&self) -> &'a T { + pub(super) unsafe fn reborrow_shared(&self) -> &'a T { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &*self.ptr.as_ptr() } } diff --git a/alloc/src/collections/btree/dedup_sorted_iter.rs b/alloc/src/collections/btree/dedup_sorted_iter.rs index cd6a88f329125..6bcf0bca519af 100644 --- a/alloc/src/collections/btree/dedup_sorted_iter.rs +++ b/alloc/src/collections/btree/dedup_sorted_iter.rs @@ -6,7 +6,7 @@ use core::iter::Peekable; /// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1]. /// /// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter -pub struct DedupSortedIter +pub(super) struct DedupSortedIter where I: Iterator, { @@ -17,7 +17,7 @@ impl DedupSortedIter where I: Iterator, { - pub fn new(iter: I) -> Self { + pub(super) fn new(iter: I) -> Self { Self { iter: iter.peekable() } } } diff --git a/alloc/src/collections/btree/fix.rs b/alloc/src/collections/btree/fix.rs index 09edea3555ad5..b0c6759794691 100644 --- a/alloc/src/collections/btree/fix.rs +++ b/alloc/src/collections/btree/fix.rs @@ -57,7 +57,10 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// /// This method does not expect ancestors to already be underfull upon entry /// and panics if it encounters an empty ancestor. - pub fn fix_node_and_affected_ancestors(mut self, alloc: A) -> bool { + pub(super) fn fix_node_and_affected_ancestors( + mut self, + alloc: A, + ) -> bool { loop { match self.fix_node_through_parent(alloc.clone()) { Ok(Some(parent)) => self = parent.forget_type(), @@ -70,7 +73,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { impl Root { /// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty. - pub fn fix_top(&mut self, alloc: A) { + pub(super) fn fix_top(&mut self, alloc: A) { while self.height() > 0 && self.len() == 0 { self.pop_internal_level(alloc.clone()); } @@ -79,7 +82,7 @@ impl Root { /// Stocks up or merge away any underfull nodes on the right border of the /// tree. The other nodes, those that are not the root nor a rightmost edge, /// must already have at least MIN_LEN elements. - pub fn fix_right_border(&mut self, alloc: A) { + pub(super) fn fix_right_border(&mut self, alloc: A) { self.fix_top(alloc.clone()); if self.len() > 0 { self.borrow_mut().last_kv().fix_right_border_of_right_edge(alloc.clone()); @@ -88,7 +91,7 @@ impl Root { } /// The symmetric clone of `fix_right_border`. - pub fn fix_left_border(&mut self, alloc: A) { + pub(super) fn fix_left_border(&mut self, alloc: A) { self.fix_top(alloc.clone()); if self.len() > 0 { self.borrow_mut().first_kv().fix_left_border_of_left_edge(alloc.clone()); @@ -99,7 +102,7 @@ impl Root { /// Stocks up any underfull nodes on the right border of the tree. /// The other nodes, those that are neither the root nor a rightmost edge, /// must be prepared to have up to MIN_LEN elements stolen. - pub fn fix_right_border_of_plentiful(&mut self) { + pub(super) fn fix_right_border_of_plentiful(&mut self) { let mut cur_node = self.borrow_mut(); while let Internal(internal) = cur_node.force() { // Check if rightmost child is underfull. diff --git a/alloc/src/collections/btree/mem.rs b/alloc/src/collections/btree/mem.rs index d738c5c47b4cc..4643c4133d55d 100644 --- a/alloc/src/collections/btree/mem.rs +++ b/alloc/src/collections/btree/mem.rs @@ -6,7 +6,7 @@ use core::{intrinsics, mem, ptr}; /// If a panic occurs in the `change` closure, the entire process will be aborted. #[allow(dead_code)] // keep as illustration and for future use #[inline] -pub fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { +pub(super) fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { replace(v, |value| (change(value), ())) } @@ -15,7 +15,7 @@ pub fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { /// /// If a panic occurs in the `change` closure, the entire process will be aborted. #[inline] -pub fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { +pub(super) fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { struct PanicGuard; impl Drop for PanicGuard { fn drop(&mut self) { diff --git a/alloc/src/collections/btree/merge_iter.rs b/alloc/src/collections/btree/merge_iter.rs index 7f23d93b990f5..c5b93d30a1185 100644 --- a/alloc/src/collections/btree/merge_iter.rs +++ b/alloc/src/collections/btree/merge_iter.rs @@ -4,7 +4,7 @@ use core::iter::FusedIterator; /// Core of an iterator that merges the output of two strictly ascending iterators, /// for instance a union or a symmetric difference. -pub struct MergeIterInner { +pub(super) struct MergeIterInner { a: I, b: I, peeked: Option>, @@ -40,7 +40,7 @@ where impl MergeIterInner { /// Creates a new core for an iterator merging a pair of sources. - pub fn new(a: I, b: I) -> Self { + pub(super) fn new(a: I, b: I) -> Self { MergeIterInner { a, b, peeked: None } } @@ -51,7 +51,7 @@ impl MergeIterInner { /// the sources are not strictly ascending). If neither returned option /// contains a value, iteration has finished and subsequent calls will /// return the same empty pair. - pub fn nexts Ordering>( + pub(super) fn nexts Ordering>( &mut self, cmp: Cmp, ) -> (Option, Option) @@ -85,7 +85,7 @@ impl MergeIterInner { } /// Returns a pair of upper bounds for the `size_hint` of the final iterator. - pub fn lens(&self) -> (usize, usize) + pub(super) fn lens(&self) -> (usize, usize) where I: ExactSizeIterator, { diff --git a/alloc/src/collections/btree/mod.rs b/alloc/src/collections/btree/mod.rs index b8667d09c33b3..6651480667391 100644 --- a/alloc/src/collections/btree/mod.rs +++ b/alloc/src/collections/btree/mod.rs @@ -2,13 +2,13 @@ mod append; mod borrow; mod dedup_sorted_iter; mod fix; -pub mod map; +pub(super) mod map; mod mem; mod merge_iter; mod navigate; mod node; mod remove; mod search; -pub mod set; +pub(super) mod set; mod set_val; mod split; diff --git a/alloc/src/collections/btree/navigate.rs b/alloc/src/collections/btree/navigate.rs index 14b7d4ad71f86..b2a7de74875d9 100644 --- a/alloc/src/collections/btree/navigate.rs +++ b/alloc/src/collections/btree/navigate.rs @@ -7,7 +7,7 @@ use super::node::{Handle, NodeRef, marker}; use super::search::SearchBound; use crate::alloc::Allocator; // `front` and `back` are always both `None` or both `Some`. -pub struct LeafRange { +pub(super) struct LeafRange { front: Option, marker::Edge>>, back: Option, marker::Edge>>, } @@ -25,7 +25,7 @@ impl Default for LeafRange { } impl LeafRange { - pub fn none() -> Self { + pub(super) fn none() -> Self { LeafRange { front: None, back: None } } @@ -34,7 +34,7 @@ impl LeafRange { } /// Temporarily takes out another, immutable equivalent of the same range. - pub fn reborrow(&self) -> LeafRange, K, V> { + pub(super) fn reborrow(&self) -> LeafRange, K, V> { LeafRange { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), @@ -44,24 +44,24 @@ impl LeafRange { impl<'a, K, V> LeafRange, K, V> { #[inline] - pub fn next_checked(&mut self) -> Option<(&'a K, &'a V)> { + pub(super) fn next_checked(&mut self) -> Option<(&'a K, &'a V)> { self.perform_next_checked(|kv| kv.into_kv()) } #[inline] - pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> { + pub(super) fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> { self.perform_next_back_checked(|kv| kv.into_kv()) } } impl<'a, K, V> LeafRange, K, V> { #[inline] - pub fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> { + pub(super) fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> { self.perform_next_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut()) } #[inline] - pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> { + pub(super) fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> { self.perform_next_back_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut()) } } @@ -124,7 +124,7 @@ impl LazyLeafHandle { } // `front` and `back` are always both `None` or both `Some`. -pub struct LazyLeafRange { +pub(super) struct LazyLeafRange { front: Option>, back: Option>, } @@ -142,12 +142,12 @@ impl<'a, K: 'a, V: 'a> Clone for LazyLeafRange, K, V> { } impl LazyLeafRange { - pub fn none() -> Self { + pub(super) fn none() -> Self { LazyLeafRange { front: None, back: None } } /// Temporarily takes out another, immutable equivalent of the same range. - pub fn reborrow(&self) -> LazyLeafRange, K, V> { + pub(super) fn reborrow(&self) -> LazyLeafRange, K, V> { LazyLeafRange { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), @@ -157,24 +157,24 @@ impl LazyLeafRange { impl<'a, K, V> LazyLeafRange, K, V> { #[inline] - pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { + pub(super) unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { unsafe { self.init_front().unwrap().next_unchecked() } } #[inline] - pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { + pub(super) unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { unsafe { self.init_back().unwrap().next_back_unchecked() } } } impl<'a, K, V> LazyLeafRange, K, V> { #[inline] - pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { + pub(super) unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { self.init_front().unwrap().next_unchecked() } } #[inline] - pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { + pub(super) unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { self.init_back().unwrap().next_back_unchecked() } } } @@ -190,7 +190,7 @@ impl LazyLeafRange { } #[inline] - pub unsafe fn deallocating_next_unchecked( + pub(super) unsafe fn deallocating_next_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -200,7 +200,7 @@ impl LazyLeafRange { } #[inline] - pub unsafe fn deallocating_next_back_unchecked( + pub(super) unsafe fn deallocating_next_back_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -210,7 +210,7 @@ impl LazyLeafRange { } #[inline] - pub fn deallocating_end(&mut self, alloc: A) { + pub(super) fn deallocating_end(&mut self, alloc: A) { if let Some(front) = self.take_front() { front.deallocating_end(alloc) } @@ -313,7 +313,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// /// The result is meaningful only if the tree is ordered by key, like the tree /// in a `BTreeMap` is. - pub fn range_search(self, range: R) -> LeafRange, K, V> + pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, K: Borrow, @@ -324,7 +324,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } /// Finds the pair of leaf edges delimiting an entire tree. - pub fn full_range(self) -> LazyLeafRange, K, V> { + pub(super) fn full_range(self) -> LazyLeafRange, K, V> { full_range(self, self) } } @@ -339,7 +339,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// /// # Safety /// Do not use the duplicate handles to visit the same KV twice. - pub fn range_search(self, range: R) -> LeafRange, K, V> + pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, K: Borrow, @@ -351,7 +351,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. /// The results are non-unique references allowing mutation (of values only), so must be used /// with care. - pub fn full_range(self) -> LazyLeafRange, K, V> { + pub(super) fn full_range(self) -> LazyLeafRange, K, V> { // We duplicate the root NodeRef here -- we will never visit the same KV // twice, and never end up with overlapping value references. let self2 = unsafe { ptr::read(&self) }; @@ -363,7 +363,7 @@ impl NodeRef { /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. /// The results are non-unique references allowing massively destructive mutation, so must be /// used with the utmost care. - pub fn full_range(self) -> LazyLeafRange { + pub(super) fn full_range(self) -> LazyLeafRange { // We duplicate the root NodeRef here -- we will never access it in a way // that overlaps references obtained from the root. let self2 = unsafe { ptr::read(&self) }; @@ -377,7 +377,7 @@ impl /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the right side, which is either in the same leaf node or in an ancestor node. /// If the leaf edge is the last one in the tree, returns [`Result::Err`] with the root node. - pub fn next_kv( + pub(super) fn next_kv( self, ) -> Result< Handle, marker::KV>, @@ -398,7 +398,7 @@ impl /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the left side, which is either in the same leaf node or in an ancestor node. /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node. - pub fn next_back_kv( + pub(super) fn next_back_kv( self, ) -> Result< Handle, marker::KV>, @@ -627,7 +627,9 @@ impl NodeRef Handle, marker::Edge> { + pub(super) fn first_leaf_edge( + self, + ) -> Handle, marker::Edge> { let mut node = self; loop { match node.force() { @@ -640,7 +642,9 @@ impl NodeRef Handle, marker::Edge> { + pub(super) fn last_leaf_edge( + self, + ) -> Handle, marker::Edge> { let mut node = self; loop { match node.force() { @@ -651,7 +655,7 @@ impl NodeRef { +pub(super) enum Position { Leaf(NodeRef), Internal(NodeRef), InternalKV, @@ -661,7 +665,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// Visits leaf nodes and internal KVs in order of ascending keys, and also /// visits internal nodes as a whole in a depth first order, meaning that /// internal nodes precede their individual KVs and their child nodes. - pub fn visit_nodes_in_order(self, mut visit: F) + pub(super) fn visit_nodes_in_order(self, mut visit: F) where F: FnMut(Position, K, V>), { @@ -693,7 +697,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } /// Calculates the number of elements in a (sub)tree. - pub fn calc_length(self) -> usize { + pub(super) fn calc_length(self) -> usize { let mut result = 0; self.visit_nodes_in_order(|pos| match pos { Position::Leaf(node) => result += node.len(), @@ -708,7 +712,9 @@ impl Handle, marker::KV> { /// Returns the leaf edge closest to a KV for forward navigation. - pub fn next_leaf_edge(self) -> Handle, marker::Edge> { + pub(super) fn next_leaf_edge( + self, + ) -> Handle, marker::Edge> { match self.force() { Leaf(leaf_kv) => leaf_kv.right_edge(), Internal(internal_kv) => { @@ -719,7 +725,7 @@ impl } /// Returns the leaf edge closest to a KV for backward navigation. - pub fn next_back_leaf_edge( + pub(super) fn next_back_leaf_edge( self, ) -> Handle, marker::Edge> { match self.force() { @@ -735,7 +741,7 @@ impl impl NodeRef { /// Returns the leaf edge corresponding to the first point at which the /// given bound is true. - pub fn lower_bound( + pub(super) fn lower_bound( self, mut bound: SearchBound<&Q>, ) -> Handle, marker::Edge> @@ -758,7 +764,7 @@ impl NodeRef( + pub(super) fn upper_bound( self, mut bound: SearchBound<&Q>, ) -> Handle, marker::Edge> diff --git a/alloc/src/collections/btree/node.rs b/alloc/src/collections/btree/node.rs index 4057657632ba4..6815ac1c19305 100644 --- a/alloc/src/collections/btree/node.rs +++ b/alloc/src/collections/btree/node.rs @@ -40,8 +40,8 @@ use crate::alloc::{Allocator, Layout}; use crate::boxed::Box; const B: usize = 6; -pub const CAPACITY: usize = 2 * B - 1; -pub const MIN_LEN_AFTER_SPLIT: usize = B - 1; +pub(super) const CAPACITY: usize = 2 * B - 1; +pub(super) const MIN_LEN_AFTER_SPLIT: usize = B - 1; const KV_IDX_CENTER: usize = B - 1; const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1; const EDGE_IDX_RIGHT_OF_CENTER: usize = B; @@ -179,7 +179,7 @@ type BoxedNode = NonNull>; /// as the returned reference is used. /// The methods supporting insert bend this rule by returning a raw pointer, /// i.e., a reference without any lifetime. -pub struct NodeRef { +pub(super) struct NodeRef { /// The number of levels that the node and the level of leaves are apart, a /// constant of the node that cannot be entirely described by `Type`, and that /// the node itself does not store. We only need to store the height of the root @@ -195,7 +195,7 @@ pub struct NodeRef { /// The root node of an owned tree. /// /// Note that this does not have a destructor, and must be cleaned up manually. -pub type Root = NodeRef; +pub(super) type Root = NodeRef; impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef, K, V, Type> {} impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef, K, V, Type> { @@ -213,7 +213,7 @@ unsafe impl Send for NodeRef unsafe impl Send for NodeRef {} impl NodeRef { - pub fn new_leaf(alloc: A) -> Self { + pub(super) fn new_leaf(alloc: A) -> Self { Self::from_new_leaf(LeafNode::new(alloc)) } @@ -274,7 +274,7 @@ impl NodeRef { /// The number of edges is `len() + 1`. /// Note that, despite being safe, calling this function can have the side effect /// of invalidating mutable references that unsafe code has created. - pub fn len(&self) -> usize { + pub(super) fn len(&self) -> usize { // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut, // there might be outstanding mutable references to values that we must not invalidate. unsafe { usize::from((*Self::as_leaf_ptr(self)).len) } @@ -285,12 +285,12 @@ impl NodeRef { /// root on top, the number says at which elevation the node appears. /// If you picture trees with leaves on top, the number says how high /// the tree extends above the node. - pub fn height(&self) -> usize { + pub(super) fn height(&self) -> usize { self.height } /// Temporarily takes out another, immutable reference to the same node. - pub fn reborrow(&self) -> NodeRef, K, V, Type> { + pub(super) fn reborrow(&self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -315,7 +315,7 @@ impl NodeRef /// /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. - pub fn ascend( + pub(super) fn ascend( self, ) -> Result, marker::Edge>, Self> { const { @@ -335,24 +335,24 @@ impl NodeRef .ok_or(self) } - pub fn first_edge(self) -> Handle { + pub(super) fn first_edge(self) -> Handle { unsafe { Handle::new_edge(self, 0) } } - pub fn last_edge(self) -> Handle { + pub(super) fn last_edge(self) -> Handle { let len = self.len(); unsafe { Handle::new_edge(self, len) } } /// Note that `self` must be nonempty. - pub fn first_kv(self) -> Handle { + pub(super) fn first_kv(self) -> Handle { let len = self.len(); assert!(len > 0); unsafe { Handle::new_kv(self, 0) } } /// Note that `self` must be nonempty. - pub fn last_kv(self) -> Handle { + pub(super) fn last_kv(self) -> Handle { let len = self.len(); assert!(len > 0); unsafe { Handle::new_kv(self, len - 1) } @@ -381,7 +381,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } /// Borrows a view into the keys stored in the node. - pub fn keys(&self) -> &[K] { + pub(super) fn keys(&self) -> &[K] { let leaf = self.into_leaf(); unsafe { leaf.keys.get_unchecked(..usize::from(leaf.len)).assume_init_ref() } } @@ -391,7 +391,7 @@ impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also /// deallocates the current node in the process. This is unsafe because the /// current node will still be accessible despite being deallocated. - pub unsafe fn deallocate_and_ascend( + pub(super) unsafe fn deallocate_and_ascend( self, alloc: A, ) -> Option, marker::Edge>> { @@ -443,7 +443,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Returns a dormant copy of this node with its lifetime erased which can /// be reawakened later. - pub fn dormant(&self) -> NodeRef { + pub(super) fn dormant(&self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -455,7 +455,7 @@ impl NodeRef { /// /// The reborrow must have ended, i.e., the reference returned by `new` and /// all pointers and references derived from it, must not be used anymore. - pub unsafe fn awaken<'a>(self) -> NodeRef, K, V, Type> { + pub(super) unsafe fn awaken<'a>(self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -536,7 +536,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// Borrows exclusive access to the length of the node. - pub fn len_mut(&mut self) -> &mut u16 { + pub(super) fn len_mut(&mut self) -> &mut u16 { &mut self.as_leaf_mut().len } } @@ -578,14 +578,14 @@ impl NodeRef { impl NodeRef { /// Returns a new owned tree, with its own root node that is initially empty. - pub fn new(alloc: A) -> Self { + pub(super) fn new(alloc: A) -> Self { NodeRef::new_leaf(alloc).forget_type() } /// Adds a new internal node with a single edge pointing to the previous root node, /// make that new node the root node, and return it. This increases the height by 1 /// and is the opposite of `pop_internal_level`. - pub fn push_internal_level( + pub(super) fn push_internal_level( &mut self, alloc: A, ) -> NodeRef, K, V, marker::Internal> { @@ -604,7 +604,7 @@ impl NodeRef { /// it will not invalidate other handles or references to the root node. /// /// Panics if there is no internal level, i.e., if the root node is a leaf. - pub fn pop_internal_level(&mut self, alloc: A) { + pub(super) fn pop_internal_level(&mut self, alloc: A) { assert!(self.height > 0); let top = self.node; @@ -628,18 +628,18 @@ impl NodeRef { /// Mutably borrows the owned root node. Unlike `reborrow_mut`, this is safe /// because the return value cannot be used to destroy the root, and there /// cannot be other references to the tree. - pub fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { + pub(super) fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Slightly mutably borrows the owned root node. - pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { + pub(super) fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Irreversibly transitions to a reference that permits traversal and offers /// destructive methods and little else. - pub fn into_dying(self) -> NodeRef { + pub(super) fn into_dying(self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -651,7 +651,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// # Safety /// /// The returned handle has an unbound lifetime. - pub unsafe fn push_with_handle<'b>( + pub(super) unsafe fn push_with_handle<'b>( &mut self, key: K, val: V, @@ -672,7 +672,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { /// Adds a key-value pair to the end of the node, and returns /// the mutable reference of the inserted value. - pub fn push(&mut self, key: K, val: V) -> *mut V { + pub(super) fn push(&mut self, key: K, val: V) -> *mut V { // SAFETY: The unbound handle is no longer accessible. unsafe { self.push_with_handle(key, val).into_val_mut() } } @@ -681,7 +681,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { /// Adds a key-value pair, and an edge to go to the right of that pair, /// to the end of the node. - pub fn push(&mut self, key: K, val: V, edge: Root) { + pub(super) fn push(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); let len = self.len_mut(); @@ -699,21 +699,21 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { impl NodeRef { /// Removes any static information asserting that this node is a `Leaf` node. - pub fn forget_type(self) -> NodeRef { + pub(super) fn forget_type(self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Removes any static information asserting that this node is an `Internal` node. - pub fn forget_type(self) -> NodeRef { + pub(super) fn forget_type(self) -> NodeRef { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Checks whether a node is an `Internal` node or a `Leaf` node. - pub fn force( + pub(super) fn force( self, ) -> ForceResult< NodeRef, @@ -737,7 +737,9 @@ impl NodeRef { impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. - pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { + pub(super) unsafe fn cast_to_leaf_unchecked( + self, + ) -> NodeRef, K, V, marker::Leaf> { debug_assert!(self.height == 0); NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -757,7 +759,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// a child node, these represent the spaces where child pointers would go between the key-value /// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one /// to the left of the node, one between the two pairs, and one at the right of the node. -pub struct Handle { +pub(super) struct Handle { node: Node, idx: usize, _marker: PhantomData, @@ -774,12 +776,12 @@ impl Clone for Handle { impl Handle { /// Retrieves the node that contains the edge or key-value pair this handle points to. - pub fn into_node(self) -> Node { + pub(super) fn into_node(self) -> Node { self.node } /// Returns the position of this handle in the node. - pub fn idx(&self) -> usize { + pub(super) fn idx(&self) -> usize { self.idx } } @@ -787,17 +789,17 @@ impl Handle { impl Handle, marker::KV> { /// Creates a new handle to a key-value pair in `node`. /// Unsafe because the caller must ensure that `idx < node.len()`. - pub unsafe fn new_kv(node: NodeRef, idx: usize) -> Self { + pub(super) unsafe fn new_kv(node: NodeRef, idx: usize) -> Self { debug_assert!(idx < node.len()); Handle { node, idx, _marker: PhantomData } } - pub fn left_edge(self) -> Handle, marker::Edge> { + pub(super) fn left_edge(self) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node, self.idx) } } - pub fn right_edge(self) -> Handle, marker::Edge> { + pub(super) fn right_edge(self) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node, self.idx + 1) } } } @@ -815,7 +817,9 @@ impl Handle, HandleType> { /// Temporarily takes out another immutable handle on the same location. - pub fn reborrow(&self) -> Handle, K, V, NodeType>, HandleType> { + pub(super) fn reborrow( + &self, + ) -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type Handle { node: self.node.reborrow(), idx: self.idx, _marker: PhantomData } } @@ -827,7 +831,7 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// dangerous. /// /// For details, see `NodeRef::reborrow_mut`. - pub unsafe fn reborrow_mut( + pub(super) unsafe fn reborrow_mut( &mut self, ) -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type @@ -837,7 +841,9 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// Returns a dormant copy of this handle which can be reawakened later. /// /// See `DormantMutRef` for more details. - pub fn dormant(&self) -> Handle, HandleType> { + pub(super) fn dormant( + &self, + ) -> Handle, HandleType> { Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData } } } @@ -849,7 +855,9 @@ impl Handle(self) -> Handle, K, V, NodeType>, HandleType> { + pub(super) unsafe fn awaken<'a>( + self, + ) -> Handle, K, V, NodeType>, HandleType> { Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData } } } @@ -857,13 +865,15 @@ impl Handle Handle, marker::Edge> { /// Creates a new handle to an edge in `node`. /// Unsafe because the caller must ensure that `idx <= node.len()`. - pub unsafe fn new_edge(node: NodeRef, idx: usize) -> Self { + pub(super) unsafe fn new_edge(node: NodeRef, idx: usize) -> Self { debug_assert!(idx <= node.len()); Handle { node, idx, _marker: PhantomData } } - pub fn left_kv(self) -> Result, marker::KV>, Self> { + pub(super) fn left_kv( + self, + ) -> Result, marker::KV>, Self> { if self.idx > 0 { Ok(unsafe { Handle::new_kv(self.node, self.idx - 1) }) } else { @@ -871,7 +881,9 @@ impl Handle, mar } } - pub fn right_kv(self) -> Result, marker::KV>, Self> { + pub(super) fn right_kv( + self, + ) -> Result, marker::KV>, Self> { if self.idx < self.node.len() { Ok(unsafe { Handle::new_kv(self.node, self.idx) }) } else { @@ -880,7 +892,7 @@ impl Handle, mar } } -pub enum LeftOrRight { +pub(super) enum LeftOrRight { Left(T), Right(T), } @@ -1034,7 +1046,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// If the returned result is some `SplitResult`, the `left` field will be the root node. /// The returned pointer points to the inserted value, which in the case of `SplitResult` /// is in the `left` or `right` tree. - pub fn insert_recursing( + pub(super) fn insert_recursing( self, key: K, value: V, @@ -1078,7 +1090,7 @@ impl /// /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. - pub fn descend(self) -> NodeRef { + pub(super) fn descend(self) -> NodeRef { const { assert!(BorrowType::TRAVERSAL_PERMIT); } @@ -1097,7 +1109,7 @@ impl } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn into_kv(self) -> (&'a K, &'a V) { + pub(super) fn into_kv(self) -> (&'a K, &'a V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf(); let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() }; @@ -1107,17 +1119,17 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeTyp } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn key_mut(&mut self) -> &mut K { + pub(super) fn key_mut(&mut self) -> &mut K { unsafe { self.node.key_area_mut(self.idx).assume_init_mut() } } - pub fn into_val_mut(self) -> &'a mut V { + pub(super) fn into_val_mut(self) -> &'a mut V { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } - pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { + pub(super) fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.into_leaf_mut(); let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; @@ -1127,13 +1139,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> } impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + pub(super) fn into_kv_valmut(self) -> (&'a K, &'a mut V) { unsafe { self.node.into_key_val_mut_at(self.idx) } } } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn kv_mut(&mut self) -> (&mut K, &mut V) { + pub(super) fn kv_mut(&mut self) -> (&mut K, &mut V) { debug_assert!(self.idx < self.node.len()); // We cannot call separate key and value methods, because calling the second one // invalidates the reference returned by the first. @@ -1146,7 +1158,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> } /// Replaces the key and value that the KV handle refers to. - pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) { + pub(super) fn replace_kv(&mut self, k: K, v: V) -> (K, V) { let (key, val) = self.kv_mut(); (mem::replace(key, k), mem::replace(val, v)) } @@ -1156,7 +1168,7 @@ impl Handle, marker::KV> /// Extracts the key and value that the KV handle refers to. /// # Safety /// The node that the handle refers to must not yet have been deallocated. - pub unsafe fn into_key_val(mut self) -> (K, V) { + pub(super) unsafe fn into_key_val(mut self) -> (K, V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.as_leaf_dying(); unsafe { @@ -1170,7 +1182,7 @@ impl Handle, marker::KV> /// # Safety /// The node that the handle refers to must not yet have been deallocated. #[inline] - pub unsafe fn drop_key_val(mut self) { + pub(super) unsafe fn drop_key_val(mut self) { // Run the destructor of the value even if the destructor of the key panics. struct Dropper<'a, T>(&'a mut MaybeUninit); impl Drop for Dropper<'_, T> { @@ -1229,7 +1241,10 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// - The key and value pointed to by this handle are extracted. /// - All the key-value pairs to the right of this handle are put into a newly /// allocated node. - pub fn split(mut self, alloc: A) -> SplitResult<'a, K, V, marker::Leaf> { + pub(super) fn split( + mut self, + alloc: A, + ) -> SplitResult<'a, K, V, marker::Leaf> { let mut new_node = LeafNode::new(alloc); let kv = self.split_leaf_data(&mut new_node); @@ -1240,7 +1255,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// Removes the key-value pair pointed to by this handle and returns it, along with the edge /// that the key-value pair collapsed into. - pub fn remove( + pub(super) fn remove( mut self, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { let old_len = self.node.len(); @@ -1261,7 +1276,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// - The key and value pointed to by this handle are extracted. /// - All the edges and key-value pairs to the right of this handle are put into /// a newly allocated node. - pub fn split( + pub(super) fn split( mut self, alloc: A, ) -> SplitResult<'a, K, V, marker::Internal> { @@ -1285,14 +1300,14 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// Represents a session for evaluating and performing a balancing operation /// around an internal key-value pair. -pub struct BalancingContext<'a, K, V> { +pub(super) struct BalancingContext<'a, K, V> { parent: Handle, K, V, marker::Internal>, marker::KV>, left_child: NodeRef, K, V, marker::LeafOrInternal>, right_child: NodeRef, K, V, marker::LeafOrInternal>, } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { - pub fn consider_for_balancing(self) -> BalancingContext<'a, K, V> { + pub(super) fn consider_for_balancing(self) -> BalancingContext<'a, K, V> { let self1 = unsafe { ptr::read(&self) }; let self2 = unsafe { ptr::read(&self) }; BalancingContext { @@ -1318,7 +1333,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// typically faster, since we only need to shift the node's N elements to /// the right, instead of shifting at least N of the sibling's elements to /// the left. - pub fn choose_parent_kv(self) -> Result>, Self> { + pub(super) fn choose_parent_kv(self) -> Result>, Self> { match unsafe { ptr::read(&self) }.ascend() { Ok(parent_edge) => match parent_edge.left_kv() { Ok(left_parent_kv) => Ok(LeftOrRight::Left(BalancingContext { @@ -1341,25 +1356,25 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { } impl<'a, K, V> BalancingContext<'a, K, V> { - pub fn left_child_len(&self) -> usize { + pub(super) fn left_child_len(&self) -> usize { self.left_child.len() } - pub fn right_child_len(&self) -> usize { + pub(super) fn right_child_len(&self) -> usize { self.right_child.len() } - pub fn into_left_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { + pub(super) fn into_left_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { self.left_child } - pub fn into_right_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { + pub(super) fn into_right_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { self.right_child } /// Returns whether merging is possible, i.e., whether there is enough room /// in a node to combine the central KV with both adjacent child nodes. - pub fn can_merge(&self) -> bool { + pub(super) fn can_merge(&self) -> bool { self.left_child.len() + 1 + self.right_child.len() <= CAPACITY } } @@ -1433,7 +1448,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// the left child node and returns the shrunk parent node. /// /// Panics unless we `.can_merge()`. - pub fn merge_tracking_parent( + pub(super) fn merge_tracking_parent( self, alloc: A, ) -> NodeRef, K, V, marker::Internal> { @@ -1444,7 +1459,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// the left child node and returns that child node. /// /// Panics unless we `.can_merge()`. - pub fn merge_tracking_child( + pub(super) fn merge_tracking_child( self, alloc: A, ) -> NodeRef, K, V, marker::LeafOrInternal> { @@ -1456,7 +1471,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// where the tracked child edge ended up, /// /// Panics unless we `.can_merge()`. - pub fn merge_tracking_child_edge( + pub(super) fn merge_tracking_child_edge( self, track_edge_idx: LeftOrRight, alloc: A, @@ -1479,7 +1494,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// of the parent, while pushing the old parent key-value pair into the right child. /// Returns a handle to the edge in the right child corresponding to where the original /// edge specified by `track_right_edge_idx` ended up. - pub fn steal_left( + pub(super) fn steal_left( mut self, track_right_edge_idx: usize, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { @@ -1491,7 +1506,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// of the parent, while pushing the old parent key-value pair onto the left child. /// Returns a handle to the edge in the left child specified by `track_left_edge_idx`, /// which didn't move. - pub fn steal_right( + pub(super) fn steal_right( mut self, track_left_edge_idx: usize, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { @@ -1500,7 +1515,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } /// This does stealing similar to `steal_left` but steals multiple elements at once. - pub fn bulk_steal_left(&mut self, count: usize) { + pub(super) fn bulk_steal_left(&mut self, count: usize) { assert!(count > 0); unsafe { let left_node = &mut self.left_child; @@ -1563,7 +1578,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } /// The symmetric clone of `bulk_steal_left`. - pub fn bulk_steal_right(&mut self, count: usize) { + pub(super) fn bulk_steal_right(&mut self, count: usize) { assert!(count > 0); unsafe { let left_node = &mut self.left_child; @@ -1628,7 +1643,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { } impl Handle, marker::Edge> { - pub fn forget_node_type( + pub(super) fn forget_node_type( self, ) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node.forget_type(), self.idx) } @@ -1636,7 +1651,7 @@ impl Handle, marker::E } impl Handle, marker::Edge> { - pub fn forget_node_type( + pub(super) fn forget_node_type( self, ) -> Handle, marker::Edge> { unsafe { Handle::new_edge(self.node.forget_type(), self.idx) } @@ -1644,7 +1659,7 @@ impl Handle, marke } impl Handle, marker::KV> { - pub fn forget_node_type( + pub(super) fn forget_node_type( self, ) -> Handle, marker::KV> { unsafe { Handle::new_kv(self.node.forget_type(), self.idx) } @@ -1653,7 +1668,7 @@ impl Handle, marker::K impl Handle, Type> { /// Checks whether the underlying node is an `Internal` node or a `Leaf` node. - pub fn force( + pub(super) fn force( self, ) -> ForceResult< Handle, Type>, @@ -1672,7 +1687,7 @@ impl Handle Handle, K, V, marker::LeafOrInternal>, Type> { /// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`. - pub unsafe fn cast_to_leaf_unchecked( + pub(super) unsafe fn cast_to_leaf_unchecked( self, ) -> Handle, K, V, marker::Leaf>, Type> { let node = unsafe { self.node.cast_to_leaf_unchecked() }; @@ -1683,7 +1698,7 @@ impl<'a, K, V, Type> Handle, K, V, marker::LeafOrInterna impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { /// Move the suffix after `self` from one node to another one. `right` must be empty. /// The first edge of `right` remains unchanged. - pub fn move_suffix( + pub(super) fn move_suffix( &mut self, right: &mut NodeRef, K, V, marker::LeafOrInternal>, ) { @@ -1726,13 +1741,13 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma } } -pub enum ForceResult { +pub(super) enum ForceResult { Leaf(Leaf), Internal(Internal), } /// Result of insertion, when a node needed to expand beyond its capacity. -pub struct SplitResult<'a, K, V, NodeType> { +pub(super) struct SplitResult<'a, K, V, NodeType> { // Altered node in existing tree with elements and edges that belong to the left of `kv`. pub left: NodeRef, K, V, NodeType>, // Some key and value that existed before and were split off, to be inserted elsewhere. @@ -1742,32 +1757,32 @@ pub struct SplitResult<'a, K, V, NodeType> { } impl<'a, K, V> SplitResult<'a, K, V, marker::Leaf> { - pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { + pub(super) fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() } } } impl<'a, K, V> SplitResult<'a, K, V, marker::Internal> { - pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { + pub(super) fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() } } } -pub mod marker { +pub(super) mod marker { use core::marker::PhantomData; - pub enum Leaf {} - pub enum Internal {} - pub enum LeafOrInternal {} + pub(crate) enum Leaf {} + pub(crate) enum Internal {} + pub(crate) enum LeafOrInternal {} - pub enum Owned {} - pub enum Dying {} - pub enum DormantMut {} - pub struct Immut<'a>(PhantomData<&'a ()>); - pub struct Mut<'a>(PhantomData<&'a mut ()>); - pub struct ValMut<'a>(PhantomData<&'a mut ()>); + pub(crate) enum Owned {} + pub(crate) enum Dying {} + pub(crate) enum DormantMut {} + pub(crate) struct Immut<'a>(PhantomData<&'a ()>); + pub(crate) struct Mut<'a>(PhantomData<&'a mut ()>); + pub(crate) struct ValMut<'a>(PhantomData<&'a mut ()>); - pub trait BorrowType { + pub(crate) trait BorrowType { /// If node references of this borrow type allow traversing to other /// nodes in the tree, this constant is set to `true`. It can be used /// for a compile-time assertion. @@ -1786,8 +1801,8 @@ pub mod marker { impl<'a> BorrowType for ValMut<'a> {} impl BorrowType for DormantMut {} - pub enum KV {} - pub enum Edge {} + pub(crate) enum KV {} + pub(crate) enum Edge {} } /// Inserts a value into a slice of initialized elements followed by one uninitialized element. diff --git a/alloc/src/collections/btree/node/tests.rs b/alloc/src/collections/btree/node/tests.rs index 4d2fa0f094171..ecd009f11c71a 100644 --- a/alloc/src/collections/btree/node/tests.rs +++ b/alloc/src/collections/btree/node/tests.rs @@ -6,7 +6,7 @@ use crate::string::String; impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { // Asserts that the back pointer in each reachable node points to its parent. - pub fn assert_back_pointers(self) { + pub(crate) fn assert_back_pointers(self) { if let ForceResult::Internal(node) = self.force() { for idx in 0..=node.len() { let edge = unsafe { Handle::new_edge(node, idx) }; @@ -20,7 +20,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> // Renders a multi-line display of the keys in order and in tree hierarchy, // picturing the tree growing sideways from its root on the left to its // leaves on the right. - pub fn dump_keys(self) -> String + pub(crate) fn dump_keys(self) -> String where K: Debug, { diff --git a/alloc/src/collections/btree/remove.rs b/alloc/src/collections/btree/remove.rs index 56f2824b782bd..9d870b86f34a0 100644 --- a/alloc/src/collections/btree/remove.rs +++ b/alloc/src/collections/btree/remove.rs @@ -10,7 +10,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter /// the leaf edge corresponding to that former pair. It's possible this empties /// a root node that is internal, which the caller should pop from the map /// holding the tree. The caller should also decrement the map's length. - pub fn remove_kv_tracking( + pub(super) fn remove_kv_tracking( self, handle_emptied_internal_root: F, alloc: A, diff --git a/alloc/src/collections/btree/search.rs b/alloc/src/collections/btree/search.rs index 22e015edac3d2..96e5bf108024b 100644 --- a/alloc/src/collections/btree/search.rs +++ b/alloc/src/collections/btree/search.rs @@ -8,7 +8,7 @@ use SearchResult::*; use super::node::ForceResult::*; use super::node::{Handle, NodeRef, marker}; -pub enum SearchBound { +pub(super) enum SearchBound { /// An inclusive bound to look for, just like `Bound::Included(T)`. Included(T), /// An exclusive bound to look for, just like `Bound::Excluded(T)`. @@ -20,7 +20,7 @@ pub enum SearchBound { } impl SearchBound { - pub fn from_range(range_bound: Bound) -> Self { + pub(super) fn from_range(range_bound: Bound) -> Self { match range_bound { Bound::Included(t) => Included(t), Bound::Excluded(t) => Excluded(t), @@ -29,12 +29,12 @@ impl SearchBound { } } -pub enum SearchResult { +pub(super) enum SearchResult { Found(Handle, marker::KV>), GoDown(Handle, marker::Edge>), } -pub enum IndexResult { +pub(super) enum IndexResult { KV(usize), Edge(usize), } @@ -46,7 +46,7 @@ impl NodeRef( + pub(super) fn search_tree( mut self, key: &Q, ) -> SearchResult @@ -80,7 +80,7 @@ impl NodeRef( + pub(super) fn search_tree_for_bifurcation<'r, Q: ?Sized, R>( mut self, range: &'r R, ) -> Result< @@ -156,7 +156,7 @@ impl NodeRef( + pub(super) fn find_lower_bound_edge<'r, Q>( self, bound: SearchBound<&'r Q>, ) -> (Handle, SearchBound<&'r Q>) @@ -170,7 +170,7 @@ impl NodeRef( + pub(super) fn find_upper_bound_edge<'r, Q>( self, bound: SearchBound<&'r Q>, ) -> (Handle, SearchBound<&'r Q>) @@ -192,7 +192,10 @@ impl NodeRef { /// /// The result is meaningful only if the tree is ordered by key, like the tree /// in a `BTreeMap` is. - pub fn search_node(self, key: &Q) -> SearchResult + pub(super) fn search_node( + self, + key: &Q, + ) -> SearchResult where Q: Ord, K: Borrow, diff --git a/alloc/src/collections/btree/split.rs b/alloc/src/collections/btree/split.rs index c188ed1da6113..87a79e6cf3f93 100644 --- a/alloc/src/collections/btree/split.rs +++ b/alloc/src/collections/btree/split.rs @@ -8,7 +8,7 @@ use super::search::SearchResult::*; impl Root { /// Calculates the length of both trees that result from splitting up /// a given number of distinct key-value pairs. - pub fn calc_split_length( + pub(super) fn calc_split_length( total_num: usize, root_a: &Root, root_b: &Root, @@ -31,7 +31,11 @@ impl Root { /// and if the ordering of `Q` corresponds to that of `K`. /// If `self` respects all `BTreeMap` tree invariants, then both /// `self` and the returned tree will respect those invariants. - pub fn split_off(&mut self, key: &Q, alloc: A) -> Self + pub(super) fn split_off( + &mut self, + key: &Q, + alloc: A, + ) -> Self where K: Borrow, { diff --git a/alloc/src/collections/linked_list/tests.rs b/alloc/src/collections/linked_list/tests.rs index b7d4f8512a0f2..aa19239f6c55d 100644 --- a/alloc/src/collections/linked_list/tests.rs +++ b/alloc/src/collections/linked_list/tests.rs @@ -58,7 +58,7 @@ fn list_from(v: &[T]) -> LinkedList { v.iter().cloned().collect() } -pub fn check_links(list: &LinkedList) { +fn check_links(list: &LinkedList) { unsafe { let mut len = 0; let mut last_ptr: Option<&Node> = None; diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 28e4217e30394..0bb7c432cc35f 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -88,6 +88,7 @@ #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] #![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] // // Library features: // tidy-alphabetical-start @@ -227,7 +228,7 @@ pub mod alloc; pub mod boxed; #[cfg(test)] mod boxed { - pub use std::boxed::Box; + pub(crate) use std::boxed::Box; } pub mod borrow; #[unstable(feature = "bstr", issue = "134915")] diff --git a/alloc/src/raw_vec.rs b/alloc/src/raw_vec.rs index ad86bf4bf072f..b80d1fc788947 100644 --- a/alloc/src/raw_vec.rs +++ b/alloc/src/raw_vec.rs @@ -97,7 +97,7 @@ impl RawVec { /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. #[must_use] - pub const fn new() -> Self { + pub(crate) const fn new() -> Self { Self::new_in(Global) } @@ -120,7 +120,7 @@ impl RawVec { #[must_use] #[inline] #[track_caller] - pub fn with_capacity(capacity: usize) -> Self { + pub(crate) fn with_capacity(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData } } @@ -129,7 +129,7 @@ impl RawVec { #[must_use] #[inline] #[track_caller] - pub fn with_capacity_zeroed(capacity: usize) -> Self { + pub(crate) fn with_capacity_zeroed(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT), _marker: PhantomData, @@ -172,7 +172,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[inline] - pub const fn new_in(alloc: A) -> Self { + pub(crate) const fn new_in(alloc: A) -> Self { Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } } @@ -181,7 +181,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -191,7 +191,7 @@ impl RawVec { /// Like `try_with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[inline] - pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + pub(crate) fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { match RawVecInner::try_with_capacity_in(capacity, alloc, T::LAYOUT) { Ok(inner) => Ok(Self { inner, _marker: PhantomData }), Err(e) => Err(e), @@ -203,7 +203,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { + pub(crate) fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -222,7 +222,7 @@ impl RawVec { /// /// Note, that the requested capacity and `self.capacity()` could differ, as /// an allocator could overallocate and return a greater memory block than requested. - pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { + pub(crate) unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { // Sanity-check one half of the safety requirement (we cannot check the other half). debug_assert!( len <= self.capacity(), @@ -247,7 +247,7 @@ impl RawVec { /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is /// guaranteed. #[inline] - pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { + pub(crate) unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { // SAFETY: Precondition passed to the caller unsafe { let ptr = ptr.cast(); @@ -265,7 +265,7 @@ impl RawVec { /// /// See [`RawVec::from_raw_parts_in`]. #[inline] - pub unsafe fn from_nonnull_in(ptr: NonNull, capacity: usize, alloc: A) -> Self { + pub(crate) unsafe fn from_nonnull_in(ptr: NonNull, capacity: usize, alloc: A) -> Self { // SAFETY: Precondition passed to the caller unsafe { let ptr = ptr.cast(); @@ -278,12 +278,12 @@ impl RawVec { /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. #[inline] - pub const fn ptr(&self) -> *mut T { + pub(crate) const fn ptr(&self) -> *mut T { self.inner.ptr() } #[inline] - pub fn non_null(&self) -> NonNull { + pub(crate) fn non_null(&self) -> NonNull { self.inner.non_null() } @@ -291,13 +291,13 @@ impl RawVec { /// /// This will always be `usize::MAX` if `T` is zero-sized. #[inline] - pub const fn capacity(&self) -> usize { + pub(crate) const fn capacity(&self) -> usize { self.inner.capacity(size_of::()) } /// Returns a shared reference to the allocator backing this `RawVec`. #[inline] - pub fn allocator(&self) -> &A { + pub(crate) fn allocator(&self) -> &A { self.inner.allocator() } @@ -323,7 +323,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - pub fn reserve(&mut self, len: usize, additional: usize) { + pub(crate) fn reserve(&mut self, len: usize, additional: usize) { self.inner.reserve(len, additional, T::LAYOUT) } @@ -332,12 +332,16 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline(never)] #[track_caller] - pub fn grow_one(&mut self) { + pub(crate) fn grow_one(&mut self) { self.inner.grow_one(T::LAYOUT) } /// The same as `reserve`, but returns on errors instead of panicking or aborting. - pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + pub(crate) fn try_reserve( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TryReserveError> { self.inner.try_reserve(len, additional, T::LAYOUT) } @@ -360,12 +364,12 @@ impl RawVec { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] #[track_caller] - pub fn reserve_exact(&mut self, len: usize, additional: usize) { + pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) { self.inner.reserve_exact(len, additional, T::LAYOUT) } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. - pub fn try_reserve_exact( + pub(crate) fn try_reserve_exact( &mut self, len: usize, additional: usize, @@ -386,7 +390,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[track_caller] #[inline] - pub fn shrink_to_fit(&mut self, cap: usize) { + pub(crate) fn shrink_to_fit(&mut self, cap: usize) { self.inner.shrink_to_fit(cap, T::LAYOUT) } } diff --git a/alloc/src/slice.rs b/alloc/src/slice.rs index edc8d99f2f990..1cedead7aa243 100644 --- a/alloc/src/slice.rs +++ b/alloc/src/slice.rs @@ -85,6 +85,7 @@ use crate::vec::Vec; // functions are actually methods that are in `impl [T]` but not in // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test +#[allow(unreachable_pub)] // cfg(test) pub above pub(crate) mod hack { use core::alloc::Allocator; diff --git a/alloc/src/testing/crash_test.rs b/alloc/src/testing/crash_test.rs index 684bac60d9a86..8e00e4f41e5d6 100644 --- a/alloc/src/testing/crash_test.rs +++ b/alloc/src/testing/crash_test.rs @@ -11,7 +11,7 @@ use crate::fmt::Debug; // the `Debug` trait is the only thing we use from `crate /// Crash test dummies are identified and ordered by an id, so they can be used /// as keys in a BTreeMap. #[derive(Debug)] -pub struct CrashTestDummy { +pub(crate) struct CrashTestDummy { pub id: usize, cloned: AtomicUsize, dropped: AtomicUsize, @@ -20,7 +20,7 @@ pub struct CrashTestDummy { impl CrashTestDummy { /// Creates a crash test dummy design. The `id` determines order and equality of instances. - pub fn new(id: usize) -> CrashTestDummy { + pub(crate) fn new(id: usize) -> CrashTestDummy { CrashTestDummy { id, cloned: AtomicUsize::new(0), @@ -31,34 +31,34 @@ impl CrashTestDummy { /// Creates an instance of a crash test dummy that records what events it experiences /// and optionally panics. - pub fn spawn(&self, panic: Panic) -> Instance<'_> { + pub(crate) fn spawn(&self, panic: Panic) -> Instance<'_> { Instance { origin: self, panic } } /// Returns how many times instances of the dummy have been cloned. - pub fn cloned(&self) -> usize { + pub(crate) fn cloned(&self) -> usize { self.cloned.load(SeqCst) } /// Returns how many times instances of the dummy have been dropped. - pub fn dropped(&self) -> usize { + pub(crate) fn dropped(&self) -> usize { self.dropped.load(SeqCst) } /// Returns how many times instances of the dummy have had their `query` member invoked. - pub fn queried(&self) -> usize { + pub(crate) fn queried(&self) -> usize { self.queried.load(SeqCst) } } #[derive(Debug)] -pub struct Instance<'a> { +pub(crate) struct Instance<'a> { origin: &'a CrashTestDummy, panic: Panic, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Panic { +pub(crate) enum Panic { Never, InClone, InDrop, @@ -66,12 +66,12 @@ pub enum Panic { } impl Instance<'_> { - pub fn id(&self) -> usize { + pub(crate) fn id(&self) -> usize { self.origin.id } /// Some anonymous query, the result of which is already given. - pub fn query(&self, result: R) -> R { + pub(crate) fn query(&self, result: R) -> R { self.origin.queried.fetch_add(1, SeqCst); if self.panic == Panic::InQuery { panic!("panic in `query`"); diff --git a/alloc/src/testing/mod.rs b/alloc/src/testing/mod.rs index 7a094f8a59522..c8457daf93e5a 100644 --- a/alloc/src/testing/mod.rs +++ b/alloc/src/testing/mod.rs @@ -1,3 +1,3 @@ -pub mod crash_test; -pub mod ord_chaos; -pub mod rng; +pub(crate) mod crash_test; +pub(crate) mod ord_chaos; +pub(crate) mod rng; diff --git a/alloc/src/testing/ord_chaos.rs b/alloc/src/testing/ord_chaos.rs index 96ce7c1579046..55e1ae5e3deaa 100644 --- a/alloc/src/testing/ord_chaos.rs +++ b/alloc/src/testing/ord_chaos.rs @@ -4,7 +4,7 @@ use std::ptr; // Minimal type with an `Ord` implementation violating transitivity. #[derive(Debug)] -pub enum Cyclic3 { +pub(crate) enum Cyclic3 { A, B, C, @@ -37,16 +37,16 @@ impl Eq for Cyclic3 {} // Controls the ordering of values wrapped by `Governed`. #[derive(Debug)] -pub struct Governor { +pub(crate) struct Governor { flipped: Cell, } impl Governor { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Governor { flipped: Cell::new(false) } } - pub fn flip(&self) { + pub(crate) fn flip(&self) { self.flipped.set(!self.flipped.get()); } } @@ -55,7 +55,7 @@ impl Governor { // (assuming that `T` respects total order), but can suddenly be made to invert // that total order. #[derive(Debug)] -pub struct Governed<'a, T>(pub T, pub &'a Governor); +pub(crate) struct Governed<'a, T>(pub T, pub &'a Governor); impl PartialOrd for Governed<'_, T> { fn partial_cmp(&self, other: &Self) -> Option { diff --git a/alloc/src/testing/rng.rs b/alloc/src/testing/rng.rs index ecf543bee035a..77d3348f38a5d 100644 --- a/alloc/src/testing/rng.rs +++ b/alloc/src/testing/rng.rs @@ -1,5 +1,5 @@ /// XorShiftRng -pub struct DeterministicRng { +pub(crate) struct DeterministicRng { count: usize, x: u32, y: u32, @@ -8,12 +8,12 @@ pub struct DeterministicRng { } impl DeterministicRng { - pub fn new() -> Self { + pub(crate) fn new() -> Self { DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } } /// Guarantees that each returned number is unique. - pub fn next(&mut self) -> u32 { + pub(crate) fn next(&mut self) -> u32 { self.count += 1; assert!(self.count <= 70029); let x = self.x; From d014318e0f8274f58cdf74c95cfeb8dbfc3efde1 Mon Sep 17 00:00:00 2001 From: LemonJ <1632798336@qq.com> Date: Tue, 21 Jan 2025 16:25:56 +0800 Subject: [PATCH 380/481] add missing allocator safety in alloc crate --- alloc/src/boxed.rs | 5 ++++- alloc/src/sync.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 1b5e44a913467..8b38e6fc259af 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -1115,6 +1115,8 @@ impl Box { /// memory problems. For example, a double-free may occur if the /// function is called twice on the same `NonNull` pointer. /// + /// The non-null pointer must point to a block of memory allocated by the global allocator. + /// /// The safety conditions are described in the [memory layout] section. /// /// # Examples @@ -1170,7 +1172,7 @@ impl Box { /// 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` + /// The raw pointer must point to a block of memory allocated by `alloc`. /// /// # Examples /// @@ -1225,6 +1227,7 @@ impl Box { /// 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 /// diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 8eee7cff2080d..431e19e6ef1d7 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -2740,7 +2740,7 @@ impl Weak { /// # Safety /// /// The pointer must have originated from the [`into_raw`] and must still own its potential - /// weak reference. + /// weak reference, and must point to a block of memory allocated by global allocator. /// /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this /// takes ownership of one weak reference currently represented as a raw pointer (the weak From 8e702fc6aefd2dd7c4b8deb6910982c2d31042fc Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 22 Jan 2025 17:24:34 +0100 Subject: [PATCH 381/481] Document purpose of closure in from_fn.rs more clearly --- core/src/iter/sources/from_fn.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/iter/sources/from_fn.rs b/core/src/iter/sources/from_fn.rs index 5f3d404d7dca2..75cc0ffe3c77c 100644 --- a/core/src/iter/sources/from_fn.rs +++ b/core/src/iter/sources/from_fn.rs @@ -1,7 +1,7 @@ use crate::fmt; -/// Creates a new iterator where each iteration calls the provided closure -/// `F: FnMut() -> Option`. +/// Creates an iterator with the provided closure +/// `F: FnMut() -> Option` as its `[next](Iterator::next)` method. /// /// The iterator will yield the `T`s returned from the closure. /// From f5c8fa0baa86a9fc82402327fab0398166eb45e3 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sun, 26 Jan 2025 13:22:45 +0100 Subject: [PATCH 382/481] Document powf and powi calls that always return 1.0 --- std/src/f128.rs | 18 +++++++++++++++++- std/src/f16.rs | 18 +++++++++++++++++- std/src/f32.rs | 7 +++++-- std/src/f64.rs | 7 +++++-- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/std/src/f128.rs b/std/src/f128.rs index 4f37e18a8cd76..d65f5ed61cfbc 100644 --- a/std/src/f128.rs +++ b/std/src/f128.rs @@ -324,6 +324,20 @@ impl f128 { /// /// The precision of this function is non-deterministic. This means it varies by platform, /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 2.0_f128; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f128::EPSILON); + /// + /// assert_eq!(f128::powi(f128::NAN, 0), 1.0); + /// # } + /// ``` #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] @@ -347,8 +361,10 @@ impl f128 { /// /// let x = 2.0_f128; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// /// assert!(abs_difference <= f128::EPSILON); + /// + /// assert_eq!(f128::powf(1.0, f128::NAN), 1.0); + /// assert_eq!(f128::powf(f128::NAN, 0.0), 1.0); /// # } /// ``` #[inline] diff --git a/std/src/f16.rs b/std/src/f16.rs index 42cd6e3fe2a5f..5b0903bceabb4 100644 --- a/std/src/f16.rs +++ b/std/src/f16.rs @@ -324,6 +324,20 @@ impl f16 { /// /// The precision of this function is non-deterministic. This means it varies by platform, /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 2.0_f16; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f16::EPSILON); + /// + /// assert_eq!(f16::powi(f16::NAN, 0), 1.0); + /// # } + /// ``` #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] @@ -347,8 +361,10 @@ impl f16 { /// /// let x = 2.0_f16; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// /// assert!(abs_difference <= f16::EPSILON); + /// + /// assert_eq!(f16::powf(1.0, f16::NAN), 1.0); + /// assert_eq!(f16::powf(f16::NAN, 0.0), 1.0); /// # } /// ``` #[inline] diff --git a/std/src/f32.rs b/std/src/f32.rs index 438d77b1626be..f9b6723788ae3 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -306,8 +306,9 @@ impl f32 { /// ``` /// let x = 2.0_f32; /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// /// assert!(abs_difference <= f32::EPSILON); + /// + /// assert_eq!(f32::powi(f32::NAN, 0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -329,8 +330,10 @@ impl f32 { /// ``` /// let x = 2.0_f32; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// /// assert!(abs_difference <= f32::EPSILON); + /// + /// assert_eq!(f32::powf(1.0, f32::NAN), 1.0); + /// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/std/src/f64.rs b/std/src/f64.rs index 9bb4bfbab2a0f..0de55a15d48e8 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -306,8 +306,9 @@ impl f64 { /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f64::EPSILON); /// - /// assert!(abs_difference < 1e-10); + /// assert_eq!(f64::powi(f64::NAN, 0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -329,8 +330,10 @@ impl f64 { /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); + /// assert!(abs_difference <= f64::EPSILON); /// - /// assert!(abs_difference < 1e-10); + /// assert_eq!(f64::powf(1.0, f64::NAN), 1.0); + /// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] From 664a96fa9b3e27ccc6105841026a4fbc2e516290 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 22 Jan 2025 09:30:28 +0100 Subject: [PATCH 383/481] Fix platform-specific doc string for AtomicUsize::from_mut to be platform-independent --- core/src/sync/atomic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 9b56abbd330d1..0061e33f98647 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -2547,7 +2547,7 @@ macro_rules! atomic_int { $int_type, no = [ "**Note:** This function is only available on targets where `", - stringify!($int_type), "` has an alignment of ", $align, " bytes." + stringify!($atomic_type), "` has the same alignment as `", stringify!($int_type), "`." ], }] /// From d09b7f585727e57b6837773d75a487724bfcd470 Mon Sep 17 00:00:00 2001 From: wowinter13 Date: Sat, 25 Jan 2025 23:18:18 +0100 Subject: [PATCH 384/481] [Clippy] Add vec_reserve & vecdeque_reserve diagnostic items --- alloc/src/collections/vec_deque/mod.rs | 1 + alloc/src/vec/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/alloc/src/collections/vec_deque/mod.rs b/alloc/src/collections/vec_deque/mod.rs index 1c33f8f60d824..299c8b8679e3d 100644 --- a/alloc/src/collections/vec_deque/mod.rs +++ b/alloc/src/collections/vec_deque/mod.rs @@ -823,6 +823,7 @@ impl VecDeque { /// assert!(buf.capacity() >= 11); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_reserve")] #[track_caller] pub fn reserve(&mut self, additional: usize) { let new_cap = self.len.checked_add(additional).expect("capacity overflow"); diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 54673ceb1da81..48afcf6e0645b 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -1267,6 +1267,7 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); } From 0270aa2f418c9bea8ea4278f9a7de2cfda728651 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 28 Jan 2025 14:41:15 +0900 Subject: [PATCH 385/481] Update comments and sort target_arch in c_char_definition --- core/src/ffi/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 79d094556c45c..51687a3adcdd4 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -116,7 +116,6 @@ mod c_char_definition { // Section 2.1 "Basic Types" in MSP430 Embedded Application Binary // Interface says "The char type is unsigned by default". // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf - // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). // powerpc/powerpc64: // - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC // Processor Supplement says ANSI C char is unsigned byte @@ -139,8 +138,10 @@ mod c_char_definition { // https://github.com/IBM/s390x-abi/releases/tag/v1.6.1 // - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char." // https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types - // Xtensa: - // - "The char type is unsigned by default for Xtensa processors." + // xtensa: + // Section 2.17.1 "Data Types and Alignment" of Xtensa LX Microprocessor Overview handbook + // says "`char` type is unsigned by default". + // https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf // // On the following operating systems, c_char is signed by default, regardless of architecture. // Darwin (macOS, iOS, etc.): @@ -150,11 +151,12 @@ mod c_char_definition { // Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char // are promoted to int as if from type signed char by default, unless the /J compilation // option is used." - // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types) - // L4RE: + // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types + // L4Re: // The kernel builds with -funsigned-char on all targets (but useserspace follows the // architecture defaults). As we only have a target for userspace apps so there are no - // special cases for L4RE below. + // special cases for L4Re below. + // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 if #[cfg(all( not(windows), not(target_vendor = "apple"), @@ -166,8 +168,8 @@ mod c_char_definition { target_arch = "msp430", target_arch = "powerpc", target_arch = "powerpc64", - target_arch = "riscv64", target_arch = "riscv32", + target_arch = "riscv64", target_arch = "s390x", target_arch = "xtensa", ) From e35b8fea974f22af497c993ca8de3953e0c99a39 Mon Sep 17 00:00:00 2001 From: Caio Date: Tue, 21 Jan 2025 17:54:16 -0300 Subject: [PATCH 386/481] [cfg_match] Document the use of expressions --- core/src/macros/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 5c04e5a40df09..01a3c9d2ada72 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -313,6 +313,17 @@ pub macro cfg_match { /// } /// } /// ``` +/// +/// If desired, it is possible to return expressions through the use of surrounding braces: +/// +/// ``` +/// #![feature(cfg_match)] +/// +/// let _some_string = cfg_match! {{ +/// unix => { "With great power comes great electricity bills" } +/// _ => { "Behind every successful diet is an unwatched pizza" } +/// }}; +/// ``` #[cfg(not(bootstrap))] #[unstable(feature = "cfg_match", issue = "115585")] #[rustc_diagnostic_item = "cfg_match"] From 3b220ff5f74f6409f0247b22629ba1744ac00056 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 28 Jan 2025 19:10:28 +0530 Subject: [PATCH 387/481] uefi: process: Fix args - While working on process env support, I found that args were currently broken. Not sure how I missed it in the PR, but well here is the fix. - Additionally, no point in adding space at the end of args. Signed-off-by: Ayush Singh --- std/src/sys/pal/uefi/process.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/src/sys/pal/uefi/process.rs b/std/src/sys/pal/uefi/process.rs index 1a0754134dfb8..3077a72eac661 100644 --- a/std/src/sys/pal/uefi/process.rs +++ b/std/src/sys/pal/uefi/process.rs @@ -460,7 +460,7 @@ mod uefi_command_internal { helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); let len = args.len(); - let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap(); + let args_size: u32 = (len * crate::mem::size_of::()).try_into().unwrap(); let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { @@ -706,9 +706,10 @@ mod uefi_command_internal { res.push(QUOTE); res.extend(prog.encode_wide()); res.push(QUOTE); - res.push(SPACE); for arg in args { + res.push(SPACE); + // Wrap the argument in quotes to be treat as single arg res.push(QUOTE); for c in arg.encode_wide() { @@ -719,8 +720,6 @@ mod uefi_command_internal { res.push(c); } res.push(QUOTE); - - res.push(SPACE); } res.into_boxed_slice() From da796858f5beccc78e5360ee37f9b847a28e9c1e Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sun, 26 Jan 2025 12:48:33 +0100 Subject: [PATCH 388/481] Test pipes also when not running on Windows and Linux simultaneously Fixes https://github.com/rust-lang/rust/pull/135635#pullrequestreview-2574184488. --- std/src/io/pipe/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/io/pipe/tests.rs b/std/src/io/pipe/tests.rs index c1f3f192ca2d7..f113b157459d3 100644 --- a/std/src/io/pipe/tests.rs +++ b/std/src/io/pipe/tests.rs @@ -1,7 +1,7 @@ use crate::io::{Read, Write, pipe}; #[test] -#[cfg(all(windows, unix, not(miri)))] +#[cfg(all(any(unix, windows), not(miri)))] fn pipe_creation_clone_and_rw() { let (rx, tx) = pipe().unwrap(); From edb0d588f2b61397f9f0185d9f4582cca02a0175 Mon Sep 17 00:00:00 2001 From: edwloef Date: Tue, 21 Jan 2025 22:28:04 +0100 Subject: [PATCH 389/481] optimize slice::ptr_rotate for compile-time-constant small rotates --- core/src/slice/rotate.rs | 327 ++++++++++++++++++++------------------- 1 file changed, 166 insertions(+), 161 deletions(-) diff --git a/core/src/slice/rotate.rs b/core/src/slice/rotate.rs index d8e0acb565c8c..20833dc31aa2b 100644 --- a/core/src/slice/rotate.rs +++ b/core/src/slice/rotate.rs @@ -11,11 +11,18 @@ use crate::{cmp, ptr}; /// /// # Algorithm /// -/// Algorithm 1 is used for small values of `left + right` or for large `T`. The elements are moved -/// into their final positions one at a time starting at `mid - left` and advancing by `right` steps -/// modulo `left + right`, such that only one temporary is needed. Eventually, we arrive back at -/// `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps skipped over -/// elements. For example: +/// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The +/// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and +/// the ones on the buffer are moved back into the hole on the opposite side of where they +/// originated. +/// +/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough. +/// +/// Algorithm 2 is otherwise used for small values of `left + right` or for large `T`. The elements +/// are moved into their final positions one at a time starting at `mid - left` and advancing by +/// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we +/// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps +/// skipped over elements. For example: /// ```text /// left = 10, right = 6 /// the `^` indicates an element in its final place @@ -39,13 +46,7 @@ use crate::{cmp, ptr}; /// `gcd(left + right, right)` value). The end result is that all elements are finalized once and /// only once. /// -/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to -/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove` -/// is applied to the others, and the ones on the buffer are moved back into the hole on the -/// opposite side of where they originated. -/// -/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough. -/// Algorithm 1 can be vectorized by chunking and performing many rounds at once, but there are too +/// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too /// few rounds on average until `left + right` is enormous, and the worst case of a single /// round is always there. Instead, algorithm 3 utilizes repeated swapping of /// `min(left, right)` elements until a smaller rotate problem is left. @@ -65,172 +66,176 @@ pub(super) unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: if T::IS_ZST { return; } - loop { - // N.B. the below algorithms can fail if these cases are not checked - if (right == 0) || (left == 0) { - return; + // N.B. the below algorithms can fail if these cases are not checked + if (right == 0) || (left == 0) { + return; + } + // `T` is not a zero-sized type, so it's okay to divide by its size. + if !cfg!(feature = "optimize_for_size") + && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() + { + // Algorithm 1 + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); + let buf = rawarray.as_mut_ptr() as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` + let dim = unsafe { mid.sub(left).add(right) }; + if left <= right { + // SAFETY: + // + // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` + unsafe { + // 1) + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + // 2) + ptr::copy(mid, mid.sub(left), right); + // 3) + ptr::copy_nonoverlapping(buf, dim, left); + } + } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed + unsafe { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } } - if !cfg!(feature = "optimize_for_size") - && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) - { - // Algorithm 1 - // Microbenchmarks indicate that the average performance for random shifts is better all - // the way until about `left + right == 32`, but the worst case performance breaks even - // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 - // `usize`s, this algorithm also outperforms other algorithms. - // SAFETY: callers must ensure `mid - left` is valid for reading and writing. - let x = unsafe { mid.sub(left) }; - // beginning of first round - // SAFETY: see previous comment. - let mut tmp: T = unsafe { x.read() }; - let mut i = right; - // `gcd` can be found before hand by calculating `gcd(left + right, right)`, - // but it is faster to do one loop which calculates the gcd as a side effect, then - // doing the rest of the chunk - let mut gcd = right; - // benchmarks reveal that it is faster to swap temporaries all the way through instead - // of reading one temporary once, copying backwards, and then writing that temporary at - // the very end. This is possibly due to the fact that swapping or replacing temporaries - // uses only one memory address in the loop instead of needing to manage two. + } else if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) + { + // Algorithm 2 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. + let x = unsafe { mid.sub(left) }; + // beginning of first round + // SAFETY: see previous comment. + let mut tmp: T = unsafe { x.read() }; + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a subtraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract + tmp = unsafe { x.add(i).replace(tmp) }; + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. + unsafe { x.write(tmp) }; + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + for start in 1..gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above + tmp = unsafe { x.add(start).read() }; + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. + i = start + right; loop { - // [long-safety-expl] - // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and - // writing. - // - // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` - // - `i <= left+right-1` is always true - // - if `i < left`, `right` is added so `i < left+right` and on the next - // iteration `left` is removed from `i` so it doesn't go further - // - if `i >= left`, `left` is removed immediately and so it doesn't go further. - // - overflows cannot happen for `i` since the function's safety contract ask for - // `mid+right-1 = x+left+right` to be valid for writing - // - underflows cannot happen because `i` must be bigger or equal to `left` for - // a subtraction of `left` to happen. - // - // So `x+i` is valid for reading and writing if the caller respected the contract + // SAFETY: see [long-safety-expl] and [safety-expl-addition] tmp = unsafe { x.add(i).replace(tmp) }; - // instead of incrementing `i` and then checking if it is outside the bounds, we - // check if `i` will go outside the bounds on the next increment. This prevents - // any wrapping of pointers or `usize`. if i >= left { i -= left; - if i == 0 { - // end of first round - // SAFETY: tmp has been read from a valid source and x is valid for writing - // according to the caller. - unsafe { x.write(tmp) }; + if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + unsafe { x.add(start).write(tmp) }; break; } - // this conditional must be here if `left + right >= 15` - if i < gcd { - gcd = i; - } } else { i += right; } } - // finish the chunk with more rounds - for start in 1..gcd { - // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for - // reading and writing as per the function's safety contract, see [long-safety-expl] - // above - tmp = unsafe { x.add(start).read() }; - // [safety-expl-addition] - // - // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the - // greatest common divisor of `(left+right, right)` means that `left = right` so - // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing - // according to the function's safety contract. - i = start + right; + } + } else { + loop { + if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. loop { - // SAFETY: see [long-safety-expl] and [safety-expl-addition] - tmp = unsafe { x.add(i).replace(tmp) }; - if i >= left { - i -= left; - if i == start { - // SAFETY: see [long-safety-expl] and [safety-expl-addition] - unsafe { x.add(start).write(tmp) }; - break; - } - } else { - i += right; + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Subtracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + } + left -= right; + if left < right { + break; } - } - } - return; - // `T` is not a zero-sized type, so it's okay to divide by its size. - } else if !cfg!(feature = "optimize_for_size") - && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() - { - // Algorithm 2 - // The `[T; 0]` here is to ensure this is appropriately aligned for T - let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); - let buf = rawarray.as_mut_ptr() as *mut T; - // SAFETY: `mid-left <= mid-left+right < mid+right` - let dim = unsafe { mid.sub(left).add(right) }; - if left <= right { - // SAFETY: - // - // 1) The `else if` condition about the sizes ensures `[mid-left; left]` will fit in - // `buf` without overflow and `buf` was created just above and so cannot be - // overlapped with any value of `[mid-left; left]` - // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care - // about overlaps here. - // 3) The `if` condition about `left <= right` ensures writing `left` elements to - // `dim = mid-left+right` is valid because: - // - `buf` is valid and `left` elements were written in it in 1) - // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` - unsafe { - // 1) - ptr::copy_nonoverlapping(mid.sub(left), buf, left); - // 2) - ptr::copy(mid, mid.sub(left), right); - // 3) - ptr::copy_nonoverlapping(buf, dim, left); } } else { - // SAFETY: same reasoning as above but with `left` and `right` reversed - unsafe { - ptr::copy_nonoverlapping(mid, buf, right); - ptr::copy(mid.sub(left), dim, left); - ptr::copy_nonoverlapping(buf, mid.sub(left), right); - } - } - return; - } else if left >= right { - // Algorithm 3 - // There is an alternate way of swapping that involves finding where the last swap - // of this algorithm would be, and swapping using that last chunk instead of swapping - // adjacent chunks like this algorithm is doing, but this way is still faster. - loop { - // SAFETY: - // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing - // Subtracting `right` from `mid` each turn is counterbalanced by the addition and - // check after it. - unsafe { - ptr::swap_nonoverlapping(mid.sub(right), mid, right); - mid = mid.sub(right); - } - left -= right; - if left < right { - break; + // Algorithm 3, `left < right` + loop { + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check + // after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); + } + right -= left; + if right < left { + break; + } } } - } else { - // Algorithm 3, `left < right` - loop { - // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because - // `left < right` so `mid+left < mid+right`. - // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check - // after it. - unsafe { - ptr::swap_nonoverlapping(mid.sub(left), mid, left); - mid = mid.add(left); - } - right -= left; - if right < left { - break; - } + + if (right == 0) || (left == 0) { + return; } } } From 08559757a2ec5b0811b955245107c900a72711bb Mon Sep 17 00:00:00 2001 From: edwloef Date: Mon, 27 Jan 2025 16:35:15 +0100 Subject: [PATCH 390/481] split slice::ptr_rotate into three separate algorithms, to hopefully help inlining --- core/src/slice/rotate.rs | 369 +++++++++++++++++++++------------------ 1 file changed, 195 insertions(+), 174 deletions(-) diff --git a/core/src/slice/rotate.rs b/core/src/slice/rotate.rs index 20833dc31aa2b..3e88978b78105 100644 --- a/core/src/slice/rotate.rs +++ b/core/src/slice/rotate.rs @@ -1,6 +1,8 @@ use crate::mem::{self, MaybeUninit, SizedTypeProperties}; use crate::{cmp, ptr}; +type BufType = [usize; 32]; + /// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first /// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the /// right. @@ -8,17 +10,76 @@ use crate::{cmp, ptr}; /// # Safety /// /// The specified range must be valid for reading and writing. -/// -/// # Algorithm -/// +pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { + if T::IS_ZST { + return; + } + // abort early if the rotate is a no-op + if (left == 0) || (right == 0) { + return; + } + // `T` is not a zero-sized type, so it's okay to divide by its size. + if !cfg!(feature = "optimize_for_size") + && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_memmove(left, mid, right) }; + } else if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_gcd(left, mid, right) } + } else { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_swap(left, mid, right) } + } +} + /// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The /// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and /// the ones on the buffer are moved back into the hole on the opposite side of where they /// originated. /// -/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough. +/// # Safety /// -/// Algorithm 2 is otherwise used for small values of `left + right` or for large `T`. The elements +/// The specified range must be valid for reading and writing. +unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); + let buf = rawarray.as_mut_ptr() as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` + let dim = unsafe { mid.sub(left).add(right) }; + if left <= right { + // SAFETY: + // + // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` + unsafe { + // 1) + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + // 2) + ptr::copy(mid, mid.sub(left), right); + // 3) + ptr::copy_nonoverlapping(buf, dim, left); + } + } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed + unsafe { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } + } +} + +/// Algorithm 2 is used for small values of `left + right` or for large `T`. The elements /// are moved into their final positions one at a time starting at `mid - left` and advancing by /// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we /// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps @@ -48,195 +109,155 @@ use crate::{cmp, ptr}; /// /// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too /// few rounds on average until `left + right` is enormous, and the worst case of a single -/// round is always there. Instead, algorithm 3 utilizes repeated swapping of -/// `min(left, right)` elements until a smaller rotate problem is left. +/// round is always there. /// -/// ```text -/// left = 11, right = 4 -/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] -/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left -/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 -/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these -/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 -/// we cannot swap any more, but a smaller rotation problem is left to solve -/// ``` -/// when `left < right` the swapping happens from the left instead. -pub(super) unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) { - type BufType = [usize; 32]; - if T::IS_ZST { - return; - } - // N.B. the below algorithms can fail if these cases are not checked - if (right == 0) || (left == 0) { - return; - } - // `T` is not a zero-sized type, so it's okay to divide by its size. - if !cfg!(feature = "optimize_for_size") - && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() - { - // Algorithm 1 - // The `[T; 0]` here is to ensure this is appropriately aligned for T - let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); - let buf = rawarray.as_mut_ptr() as *mut T; - // SAFETY: `mid-left <= mid-left+right < mid+right` - let dim = unsafe { mid.sub(left).add(right) }; - if left <= right { - // SAFETY: - // - // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in - // `buf` without overflow and `buf` was created just above and so cannot be - // overlapped with any value of `[mid-left; left]` - // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care - // about overlaps here. - // 3) The `if` condition about `left <= right` ensures writing `left` elements to - // `dim = mid-left+right` is valid because: - // - `buf` is valid and `left` elements were written in it in 1) - // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` - unsafe { - // 1) - ptr::copy_nonoverlapping(mid.sub(left), buf, left); - // 2) - ptr::copy(mid, mid.sub(left), right); - // 3) - ptr::copy_nonoverlapping(buf, dim, left); +/// # Safety +/// +/// The specified range must be valid for reading and writing. +unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { + // Algorithm 2 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. + let x = unsafe { mid.sub(left) }; + // beginning of first round + // SAFETY: see previous comment. + let mut tmp: T = unsafe { x.read() }; + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a subtraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract + tmp = unsafe { x.add(i).replace(tmp) }; + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. + unsafe { x.write(tmp) }; + break; } - } else { - // SAFETY: same reasoning as above but with `left` and `right` reversed - unsafe { - ptr::copy_nonoverlapping(mid, buf, right); - ptr::copy(mid.sub(left), dim, left); - ptr::copy_nonoverlapping(buf, mid.sub(left), right); + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; } + } else { + i += right; } - } else if !cfg!(feature = "optimize_for_size") - && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) - { - // Algorithm 2 - // Microbenchmarks indicate that the average performance for random shifts is better all - // the way until about `left + right == 32`, but the worst case performance breaks even - // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 - // `usize`s, this algorithm also outperforms other algorithms. - // SAFETY: callers must ensure `mid - left` is valid for reading and writing. - let x = unsafe { mid.sub(left) }; - // beginning of first round - // SAFETY: see previous comment. - let mut tmp: T = unsafe { x.read() }; - let mut i = right; - // `gcd` can be found before hand by calculating `gcd(left + right, right)`, - // but it is faster to do one loop which calculates the gcd as a side effect, then - // doing the rest of the chunk - let mut gcd = right; - // benchmarks reveal that it is faster to swap temporaries all the way through instead - // of reading one temporary once, copying backwards, and then writing that temporary at - // the very end. This is possibly due to the fact that swapping or replacing temporaries - // uses only one memory address in the loop instead of needing to manage two. + } + // finish the chunk with more rounds + for start in 1..gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above + tmp = unsafe { x.add(start).read() }; + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. + i = start + right; loop { - // [long-safety-expl] - // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and - // writing. - // - // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` - // - `i <= left+right-1` is always true - // - if `i < left`, `right` is added so `i < left+right` and on the next - // iteration `left` is removed from `i` so it doesn't go further - // - if `i >= left`, `left` is removed immediately and so it doesn't go further. - // - overflows cannot happen for `i` since the function's safety contract ask for - // `mid+right-1 = x+left+right` to be valid for writing - // - underflows cannot happen because `i` must be bigger or equal to `left` for - // a subtraction of `left` to happen. - // - // So `x+i` is valid for reading and writing if the caller respected the contract + // SAFETY: see [long-safety-expl] and [safety-expl-addition] tmp = unsafe { x.add(i).replace(tmp) }; - // instead of incrementing `i` and then checking if it is outside the bounds, we - // check if `i` will go outside the bounds on the next increment. This prevents - // any wrapping of pointers or `usize`. if i >= left { i -= left; - if i == 0 { - // end of first round - // SAFETY: tmp has been read from a valid source and x is valid for writing - // according to the caller. - unsafe { x.write(tmp) }; + if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + unsafe { x.add(start).write(tmp) }; break; } - // this conditional must be here if `left + right >= 15` - if i < gcd { - gcd = i; - } } else { i += right; } } - // finish the chunk with more rounds - for start in 1..gcd { - // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for - // reading and writing as per the function's safety contract, see [long-safety-expl] - // above - tmp = unsafe { x.add(start).read() }; - // [safety-expl-addition] - // - // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the - // greatest common divisor of `(left+right, right)` means that `left = right` so - // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing - // according to the function's safety contract. - i = start + right; + } +} + +/// Algorithm 3 utilizes repeated swapping of `min(left, right)` elements. +/// +/// /// +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) { + loop { + if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. loop { - // SAFETY: see [long-safety-expl] and [safety-expl-addition] - tmp = unsafe { x.add(i).replace(tmp) }; - if i >= left { - i -= left; - if i == start { - // SAFETY: see [long-safety-expl] and [safety-expl-addition] - unsafe { x.add(start).write(tmp) }; - break; - } - } else { - i += right; + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Subtracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + } + left -= right; + if left < right { + break; } } - } - } else { - loop { - if left >= right { - // Algorithm 3 - // There is an alternate way of swapping that involves finding where the last swap - // of this algorithm would be, and swapping using that last chunk instead of swapping - // adjacent chunks like this algorithm is doing, but this way is still faster. - loop { - // SAFETY: - // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing - // Subtracting `right` from `mid` each turn is counterbalanced by the addition and - // check after it. - unsafe { - ptr::swap_nonoverlapping(mid.sub(right), mid, right); - mid = mid.sub(right); - } - left -= right; - if left < right { - break; - } + } else { + // Algorithm 3, `left < right` + loop { + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check + // after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); } - } else { - // Algorithm 3, `left < right` - loop { - // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because - // `left < right` so `mid+left < mid+right`. - // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check - // after it. - unsafe { - ptr::swap_nonoverlapping(mid.sub(left), mid, left); - mid = mid.add(left); - } - right -= left; - if right < left { - break; - } + right -= left; + if right < left { + break; } } - - if (right == 0) || (left == 0) { - return; - } + } + if (right == 0) || (left == 0) { + return; } } } From b61e678190e332b8661c6913e58fd651a7ba54a6 Mon Sep 17 00:00:00 2001 From: edwloef Date: Tue, 28 Jan 2025 12:26:32 +0100 Subject: [PATCH 391/481] add inline attribute and codegen test --- core/src/slice/rotate.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/slice/rotate.rs b/core/src/slice/rotate.rs index 3e88978b78105..5d5ee4c7b6240 100644 --- a/core/src/slice/rotate.rs +++ b/core/src/slice/rotate.rs @@ -10,6 +10,7 @@ type BufType = [usize; 32]; /// # Safety /// /// The specified range must be valid for reading and writing. +#[inline] pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { if T::IS_ZST { return; @@ -43,6 +44,7 @@ pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { /// # Safety /// /// The specified range must be valid for reading and writing. +#[inline] unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { // The `[T; 0]` here is to ensure this is appropriately aligned for T let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); @@ -114,6 +116,7 @@ unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { /// # Safety /// /// The specified range must be valid for reading and writing. +#[inline] unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { // Algorithm 2 // Microbenchmarks indicate that the average performance for random shifts is better all @@ -218,6 +221,7 @@ unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { /// # Safety /// /// The specified range must be valid for reading and writing. +#[inline] unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) { loop { if left >= right { From 062a33e0f61beb702add94de72adcacd0088672c Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Tue, 28 Jan 2025 21:42:51 +0100 Subject: [PATCH 392/481] btree/node.rs: remove incorrect comment from pop_internal_level docs --- alloc/src/collections/btree/node.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/alloc/src/collections/btree/node.rs b/alloc/src/collections/btree/node.rs index 6815ac1c19305..2525f5856cd21 100644 --- a/alloc/src/collections/btree/node.rs +++ b/alloc/src/collections/btree/node.rs @@ -600,9 +600,6 @@ impl NodeRef { /// no cleanup is done on any of the keys, values and other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. /// - /// Requires exclusive access to the `NodeRef` object but not to the root node; - /// it will not invalidate other handles or references to the root node. - /// /// Panics if there is no internal level, i.e., if the root node is a leaf. pub(super) fn pop_internal_level(&mut self, alloc: A) { assert!(self.height > 0); From 3f30b614a673bfa9fb744f2823304ed8860cd2c2 Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Wed, 29 Jan 2025 08:35:29 +0100 Subject: [PATCH 393/481] btree/node.rs: pop_internal_level: does not invalidate other handles --- alloc/src/collections/btree/node.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alloc/src/collections/btree/node.rs b/alloc/src/collections/btree/node.rs index 2525f5856cd21..37f784a322cad 100644 --- a/alloc/src/collections/btree/node.rs +++ b/alloc/src/collections/btree/node.rs @@ -600,6 +600,9 @@ impl NodeRef { /// no cleanup is done on any of the keys, values and other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. /// + /// Does not invalidate any handles or references pointing into the subtree + /// rooted at the first child of `self`. + /// /// Panics if there is no internal level, i.e., if the root node is a leaf. pub(super) fn pop_internal_level(&mut self, alloc: A) { assert!(self.height > 0); From 1b992488736250c365aff94633bccdd82b29943b Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 29 Jan 2025 19:47:59 +0100 Subject: [PATCH 394/481] Cleanup docs for Allocator --- core/src/alloc/mod.rs | 58 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/core/src/alloc/mod.rs b/core/src/alloc/mod.rs index aa841db045ce7..dcab6136ae8a1 100644 --- a/core/src/alloc/mod.rs +++ b/core/src/alloc/mod.rs @@ -49,26 +49,26 @@ impl fmt::Display for AllocError { /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// data described via [`Layout`][]. /// -/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having -/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the +/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers. +/// An allocator for `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the /// allocated memory. /// -/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying -/// allocator does not support this (like jemalloc) or return a null pointer (such as -/// `libc::malloc`), this must be caught by the implementation. +/// In contrast to [`GlobalAlloc`][], `Allocator` allows zero-sized allocations. If an underlying +/// allocator does not support this (like jemalloc) or responds by returning a null pointer +/// (such as `libc::malloc`), this must be caught by the implementation. /// /// ### Currently allocated memory /// -/// Some of the methods require that a memory block be *currently allocated* via an allocator. This -/// means that: +/// Some of the methods require that a memory block is *currently allocated* by an allocator. +/// This means that: +/// * the starting address for that memory block was previously +/// returned by [`allocate`], [`grow`], or [`shrink`], and +/// * the memory block has not subsequently been deallocated. /// -/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or -/// [`shrink`], and -/// -/// * the memory block has not been subsequently deallocated, where blocks are either deallocated -/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or -/// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer -/// remains valid. +/// A memory block is deallocated by a call to [`deallocate`], +/// or by a call to [`grow`] or [`shrink`] that returns `Ok`. +/// A call to `grow` or `shrink` that returns `Err`, +/// does not deallocate the memory block passed to it. /// /// [`allocate`]: Allocator::allocate /// [`grow`]: Allocator::grow @@ -77,32 +77,28 @@ impl fmt::Display for AllocError { /// /// ### Memory fitting /// -/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to -/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the +/// Some of the methods require that a `layout` *fit* a memory block or vice versa. This means that the /// following conditions must hold: -/// -/// * The block must be allocated with the same alignment as [`layout.align()`], and -/// -/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: -/// - `min` is the size of the layout most recently used to allocate the block, and -/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. +/// * the memory block must be *currently allocated* with alignment of [`layout.align()`], and +/// * [`layout.size()`] must fall in the range `min ..= max`, where: +/// - `min` is the size of the layout used to allocate the block, and +/// - `max` is the actual size returned from [`allocate`], [`grow`], or [`shrink`]. /// /// [`layout.align()`]: Layout::align /// [`layout.size()`]: Layout::size /// /// # Safety /// -/// * Memory blocks returned from an allocator that are [*currently allocated*] must point to -/// valid memory and retain their validity while they are [*currently allocated*] and the shorter -/// of: -/// - the borrow-checker lifetime of the allocator type itself. -/// - as long as at least one of the instance and all of its clones has not been dropped. +/// Memory blocks that are [*currently allocated*] by an allocator, +/// must point to valid memory, and retain their validity while until either: +/// - the memory block is deallocated, or +/// - the allocator is dropped. /// -/// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this -/// allocator. A copied or cloned allocator must behave like the same allocator, and +/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it +/// A copied or cloned allocator must behave like the original allocator. /// -/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other -/// method of the allocator. +/// A memory block which is [*currently allocated*] may be passed to +/// any method of the allocator that accepts such an argument. /// /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] From 0f0c4ac53a8cb7115efb316848e83ad10f978f3e Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 27 Dec 2024 15:02:34 +0100 Subject: [PATCH 395/481] Implement `int_from_ascii` (#134821) Provides unstable `T::from_ascii()` and `T::from_ascii_radix()` for integer types `T`, as drafted in tracking issue #134821. To deduplicate documentation without additional macros, implementations of `isize` and `usize` no longer delegate to equivalent integer types. After #132870 they are inlined anyway. --- core/src/num/mod.rs | 220 ++++++++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 89 deletions(-) diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 6c1b568e231d0..55f4ccd958e77 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -1322,20 +1322,6 @@ pub enum FpCategory { Normal, } -macro_rules! from_str_radix_int_impl { - ($($t:ty)*) => {$( - #[stable(feature = "rust1", since = "1.0.0")] - impl FromStr for $t { - type Err = ParseIntError; - #[inline] - fn from_str(src: &str) -> Result { - <$t>::from_str_radix(src, 10) - } - } - )*} -} -from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } - /// Determines if a string of text of that length of that radix could be guaranteed to be /// stored in the given type T. /// Note that if the radix is known to the compiler, it is just the check of digits.len that @@ -1351,18 +1337,58 @@ pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) #[cfg_attr(feature = "panic_immediate_abort", inline)] #[cold] #[track_caller] -const fn from_str_radix_panic(radix: u32) -> ! { +const fn from_ascii_radix_panic(radix: u32) -> ! { const_panic!( - "from_str_radix_int: must lie in the range `[2, 36]`", - "from_str_radix_int: must lie in the range `[2, 36]` - found {radix}", + "from_ascii_radix: radix must lie in the range `[2, 36]`", + "from_ascii_radix: radix must lie in the range `[2, 36]` - found {radix}", radix: u32 = radix, ) } -macro_rules! from_str_radix { +macro_rules! from_str_int_impl { ($signedness:ident $($int_ty:ty)+) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl FromStr for $int_ty { + type Err = ParseIntError; + + /// Parses an integer from a string slice with decimal digits. + /// + /// The characters are expected to be an optional + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + " `+` or `-` " + } + if unsigned { + " `+` " + } + }] + /// sign followed by only digits. Leading and trailing non-digit characters (including + /// whitespace) represent an error. Underscores (which are accepted in Rust literals) + /// also represent an error. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// use std::str::FromStr; + /// + #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str(\"+10\"), Ok(10));")] + /// ``` + /// Trailing space returns error: + /// ``` + /// # use std::str::FromStr; + /// # + #[doc = concat!("assert!(", stringify!($int_ty), "::from_str(\"1 \").is_err());")] + /// ``` + #[inline] + fn from_str(src: &str) -> Result<$int_ty, ParseIntError> { + <$int_ty>::from_str_radix(src, 10) + } + } + impl $int_ty { - /// Converts a string slice in a given base to an integer. + /// Parses an integer from a string slice with digits in a given base. /// /// The string is expected to be an optional #[doc = sign_dependent_expr!{ @@ -1375,7 +1401,7 @@ macro_rules! from_str_radix { } }] /// sign followed by only digits. Leading and trailing non-digit characters (including - /// whitespace) represent an error. Underscores (which are accepted in rust literals) + /// whitespace) represent an error. Underscores (which are accepted in Rust literals) /// also represent an error. /// /// Digits are a subset of these characters, depending on `radix`: @@ -1401,11 +1427,92 @@ macro_rules! from_str_radix { #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] #[inline] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> { + <$int_ty>::from_ascii_radix(src.as_bytes(), radix) + } + + /// Parses an integer from an ASCII-byte slice with decimal digits. + /// + /// The characters are expected to be an optional + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + " `+` or `-` " + } + if unsigned { + " `+` " + } + }] + /// sign followed by only digits. Leading and trailing non-digit characters (including + /// whitespace) represent an error. Underscores (which are accepted in Rust literals) + /// also represent an error. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// #![feature(int_from_ascii)] + /// + #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_ascii(b\"+10\"), Ok(10));")] + /// ``` + /// Trailing space returns error: + /// ``` + /// # #![feature(int_from_ascii)] + /// # + #[doc = concat!("assert!(", stringify!($int_ty), "::from_ascii(b\"1 \").is_err());")] + /// ``` + #[unstable(feature = "int_from_ascii", issue = "134821")] + #[inline] + pub const fn from_ascii(src: &[u8]) -> Result<$int_ty, ParseIntError> { + <$int_ty>::from_ascii_radix(src, 10) + } + + /// Parses an integer from an ASCII-byte slice with digits in a given base. + /// + /// The characters are expected to be an optional + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + " `+` or `-` " + } + if unsigned { + " `+` " + } + }] + /// sign followed by only digits. Leading and trailing non-digit characters (including + /// whitespace) represent an error. Underscores (which are accepted in Rust literals) + /// also represent an error. + /// + /// Digits are a subset of these characters, depending on `radix`: + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// #![feature(int_from_ascii)] + /// + #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_ascii_radix(b\"A\", 16), Ok(10));")] + /// ``` + /// Trailing space returns error: + /// ``` + /// # #![feature(int_from_ascii)] + /// # + #[doc = concat!("assert!(", stringify!($int_ty), "::from_ascii_radix(b\"1 \", 10).is_err());")] + /// ``` + #[unstable(feature = "int_from_ascii", issue = "134821")] + #[inline] + pub const fn from_ascii_radix(src: &[u8], radix: u32) -> Result<$int_ty, ParseIntError> { use self::IntErrorKind::*; use self::ParseIntError as PIE; if 2 > radix || radix > 36 { - from_str_radix_panic(radix); + from_ascii_radix_panic(radix); } if src.is_empty() { @@ -1415,12 +1522,6 @@ macro_rules! from_str_radix { #[allow(unused_comparisons)] let is_signed_ty = 0 > <$int_ty>::MIN; - // all valid digits are ascii, so we will just iterate over the utf8 bytes - // and cast them to chars. .to_digit() will safely return None for anything - // other than a valid ascii digit for the given radix, including the first-byte - // of multi-byte sequences - let src = src.as_bytes(); - let (is_positive, mut digits) = match src { [b'+' | b'-'] => { return Err(PIE { kind: InvalidDigit }); @@ -1496,67 +1597,8 @@ macro_rules! from_str_radix { Ok(result) } } - )+} -} - -from_str_radix! { unsigned u8 u16 u32 u64 u128 } -from_str_radix! { signed i8 i16 i32 i64 i128 } - -// Re-use the relevant implementation of from_str_radix for isize and usize to avoid outputting two -// identical functions. -macro_rules! from_str_radix_size_impl { - ($($signedness:ident $t:ident $size:ty),*) => {$( - impl $size { - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional - #[doc = sign_dependent_expr!{ - $signedness ? - if signed { - " `+` or `-` " - } - if unsigned { - " `+` " - } - }] - /// sign followed by only digits. Leading and trailing non-digit characters (including - /// whitespace) represent an error. Underscores (which are accepted in rust literals) - /// also represent an error. - /// - /// Digits are a subset of these characters, depending on `radix`: - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36. - /// - /// # Examples - /// - /// Basic usage: - /// ``` - #[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")] - /// ``` - /// Trailing space returns error: - /// ``` - #[doc = concat!("assert!(", stringify!($size), "::from_str_radix(\"1 \", 10).is_err());")] - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] - #[inline] - pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> { - match <$t>::from_str_radix(src, radix) { - Ok(x) => Ok(x as $size), - Err(e) => Err(e), - } - } - })*} + )*} } -#[cfg(target_pointer_width = "16")] -from_str_radix_size_impl! { signed i16 isize, unsigned u16 usize } -#[cfg(target_pointer_width = "32")] -from_str_radix_size_impl! { signed i32 isize, unsigned u32 usize } -#[cfg(target_pointer_width = "64")] -from_str_radix_size_impl! { signed i64 isize, unsigned u64 usize } +from_str_int_impl! { signed isize i8 i16 i32 i64 i128 } +from_str_int_impl! { unsigned usize u8 u16 u32 u64 u128 } From 85fcd2828a7f4dfcc7d8b08489d0171c2031a878 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 14 Jan 2025 11:40:22 +0530 Subject: [PATCH 396/481] uefi: Implement path UEFI paths can be of 4 types: 1. Absolute Shell Path: Uses shell mappings 2. Absolute Device Path: this is what we want 3: Relative root: path relative to the current root. 4: Relative Absolute shell path can be identified with `:` and Absolute Device path can be identified with `/`. Relative root path will start with `\`. The algorithm is mostly taken from edk2 UEFI shell implementation and is somewhat simple. Check for the path type in order. For Absolute Shell path, use `EFI_SHELL->GetDevicePathFromMap` to get a BorrowedDevicePath for the volume. For Relative paths, we use the current working directory to construct the new path. BorrowedDevicePath abstraction is needed to interact with `EFI_SHELL->GetDevicePathFromMap` which returns a Device Path Protocol with the lifetime of UEFI shell. Absolute Shell paths cannot exist if UEFI shell is missing. Signed-off-by: Ayush Singh --- std/src/sys/pal/uefi/helpers.rs | 50 ++++++++++++++- std/src/sys/path/mod.rs | 8 +-- std/src/sys/path/uefi.rs | 105 ++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 std/src/sys/path/uefi.rs diff --git a/std/src/sys/pal/uefi/helpers.rs b/std/src/sys/pal/uefi/helpers.rs index 7504a0f7ad7f5..dccc137d6f561 100644 --- a/std/src/sys/pal/uefi/helpers.rs +++ b/std/src/sys/pal/uefi/helpers.rs @@ -14,10 +14,12 @@ use r_efi::protocols::{device_path, device_path_to_text, shell}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; +use crate::marker::PhantomData; use crate::mem::{MaybeUninit, size_of}; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::os::uefi::{self}; +use crate::path::Path; use crate::ptr::NonNull; use crate::slice; use crate::sync::atomic::{AtomicPtr, Ordering}; @@ -278,6 +280,10 @@ impl OwnedDevicePath { pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol { self.0.as_ptr() } + + pub(crate) const fn borrow<'a>(&'a self) -> BorrowedDevicePath<'a> { + BorrowedDevicePath::new(self.0) + } } impl Drop for OwnedDevicePath { @@ -293,13 +299,37 @@ impl Drop for OwnedDevicePath { impl crate::fmt::Debug for OwnedDevicePath { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - match device_path_to_text(self.0) { + match self.borrow().to_text() { Ok(p) => p.fmt(f), Err(_) => f.debug_struct("OwnedDevicePath").finish_non_exhaustive(), } } } +pub(crate) struct BorrowedDevicePath<'a> { + protocol: NonNull, + phantom: PhantomData<&'a r_efi::protocols::device_path::Protocol>, +} + +impl<'a> BorrowedDevicePath<'a> { + pub(crate) const fn new(protocol: NonNull) -> Self { + Self { protocol, phantom: PhantomData } + } + + pub(crate) fn to_text(&self) -> io::Result { + device_path_to_text(self.protocol) + } +} + +impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + match self.to_text() { + Ok(p) => p.fmt(f), + Err(_) => f.debug_struct("BorrowedDevicePath").finish_non_exhaustive(), + } + } +} + pub(crate) struct OwnedProtocol { guid: r_efi::efi::Guid, handle: NonNull, @@ -452,3 +482,21 @@ pub(crate) fn open_shell() -> Option> { None } + +/// Get device path protocol associated with shell mapping. +/// +/// returns None in case no such mapping is exists +pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result> { + let shell = + open_shell().ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell not found"))?; + let mut path = os_string_to_raw(map.as_os_str()) + .ok_or(io::const_error!(io::ErrorKind::InvalidFilename, "Invalid UEFI shell mapping"))?; + + // The Device Path Protocol pointer returned by UEFI shell is owned by the shell and is not + // freed throughout it's lifetime. So it has a 'static lifetime. + let protocol = unsafe { ((*shell.as_ptr()).get_device_path_from_map)(path.as_mut_ptr()) }; + let protocol = NonNull::new(protocol) + .ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell mapping not found"))?; + + Ok(BorrowedDevicePath::new(protocol)) +} diff --git a/std/src/sys/path/mod.rs b/std/src/sys/path/mod.rs index 24a94ec782824..1fa4e80d6780c 100644 --- a/std/src/sys/path/mod.rs +++ b/std/src/sys/path/mod.rs @@ -5,12 +5,12 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::*; - } else if #[cfg(any( - target_os = "uefi", - target_os = "solid_asp3", - ))] { + } else if #[cfg(target_os = "solid_asp3")] { mod unsupported_backslash; pub use unsupported_backslash::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; } else { mod unix; pub use unix::*; diff --git a/std/src/sys/path/uefi.rs b/std/src/sys/path/uefi.rs new file mode 100644 index 0000000000000..a3f4a3bfe1b67 --- /dev/null +++ b/std/src/sys/path/uefi.rs @@ -0,0 +1,105 @@ +#![forbid(unsafe_op_in_unsafe_fn)] +use crate::ffi::OsStr; +use crate::io; +use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::{helpers, unsupported_err}; + +const FORWARD_SLASH: u8 = b'/'; +const COLON: u8 = b':'; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; + +/// UEFI paths can be of 4 types: +/// +/// 1. Absolute Shell Path: Uses shell mappings (eg: `FS0:`). Does not exist if UEFI shell not present. +/// It can be identified with `:`. +/// Eg: FS0:\abc\run.efi +/// +/// 2. Absolute Device Path: this is what we want +/// It can be identified with `/`. +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi +/// +/// 3: Relative root: path relative to the current volume. +/// It will start with `\`. +/// Eg: \abc\run.efi +/// +/// 4: Relative +/// Eg: run.efi +/// +/// The algorithm is mostly taken from edk2 UEFI shell implementation and is +/// somewhat simple. Check for the path type in order. +/// +/// The volume mapping in Absolute Shell Path (not the rest of the path) can be converted to Device +/// Path Protocol using `EFI_SHELL->GetDevicePathFromMap`. The rest of the path (Relative root +/// path), can just be appended to the remaining path. +/// +/// For Relative root, we get the current volume (either in Shell Mapping, or Device Path Protocol +/// form) and join it with the relative root path. We then recurse the function to resolve the Shell +/// Mapping if present. +/// +/// For Relative paths, we use the current working directory to construct +/// the new path and recurse the function to resolve the Shell mapping if present. +/// +/// Finally, at the end, we get the 2nd form, i.e. Absolute Device Path, which can be used in the +/// normal UEFI APIs such as file, process, etc. +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi +pub(crate) fn absolute(path: &Path) -> io::Result { + // Absolute Shell Path + if path.as_os_str().as_encoded_bytes().contains(&COLON) { + let mut path_components = path.components(); + // Since path is not empty, it has at least one Component + let prefix = path_components.next().unwrap(); + + let dev_path = helpers::get_device_path_from_map(prefix.as_ref())?; + let mut dev_path_text = dev_path.to_text().map_err(|_| unsupported_err())?; + + // UEFI Shell does not seem to end device path with `/` + if *dev_path_text.as_encoded_bytes().last().unwrap() != FORWARD_SLASH { + dev_path_text.push("/"); + } + + let mut ans = PathBuf::from(dev_path_text); + ans.push(path_components); + + return Ok(ans); + } + + // Absolute Device Path + if path.as_os_str().as_encoded_bytes().contains(&FORWARD_SLASH) { + return Ok(path.to_path_buf()); + } + + // cur_dir() always returns something + let cur_dir = crate::env::current_dir().unwrap(); + let mut path_components = path.components(); + + // Relative Root + if path_components.next().unwrap() == crate::path::Component::RootDir { + let mut ans = PathBuf::new(); + ans.push(cur_dir.components().next().unwrap()); + ans.push(path_components); + return absolute(&ans); + } + + absolute(&cur_dir.join(path)) +} + +pub(crate) fn is_absolute(path: &Path) -> bool { + let temp = path.as_os_str().as_encoded_bytes(); + temp.contains(&COLON) || temp.contains(&FORWARD_SLASH) +} From 2b47ea0715559899d21527a3a5e874634d282677 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 22 Jan 2025 00:20:54 +0100 Subject: [PATCH 397/481] Add `AsyncFn*` to core prelude --- core/src/prelude/common.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/prelude/common.rs b/core/src/prelude/common.rs index e38ef1e147c76..8b116cecb5295 100644 --- a/core/src/prelude/common.rs +++ b/core/src/prelude/common.rs @@ -12,6 +12,9 @@ pub use crate::marker::{Copy, Send, Sized, Sync, Unpin}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; +#[stable(feature = "async_closure", since = "1.85.0")] +#[doc(no_inline)] +pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; // Re-exported functions #[stable(feature = "core_prelude", since = "1.4.0")] From 67ca7a1887cc4a573a5715780d54752fb15e0b73 Mon Sep 17 00:00:00 2001 From: Sky Date: Wed, 29 Jan 2025 20:23:59 -0500 Subject: [PATCH 398/481] Remove minor future footgun in `impl Debug for MaybeUninit` No longer breaks if `MaybeUninit` moves modules (technically it could break if `MaybeUninit` were renamed but realistically that will never happen) --- core/src/mem/maybe_uninit.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/mem/maybe_uninit.rs b/core/src/mem/maybe_uninit.rs index ac5307a671d20..0d8c3ef906bf0 100644 --- a/core/src/mem/maybe_uninit.rs +++ b/core/src/mem/maybe_uninit.rs @@ -276,10 +276,9 @@ impl Clone for MaybeUninit { impl fmt::Debug for MaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>"). - // This needs to be adjusted if `MaybeUninit` moves modules. let full_name = type_name::(); - let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1; - f.pad(short_name) + let prefix_len = full_name.find("MaybeUninit").unwrap(); + f.pad(&full_name[prefix_len..]) } } From 2336ccdfa9058ad36875ea2aa53dde0e06fa1eae Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 30 Jan 2025 11:42:19 +0100 Subject: [PATCH 399/481] Improve documentation for file locking Add notes to each method stating that locks get dropped on close. Clarify the return values of the try methods: they're only defined if the lock is held via a *different* file handle/descriptor. That goes along with the documentation that calling them while holding a lock via the *same* file handle/descriptor may deadlock. Document the behavior of unlock if no lock is held. --- std/src/fs.rs | 57 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 1f8aac48a9a8b..a5b0111adfb4a 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -629,9 +629,9 @@ impl File { /// This acquires an exclusive advisory lock; no other file handle to this file may acquire /// another lock. /// - /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns, then an exclusive lock is held. /// /// If the file not open for writing, it is unspecified whether this function returns an error. /// @@ -639,6 +639,9 @@ impl File { /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag, @@ -671,19 +674,22 @@ impl File { self.inner.lock() } - /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired. + /// Acquire a shared (non-exclusive) advisory lock on the file. Blocks until the lock can be acquired. /// /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock. + /// none may hold an exclusive lock at the same time. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns, then a shared lock is held. /// /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag, @@ -716,14 +722,18 @@ impl File { self.inner.lock_shared() } - /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked. + /// Try to acquire an exclusive advisory lock on the file. + /// + /// Returns `Ok(false)` if a different lock is already held on this file (via another + /// handle/descriptor). /// /// This acquires an exclusive advisory lock; no other file handle to this file may acquire /// another lock. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns `Ok(true)`, then it has acquired an exclusive + /// lock. /// /// If the file not open for writing, it is unspecified whether this function returns an error. /// @@ -731,6 +741,9 @@ impl File { /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and @@ -764,20 +777,25 @@ impl File { self.inner.try_lock() } - /// Acquire a shared advisory lock on the file. - /// Returns `Ok(false)` if the file is exclusively locked. + /// Try to acquire a shared (non-exclusive) advisory lock on the file. + /// + /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another + /// handle/descriptor). /// /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock. + /// none may hold an exclusive lock at the same time. /// /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. + /// However, if this method returns `Ok(true)`, then it has acquired a shared lock. /// /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and @@ -813,7 +831,12 @@ impl File { /// Release all locks on the file. /// - /// All remaining locks are released when the file handle, and all clones of it, are dropped. + /// All locks are released when the file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed. This method allows releasing locks without + /// closing the file. + /// + /// If no lock is currently held via this file descriptor/handle, this method may return an + /// error, or may return successfully without taking any action. /// /// # Platform-specific behavior /// From 7901a3c3233cbd73f280fcb075658d7e8a943d17 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 20:18:45 +0000 Subject: [PATCH 400/481] Stabilize `const_black_box` This has been unstably const since [1], but a tracking issue was never created. Per discussion on Zulip [2], there should not be any blockers to making this const-stable. The function does not provide any functionality at compile time but does allow code reuse between const- and non-const functions, so stabilize it here. [1]: https://github.com/rust-lang/rust/pull/92226 [2]: https://rust-lang.zulipchat.com/#narrow/channel/146212-t-compiler.2Fconst-eval/topic/const_black_box --- core/src/hint.rs | 4 +++- core/src/intrinsics/mod.rs | 1 + coretests/tests/lib.rs | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/hint.rs b/core/src/hint.rs index 80f6e32b6b2cd..e5c1a64c12ee5 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -468,9 +468,11 @@ pub fn spin_loop() { /// // No assumptions can be made about either operand, so the multiplication is not optimized out. /// let y = black_box(5) * black_box(10); /// ``` +/// +/// During constant evaluation, `black_box` is treated as a no-op. #[inline] #[stable(feature = "bench_black_box", since = "1.66.0")] -#[rustc_const_unstable(feature = "const_black_box", issue = "none")] +#[rustc_const_stable(feature = "const_black_box", since = "CURRENT_RUSTC_VERSION")] pub const fn black_box(dummy: T) -> T { crate::intrinsics::black_box(dummy) } diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 41b2ffad6680d..c0d435f99c0ca 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3725,6 +3725,7 @@ pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: u #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] +#[rustc_intrinsic_const_stable_indirect] pub const fn black_box(_dummy: T) -> T { unimplemented!() } diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index 0607d508a48e5..7fe7286260858 100644 --- a/coretests/tests/lib.rs +++ b/coretests/tests/lib.rs @@ -14,7 +14,6 @@ #![feature(bstr)] #![feature(cell_update)] #![feature(clone_to_uninit)] -#![feature(const_black_box)] #![feature(const_eval_select)] #![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] From 2b1ba78a70e75ca978dbd2405dbfb445e3363fdf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2025 13:44:13 +0100 Subject: [PATCH 401/481] float::min/max: mention the non-determinism around signed 0 --- core/src/num/f128.rs | 6 ++++-- core/src/num/f16.rs | 6 ++++-- core/src/num/f32.rs | 6 ++++-- core/src/num/f64.rs | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/core/src/num/f128.rs b/core/src/num/f128.rs index 8fb1588e60b35..5e45974b3d422 100644 --- a/core/src/num/f128.rs +++ b/core/src/num/f128.rs @@ -670,7 +670,8 @@ impl f128 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f128)] @@ -696,7 +697,8 @@ impl f128 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f128)] diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index 8c2af74b8f842..e3176cd168852 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -662,7 +662,8 @@ impl f16 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f16)] @@ -687,7 +688,8 @@ impl f16 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f16)] diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index 817bedbd44f98..4d42997369ffb 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -874,7 +874,8 @@ impl f32 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0f32; @@ -895,7 +896,8 @@ impl f32 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0f32; diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 1b0651a0def07..907971d303ffc 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -892,7 +892,8 @@ impl f64 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0_f64; @@ -913,7 +914,8 @@ impl f64 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0_f64; From 4d4e77ffa89fed04c6353c59fd076d7cf1e9ed14 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2025 14:40:08 +0100 Subject: [PATCH 402/481] atomic: extend compare_and_swap migration docs --- core/src/sync/atomic.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 0061e33f98647..73180bde54aa9 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -716,6 +716,12 @@ impl AtomicBool { /// AcqRel | AcqRel | Acquire /// SeqCst | SeqCst | SeqCst /// + /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use + /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`, + /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err` + /// rather than to infer success vs failure based on the value that was read. + /// + /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead. /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, /// which allows the compiler to generate better assembly code when the compare and swap /// is used in a loop. @@ -1651,6 +1657,12 @@ impl AtomicPtr { /// AcqRel | AcqRel | Acquire /// SeqCst | SeqCst | SeqCst /// + /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use + /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`, + /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err` + /// rather than to infer success vs failure based on the value that was read. + /// + /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead. /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, /// which allows the compiler to generate better assembly code when the compare and swap /// is used in a loop. @@ -2771,6 +2783,12 @@ macro_rules! atomic_int { /// AcqRel | AcqRel | Acquire /// SeqCst | SeqCst | SeqCst /// + /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use + /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`, + /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err` + /// rather than to infer success vs failure based on the value that was read. + /// + /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead. /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, /// which allows the compiler to generate better assembly code when the compare and swap /// is used in a loop. From 9d46792702cfe709f942604d1077795e987e6329 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Tue, 17 Dec 2024 13:00:22 +0000 Subject: [PATCH 403/481] Insert null checks for pointer dereferences when debug assertions are enabled Similar to how the alignment is already checked, this adds a check for null pointer dereferences in debug mode. It is implemented similarly to the alignment check as a MirPass. This is related to a 2025H1 project goal for better UB checks in debug mode: https://github.com/rust-lang/rust-project-goals/pull/177. --- core/src/panicking.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/src/panicking.rs b/core/src/panicking.rs index 53e2b238bae69..a89de12c02bdc 100644 --- a/core/src/panicking.rs +++ b/core/src/panicking.rs @@ -291,6 +291,22 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_null_pointer_dereference")] // needed by codegen for panic on null pointer deref +#[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind +fn panic_null_pointer_dereference() -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + panic_nounwind_fmt( + format_args!("null pointer dereference occured"), + /* force_no_backtrace */ false, + ) +} + /// Panics because we cannot unwind out of a function. /// /// This is a separate function to avoid the codesize impact of each crate containing the string to From d1475210b5962fe24198d86d4ed8230d2d2fe509 Mon Sep 17 00:00:00 2001 From: uellenberg Date: Mon, 27 Jan 2025 16:21:08 -0800 Subject: [PATCH 404/481] Fix off-by-one error causing driftsort to crash Fixes #136103. Based on the analysis by @jonathan-gruber-jg and @orlp. --- core/src/slice/sort/stable/drift.rs | 4 ++-- core/src/slice/sort/stable/mod.rs | 24 ++++++++++++++++++------ core/src/slice/sort/stable/quicksort.rs | 2 ++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/core/src/slice/sort/stable/drift.rs b/core/src/slice/sort/stable/drift.rs index 644e75a4581e9..cf1df1e91a50d 100644 --- a/core/src/slice/sort/stable/drift.rs +++ b/core/src/slice/sort/stable/drift.rs @@ -10,8 +10,8 @@ use crate::{cmp, intrinsics}; /// Sorts `v` based on comparison function `is_less`. If `eager_sort` is true, /// it will only do small-sorts and physical merges, ensuring O(N * log(N)) -/// worst-case complexity. `scratch.len()` must be at least `max(v.len() / 2, -/// MIN_SMALL_SORT_SCRATCH_LEN)` otherwise the implementation may abort. +/// worst-case complexity. `scratch.len()` must be at least +/// `max(v.len() - v.len() / 2, SMALL_SORT_GENERAL_SCRATCH_LEN)` otherwise the implementation may abort. /// Fully ascending and descending inputs will be sorted with exactly N - 1 /// comparisons. /// diff --git a/core/src/slice/sort/stable/mod.rs b/core/src/slice/sort/stable/mod.rs index 7adcc83b818d1..3ff2e71fd05bc 100644 --- a/core/src/slice/sort/stable/mod.rs +++ b/core/src/slice/sort/stable/mod.rs @@ -41,6 +41,8 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less cfg_if! { if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + // Unlike driftsort, mergesort only requires len / 2, + // not len - len / 2. let alloc_len = len / 2; cfg_if! { @@ -91,16 +93,26 @@ fn driftsort_main bool, BufT: BufGuard>(v: &mut [T], i // By allocating n elements of memory we can ensure the entire input can // be sorted using stable quicksort, which allows better performance on // random and low-cardinality distributions. However, we still want to - // reduce our memory usage to n / 2 for large inputs. We do this by scaling - // our allocation as max(n / 2, min(n, 8MB)), ensuring we scale like n for - // small inputs and n / 2 for large inputs, without a sudden drop off. We - // also need to ensure our alloc >= MIN_SMALL_SORT_SCRATCH_LEN, as the + // reduce our memory usage to n - n / 2 for large inputs. We do this by scaling + // our allocation as max(n - n / 2, min(n, 8MB)), ensuring we scale like n for + // small inputs and n - n / 2 for large inputs, without a sudden drop off. We + // also need to ensure our alloc >= SMALL_SORT_GENERAL_SCRATCH_LEN, as the // small-sort always needs this much memory. + // + // driftsort will produce unsorted runs of up to min_good_run_len, which + // is at most len - len / 2. + // Unsorted runs need to be processed by quicksort, which requires as much + // scratch space as the run length, therefore the scratch space must be at + // least len - len / 2. + // If min_good_run_len is ever modified, this code must be updated to allocate + // the correct scratch size for it. const MAX_FULL_ALLOC_BYTES: usize = 8_000_000; // 8MB let max_full_alloc = MAX_FULL_ALLOC_BYTES / mem::size_of::(); let len = v.len(); - let alloc_len = - cmp::max(cmp::max(len / 2, cmp::min(len, max_full_alloc)), SMALL_SORT_GENERAL_SCRATCH_LEN); + let alloc_len = cmp::max( + cmp::max(len - len / 2, cmp::min(len, max_full_alloc)), + SMALL_SORT_GENERAL_SCRATCH_LEN, + ); // For small inputs 4KiB of stack storage suffices, which allows us to avoid // calling the (de-)allocator. Benchmarks showed this was quite beneficial. diff --git a/core/src/slice/sort/stable/quicksort.rs b/core/src/slice/sort/stable/quicksort.rs index 0c8308bfce00e..630c6ff907703 100644 --- a/core/src/slice/sort/stable/quicksort.rs +++ b/core/src/slice/sort/stable/quicksort.rs @@ -7,6 +7,8 @@ use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl; use crate::{intrinsics, ptr}; /// Sorts `v` recursively using quicksort. +/// `scratch.len()` must be at least `max(v.len() - v.len() / 2, SMALL_SORT_GENERAL_SCRATCH_LEN)` +/// otherwise the implementation may abort. /// /// `limit` when initialized with `c*log(v.len())` for some c ensures we do not /// overflow the stack or go quadratic. From 9fc2bab4d13cf6410e27b9d78c1f77a49024eb13 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 31 Jan 2025 11:37:41 +0000 Subject: [PATCH 405/481] Add documentation for derive(CoercePointee) --- core/src/marker.rs | 190 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 1 deletion(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index a793fc2aa2e55..18ada14d101b5 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -1091,7 +1091,195 @@ pub trait FnPtr: Copy + Clone { fn addr(self) -> *const (); } -/// Derive macro generating impls of traits related to smart pointers. +/// Derive macro that makes a smart pointer usable with trait objects. +/// +/// # What this macro does +/// +/// This macro is intended to be used with user-defined pointer types, and makes it possible to +/// perform coercions on the pointee of the user-defined pointer. There are two aspects to this: +/// +/// ## Unsizing coercions of the pointee +/// +/// By using the macro, the following example will compile: +/// ``` +/// #![feature(derive_coerce_pointee)] +/// use std::marker::CoercePointee; +/// use std::ops::Deref; +/// +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// struct MySmartPointer(Box); +/// +/// impl Deref for MySmartPointer { +/// type Target = T; +/// fn deref(&self) -> &T { +/// &self.0 +/// } +/// } +/// +/// trait MyTrait {} +/// +/// impl MyTrait for i32 {} +/// +/// fn main() { +/// let ptr: MySmartPointer = MySmartPointer(Box::new(4)); +/// +/// // This coercion would be an error without the derive. +/// let ptr: MySmartPointer = ptr; +/// } +/// ``` +/// Without the `#[derive(CoercePointee)]` macro, this example would fail with the following error: +/// ```text +/// error[E0308]: mismatched types +/// --> src/main.rs:11:44 +/// | +/// 11 | let ptr: MySmartPointer = ptr; +/// | --------------------------- ^^^ expected `MySmartPointer`, found `MySmartPointer` +/// | | +/// | expected due to this +/// | +/// = note: expected struct `MySmartPointer` +/// found struct `MySmartPointer` +/// = help: `i32` implements `MyTrait` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well +/// ``` +/// +/// ## Dyn compatibility +/// +/// This macro allows you to dispatch on the user-defined pointer type. That is, traits using the +/// type as a receiver are dyn-compatible. For example, this compiles: +/// +/// ``` +/// #![feature(arbitrary_self_types, derive_coerce_pointee)] +/// use std::marker::CoercePointee; +/// use std::ops::Deref; +/// +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// struct MySmartPointer(Box); +/// +/// impl Deref for MySmartPointer { +/// type Target = T; +/// fn deref(&self) -> &T { +/// &self.0 +/// } +/// } +/// +/// // You can always define this trait. (as long as you have #![feature(arbitrary_self_types)]) +/// trait MyTrait { +/// fn func(self: MySmartPointer); +/// } +/// +/// // But using `dyn MyTrait` requires #[derive(CoercePointee)]. +/// fn call_func(value: MySmartPointer) { +/// value.func(); +/// } +/// ``` +/// If you remove the `#[derive(CoercePointee)]` annotation from the struct, then the above example +/// will fail with this error message: +/// ```text +/// error[E0038]: the trait `MyTrait` is not dyn compatible +/// --> src/lib.rs:21:36 +/// | +/// 17 | fn func(self: MySmartPointer); +/// | -------------------- help: consider changing method `func`'s `self` parameter to be `&self`: `&Self` +/// ... +/// 21 | fn call_func(value: MySmartPointer) { +/// | ^^^^^^^^^^^ `MyTrait` is not dyn compatible +/// | +/// note: for a trait to be dyn compatible it needs to allow building a vtable +/// for more information, visit +/// --> src/lib.rs:17:19 +/// | +/// 16 | trait MyTrait { +/// | ------- this trait is not dyn compatible... +/// 17 | fn func(self: MySmartPointer); +/// | ^^^^^^^^^^^^^^^^^^^^ ...because method `func`'s `self` parameter cannot be dispatched on +/// ``` +/// +/// # Requirements for using the macro +/// +/// This macro can only be used if: +/// * The type is a `#[repr(transparent)]` struct. +/// * The type of its non-zero-sized field must either be a standard library pointer type +/// (reference, raw pointer, `NonNull`, `Box`, `Rc`, `Arc`, etc.) or another user-defined type +/// also using the `#[derive(CoercePointee)]` macro. +/// * Zero-sized fields must not mention any generic parameters unless the zero-sized field has +/// type [`PhantomData`]. +/// +/// ## Multiple type parameters +/// +/// If the type has multiple type parameters, then you must explicitly specify which one should be +/// used for dynamic dispatch. For example: +/// ``` +/// # #![feature(derive_coerce_pointee)] +/// # use std::marker::{CoercePointee, PhantomData}; +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// struct MySmartPointer<#[pointee] T: ?Sized, U> { +/// ptr: Box, +/// _phantom: PhantomData, +/// } +/// ``` +/// Specifying `#[pointee]` when the struct has only one type parameter is allowed, but not required. +/// +/// # Examples +/// +/// A custom implementation of the `Rc` type: +/// ``` +/// #![feature(derive_coerce_pointee)] +/// use std::marker::CoercePointee; +/// use std::ops::Deref; +/// use std::ptr::NonNull; +/// +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// pub struct Rc { +/// inner: NonNull>, +/// } +/// +/// struct RcInner { +/// refcount: usize, +/// value: T, +/// } +/// +/// impl Deref for Rc { +/// type Target = T; +/// fn deref(&self) -> &T { +/// let ptr = self.inner.as_ptr(); +/// unsafe { &(*ptr).value } +/// } +/// } +/// +/// impl Rc { +/// pub fn new(value: T) -> Self { +/// let inner = Box::new(RcInner { +/// refcount: 1, +/// value, +/// }); +/// Self { +/// inner: NonNull::from(Box::leak(inner)), +/// } +/// } +/// } +/// +/// impl Clone for Rc { +/// fn clone(&self) -> Self { +/// // A real implementation would handle overflow here. +/// unsafe { (*self.inner.as_ptr()).refcount += 1 }; +/// Self { inner: self.inner } +/// } +/// } +/// +/// impl Drop for Rc { +/// fn drop(&mut self) { +/// let ptr = self.inner.as_ptr(); +/// unsafe { (*ptr).refcount -= 1 }; +/// if unsafe { (*ptr).refcount } == 0 { +/// drop(unsafe { Box::from_raw(ptr) }); +/// } +/// } +/// } +/// ``` #[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] From aa37bb79be0c3488edb8b281aa98604cdd1e32ab Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Sat, 18 Jan 2025 23:26:47 +0900 Subject: [PATCH 406/481] docs: Documented Send and Sync requirements for Mutex + MutexGuard --- std/src/sync/poison/mutex.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/std/src/sync/poison/mutex.rs b/std/src/sync/poison/mutex.rs index 01ef71a187fec..fb43ada637543 100644 --- a/std/src/sync/poison/mutex.rs +++ b/std/src/sync/poison/mutex.rs @@ -181,10 +181,29 @@ pub struct Mutex { data: UnsafeCell, } -// these are the only places where `T: Send` matters; all other -// functionality works fine on a single thread. +/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire +/// the owned `T` from the `Mutex` via [`into_inner`]. +/// +/// [`into_inner`]: Mutex::into_inner #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Mutex {} + +/// `T` must be `Send` for [`Mutex`] to be `Sync`. +/// This ensures that the protected data can be accessed safely from multiple threads +/// without causing data races or other unsafe behavior. +/// +/// [`Mutex`] provides mutable access to `T` to one thread at a time. However, it's essential +/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in +/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer, +/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap +/// allocation with a non-atomic reference count. If we were to use `Mutex>`, it would +/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable +/// to potential data races. +/// +/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available +/// to one thread at a time if `T` is not `Sync`. +/// +/// [`Rc`]: crate::rc::Rc #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Sync for Mutex {} @@ -211,8 +230,17 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { poison: poison::Guard, } +/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// +/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to +/// release mutex locks on the same thread they were acquired. +/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from +/// another thread. #[stable(feature = "rust1", since = "1.0.0")] impl !Send for MutexGuard<'_, T> {} + +/// `T` must be `Sync` for a [`MutexGuard`] to be `Sync` +/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`). #[stable(feature = "mutexguard", since = "1.19.0")] unsafe impl Sync for MutexGuard<'_, T> {} From 67403846301a1fcc6d0392c708c7c93d7f88dea8 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 31 Jan 2025 03:51:00 +0100 Subject: [PATCH 407/481] improve doc tests for (min/max/minmax).* functions - add tests for `a == b` where missing - try to make all the tests more similar - try to use more illustrative test values --- core/src/cmp.rs | 146 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 128 insertions(+), 18 deletions(-) diff --git a/core/src/cmp.rs b/core/src/cmp.rs index 97974d195fec6..34bba5f5f2ee3 100644 --- a/core/src/cmp.rs +++ b/core/src/cmp.rs @@ -973,6 +973,24 @@ pub trait Ord: Eq + PartialOrd { /// assert_eq!(1.max(2), 2); /// assert_eq!(2.max(2), 2); /// ``` + /// ``` + /// use std::cmp::Ordering; + /// + /// #[derive(Eq)] + /// struct Equal(&'static str); + /// + /// impl PartialEq for Equal { + /// fn eq(&self, other: &Self) -> bool { true } + /// } + /// impl PartialOrd for Equal { + /// fn partial_cmp(&self, other: &Self) -> Option { Some(Ordering::Equal) } + /// } + /// impl Ord for Equal { + /// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } + /// } + /// + /// assert_eq!(Equal("self").max(Equal("other")).0, "other"); + /// ``` #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] #[must_use] @@ -994,6 +1012,24 @@ pub trait Ord: Eq + PartialOrd { /// assert_eq!(1.min(2), 1); /// assert_eq!(2.min(2), 2); /// ``` + /// ``` + /// use std::cmp::Ordering; + /// + /// #[derive(Eq)] + /// struct Equal(&'static str); + /// + /// impl PartialEq for Equal { + /// fn eq(&self, other: &Self) -> bool { true } + /// } + /// impl PartialOrd for Equal { + /// fn partial_cmp(&self, other: &Self) -> Option { Some(Ordering::Equal) } + /// } + /// impl Ord for Equal { + /// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } + /// } + /// + /// assert_eq!(Equal("self").min(Equal("other")).0, "self"); + /// ``` #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] #[must_use] @@ -1414,6 +1450,24 @@ pub macro PartialOrd($item:item) { /// assert_eq!(cmp::min(1, 2), 1); /// assert_eq!(cmp::min(2, 2), 2); /// ``` +/// ``` +/// use std::cmp::{self, Ordering}; +/// +/// #[derive(Eq)] +/// struct Equal(&'static str); +/// +/// impl PartialEq for Equal { +/// fn eq(&self, other: &Self) -> bool { true } +/// } +/// impl PartialOrd for Equal { +/// fn partial_cmp(&self, other: &Self) -> Option { Some(Ordering::Equal) } +/// } +/// impl Ord for Equal { +/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } +/// } +/// +/// assert_eq!(cmp::min(Equal("v1"), Equal("v2")).0, "v1"); +/// ``` #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1431,11 +1485,16 @@ pub fn min(v1: T, v2: T) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); -/// assert_eq!(result, 1); +/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); /// -/// let result = cmp::min_by(-2, 3, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); -/// assert_eq!(result, -2); +/// let result = cmp::min_by(2, -1, abs_cmp); +/// assert_eq!(result, -1); +/// +/// let result = cmp::min_by(2, -3, abs_cmp); +/// assert_eq!(result, 2); +/// +/// let result = cmp::min_by(1, -1, abs_cmp); +/// assert_eq!(result, 1); /// ``` #[inline] #[must_use] @@ -1456,11 +1515,14 @@ pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::min_by_key(-2, 1, |x: &i32| x.abs()); -/// assert_eq!(result, 1); +/// let result = cmp::min_by_key(2, -1, |x: &i32| x.abs()); +/// assert_eq!(result, -1); /// -/// let result = cmp::min_by_key(-2, 2, |x: &i32| x.abs()); -/// assert_eq!(result, -2); +/// let result = cmp::min_by_key(2, -3, |x: &i32| x.abs()); +/// assert_eq!(result, 2); +/// +/// let result = cmp::min_by_key(1, -1, |x: &i32| x.abs()); +/// assert_eq!(result, 1); /// ``` #[inline] #[must_use] @@ -1483,6 +1545,24 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { /// assert_eq!(cmp::max(1, 2), 2); /// assert_eq!(cmp::max(2, 2), 2); /// ``` +/// ``` +/// use std::cmp::{self, Ordering}; +/// +/// #[derive(Eq)] +/// struct Equal(&'static str); +/// +/// impl PartialEq for Equal { +/// fn eq(&self, other: &Self) -> bool { true } +/// } +/// impl PartialOrd for Equal { +/// fn partial_cmp(&self, other: &Self) -> Option { Some(Ordering::Equal) } +/// } +/// impl Ord for Equal { +/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } +/// } +/// +/// assert_eq!(cmp::max(Equal("v1"), Equal("v2")).0, "v2"); +/// ``` #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1500,11 +1580,16 @@ pub fn max(v1: T, v2: T) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); +/// +/// let result = cmp::max_by(3, -2, abs_cmp) ; +/// assert_eq!(result, 3); +/// +/// let result = cmp::max_by(1, -2, abs_cmp); /// assert_eq!(result, -2); /// -/// let result = cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())) ; -/// assert_eq!(result, 2); +/// let result = cmp::max_by(1, -1, abs_cmp); +/// assert_eq!(result, -1); /// ``` #[inline] #[must_use] @@ -1525,11 +1610,14 @@ pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::max_by_key(-2, 1, |x: &i32| x.abs()); +/// let result = cmp::max_by_key(3, -2, |x: &i32| x.abs()); +/// assert_eq!(result, 3); +/// +/// let result = cmp::max_by_key(1, -2, |x: &i32| x.abs()); /// assert_eq!(result, -2); /// -/// let result = cmp::max_by_key(-2, 2, |x: &i32| x.abs()); -/// assert_eq!(result, 2); +/// let result = cmp::max_by_key(1, -1, |x: &i32| x.abs()); +/// assert_eq!(result, -1); /// ``` #[inline] #[must_use] @@ -1549,13 +1637,32 @@ pub fn max_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { /// use std::cmp; /// /// assert_eq!(cmp::minmax(1, 2), [1, 2]); -/// assert_eq!(cmp::minmax(2, 2), [2, 2]); +/// assert_eq!(cmp::minmax(2, 1), [1, 2]); /// /// // You can destructure the result using array patterns /// let [min, max] = cmp::minmax(42, 17); /// assert_eq!(min, 17); /// assert_eq!(max, 42); /// ``` +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp::{self, Ordering}; +/// +/// #[derive(Eq)] +/// struct Equal(&'static str); +/// +/// impl PartialEq for Equal { +/// fn eq(&self, other: &Self) -> bool { true } +/// } +/// impl PartialOrd for Equal { +/// fn partial_cmp(&self, other: &Self) -> Option { Some(Ordering::Equal) } +/// } +/// impl Ord for Equal { +/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } +/// } +/// +/// assert_eq!(cmp::minmax(Equal("v1"), Equal("v2")).map(|v| v.0), ["v1", "v2"]); +/// ``` #[inline] #[must_use] #[unstable(feature = "cmp_minmax", issue = "115939")] @@ -1576,11 +1683,14 @@ where /// #![feature(cmp_minmax)] /// use std::cmp; /// -/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]); -/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]); +/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); +/// +/// assert_eq!(cmp::minmax_by(-2, 1, abs_cmp), [1, -2]); +/// assert_eq!(cmp::minmax_by(-1, 2, abs_cmp), [-1, 2]); +/// assert_eq!(cmp::minmax_by(-2, 2, abs_cmp), [-2, 2]); /// /// // You can destructure the result using array patterns -/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// let [min, max] = cmp::minmax_by(-42, 17, abs_cmp); /// assert_eq!(min, 17); /// assert_eq!(max, -42); /// ``` From d68e21c9c4f767bc85c16000939d712a23a5cc5b Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 30 Jan 2025 17:27:16 +0100 Subject: [PATCH 408/481] implement all min/max fns in terms of `<`/`is_lt` `<` seems to be the "lucky one" for llvm --- core/src/cmp.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/core/src/cmp.rs b/core/src/cmp.rs index 34bba5f5f2ee3..594236cf1d96f 100644 --- a/core/src/cmp.rs +++ b/core/src/cmp.rs @@ -999,7 +999,7 @@ pub trait Ord: Eq + PartialOrd { where Self: Sized, { - max_by(self, other, Ord::cmp) + if other < self { self } else { other } } /// Compares and returns the minimum of two values. @@ -1038,7 +1038,7 @@ pub trait Ord: Eq + PartialOrd { where Self: Sized, { - min_by(self, other, Ord::cmp) + if other < self { other } else { self } } /// Restrict a value to a certain interval. @@ -1500,10 +1500,7 @@ pub fn min(v1: T, v2: T) -> T { #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { - match compare(&v1, &v2) { - Ordering::Less | Ordering::Equal => v1, - Ordering::Greater => v2, - } + if compare(&v2, &v1).is_lt() { v2 } else { v1 } } /// Returns the element that gives the minimum value from the specified function. @@ -1528,7 +1525,7 @@ pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { - min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) + if f(&v2) < f(&v1) { v2 } else { v1 } } /// Compares and returns the maximum of two values. @@ -1595,10 +1592,7 @@ pub fn max(v1: T, v2: T) -> T { #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { - match compare(&v1, &v2) { - Ordering::Less | Ordering::Equal => v2, - Ordering::Greater => v1, - } + if compare(&v2, &v1).is_lt() { v1 } else { v2 } } /// Returns the element that gives the maximum value from the specified function. @@ -1623,7 +1617,7 @@ pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { - max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) + if f(&v2) < f(&v1) { v1 } else { v2 } } /// Compares and sorts two values, returning minimum and maximum. @@ -1670,7 +1664,7 @@ pub fn minmax(v1: T, v2: T) -> [T; 2] where T: Ord, { - if v1 <= v2 { [v1, v2] } else { [v2, v1] } + if v2 < v1 { [v2, v1] } else { [v1, v2] } } /// Returns minimum and maximum values with respect to the specified comparison function. @@ -1701,7 +1695,7 @@ pub fn minmax_by(v1: T, v2: T, compare: F) -> [T; 2] where F: FnOnce(&T, &T) -> Ordering, { - if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } + if compare(&v2, &v1).is_lt() { [v2, v1] } else { [v1, v2] } } /// Returns minimum and maximum values with respect to the specified key function. @@ -1730,7 +1724,7 @@ where F: FnMut(&T) -> K, K: Ord, { - minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) + if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] } } // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types From 37772629a46d8f747d28cd8218b63997a011ffd9 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Sat, 1 Feb 2025 02:10:02 +0800 Subject: [PATCH 409/481] stabilize `once_wait` --- std/src/sync/once_lock.rs | 4 +--- std/src/sync/poison/once.rs | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/std/src/sync/once_lock.rs b/std/src/sync/once_lock.rs index 49f2dafd8fd9c..6fc0abbed9e15 100644 --- a/std/src/sync/once_lock.rs +++ b/std/src/sync/once_lock.rs @@ -174,8 +174,6 @@ impl OnceLock { /// /// Waiting for a computation on another thread to finish: /// ```rust - /// #![feature(once_wait)] - /// /// use std::thread; /// use std::sync::OnceLock; /// @@ -189,7 +187,7 @@ impl OnceLock { /// }) /// ``` #[inline] - #[unstable(feature = "once_wait", issue = "127527")] + #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] pub fn wait(&self) -> &T { self.once.wait_force(); diff --git a/std/src/sync/poison/once.rs b/std/src/sync/poison/once.rs index 27db4b634fb28..528b11ca0c1e6 100644 --- a/std/src/sync/poison/once.rs +++ b/std/src/sync/poison/once.rs @@ -269,8 +269,6 @@ impl Once { /// # Example /// /// ```rust - /// #![feature(once_wait)] - /// /// use std::sync::Once; /// use std::thread; /// @@ -289,7 +287,7 @@ impl Once { /// If this [`Once`] has been poisoned because an initialization closure has /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force) /// if this behavior is not desired. - #[unstable(feature = "once_wait", issue = "127527")] + #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] pub fn wait(&self) { if !self.inner.is_completed() { self.inner.wait(false); @@ -298,7 +296,7 @@ impl Once { /// Blocks the current thread until initialization has completed, ignoring /// poisoning. - #[unstable(feature = "once_wait", issue = "127527")] + #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] pub fn wait_force(&self) { if !self.inner.is_completed() { self.inner.wait(true); From 52067476b82f5b504ee59e387101e5b445c5947d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 31 Jan 2025 20:19:25 +0100 Subject: [PATCH 410/481] document ptr comparison being by address --- core/src/ptr/const_ptr.rs | 6 ++++-- core/src/ptr/mut_ptr.rs | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index ec569291853a5..0c6eaf60d0480 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -1681,7 +1681,7 @@ impl *const [T; N] { } } -// Equality for pointers +/// Pointer equality is by address, as produced by the [`<*const T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *const T { #[inline] @@ -1691,10 +1691,11 @@ impl PartialEq for *const T { } } +/// Pointer equality is an equivalence relation. #[stable(feature = "rust1", since = "1.0.0")] impl Eq for *const T {} -// Comparison for pointers +/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for *const T { #[inline] @@ -1710,6 +1711,7 @@ impl Ord for *const T { } } +/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for *const T { #[inline] diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 5d9d337f101a5..d1b0104c0fa92 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -2097,7 +2097,7 @@ impl *mut [T; N] { } } -// Equality for pointers +/// Pointer equality is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *mut T { #[inline(always)] @@ -2107,9 +2107,11 @@ impl PartialEq for *mut T { } } +/// Pointer equality is an equivalence relation. #[stable(feature = "rust1", since = "1.0.0")] impl Eq for *mut T {} +/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for *mut T { #[inline] @@ -2125,6 +2127,7 @@ impl Ord for *mut T { } } +/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for *mut T { #[inline(always)] From c18c177d8d57dff46533ba12ad72464ff98bd2c4 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 27 Jan 2025 15:00:21 +0100 Subject: [PATCH 411/481] Fix sentence in process::abort --- std/src/process.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/std/src/process.rs b/std/src/process.rs index e0dd2e14817a8..fd0fd1cb755e0 100644 --- a/std/src/process.rs +++ b/std/src/process.rs @@ -2318,14 +2318,10 @@ pub fn exit(code: i32) -> ! { /// Terminates the process in an abnormal fashion. /// /// The function will never return and will immediately terminate the current -/// process in a platform specific "abnormal" manner. -/// -/// Note that because this function never returns, and that it terminates the -/// process, no destructors on the current stack or any other thread's stack -/// will be run. -/// -/// Rust IO buffers (eg, from `BufWriter`) will not be flushed. -/// Likewise, C stdio buffers will (on most platforms) not be flushed. +/// process in a platform specific "abnormal" manner. As a consequence, +/// no destructors on the current stack or any other thread's stack +/// will be run, Rust IO buffers (eg, from `BufWriter`) will not be flushed, +/// and C stdio buffers will (on most platforms) not be flushed. /// /// This is in contrast to the default behavior of [`panic!`] which unwinds /// the current thread's stack and calls all destructors. From 0e80c9611c2a0b51298011dcefbff1f2792c4f96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Dec 2024 18:23:32 +0100 Subject: [PATCH 412/481] make rustc_encodable_decodable feature properly unstable --- core/src/macros/mod.rs | 6 ++---- core/src/prelude/mod.rs | 3 +-- std/src/prelude/mod.rs | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 01a3c9d2ada72..a080633ad898c 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1836,8 +1836,7 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[unstable( feature = "rustc_encodable_decodable", - issue = "none", - soft, + issue = "134301", reason = "derive macro for `rustc-serialize`; should not be used in new code" )] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] @@ -1850,8 +1849,7 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[unstable( feature = "rustc_encodable_decodable", - issue = "none", - soft, + issue = "134301", reason = "derive macro for `rustc-serialize`; should not be used in new code" )] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] diff --git a/core/src/prelude/mod.rs b/core/src/prelude/mod.rs index d3fda1cd273f9..98f061d463a09 100644 --- a/core/src/prelude/mod.rs +++ b/core/src/prelude/mod.rs @@ -22,8 +22,7 @@ pub mod v1 { // Do not `doc(inline)` these `doc(hidden)` items. #[unstable( feature = "rustc_encodable_decodable", - issue = "none", - soft, + issue = "134301", reason = "derive macro for `rustc-serialize`; should not be used in new code" )] #[allow(deprecated)] diff --git a/std/src/prelude/mod.rs b/std/src/prelude/mod.rs index 4ec328208f015..b7efffcc44668 100644 --- a/std/src/prelude/mod.rs +++ b/std/src/prelude/mod.rs @@ -124,8 +124,7 @@ pub mod v1 { // Do not `doc(inline)` these `doc(hidden)` items. #[unstable( feature = "rustc_encodable_decodable", - issue = "none", - soft, + issue = "134301", reason = "derive macro for `rustc-serialize`; should not be used in new code" )] #[allow(deprecated)] From ba503edfde4aa89d74d36bc50c021d0a2518d4cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jan 2025 18:28:42 +0100 Subject: [PATCH 413/481] remove Rustc{En,De}codable from library and compiler --- core/src/macros/mod.rs | 26 -------------------------- core/src/prelude/mod.rs | 9 --------- std/src/prelude/mod.rs | 9 --------- 3 files changed, 44 deletions(-) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index a080633ad898c..3669051ce82d3 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1831,30 +1831,4 @@ pub(crate) mod builtin { pub macro deref($pat:pat) { builtin # deref($pat) } - - /// Derive macro for `rustc-serialize`. Should not be used in new code. - #[rustc_builtin_macro] - #[unstable( - feature = "rustc_encodable_decodable", - issue = "134301", - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] - #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. - pub macro RustcDecodable($item:item) { - /* compiler built-in */ - } - - /// Derive macro for `rustc-serialize`. Should not be used in new code. - #[rustc_builtin_macro] - #[unstable( - feature = "rustc_encodable_decodable", - issue = "134301", - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] - #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. - pub macro RustcEncodable($item:item) { - /* compiler built-in */ - } } diff --git a/core/src/prelude/mod.rs b/core/src/prelude/mod.rs index 98f061d463a09..0ab97f5bbd50e 100644 --- a/core/src/prelude/mod.rs +++ b/core/src/prelude/mod.rs @@ -18,15 +18,6 @@ mod common; pub mod v1 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - - // Do not `doc(inline)` these `doc(hidden)` items. - #[unstable( - feature = "rustc_encodable_decodable", - issue = "134301", - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[allow(deprecated)] - pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; } /// The 2015 version of the core prelude. diff --git a/std/src/prelude/mod.rs b/std/src/prelude/mod.rs index b7efffcc44668..14e6c2715df0b 100644 --- a/std/src/prelude/mod.rs +++ b/std/src/prelude/mod.rs @@ -120,15 +120,6 @@ mod common; pub mod v1 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - - // Do not `doc(inline)` these `doc(hidden)` items. - #[unstable( - feature = "rustc_encodable_decodable", - issue = "134301", - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[allow(deprecated)] - pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; } /// The 2015 version of the prelude of The Rust Standard Library. From 68e53b91ee42944287c3e638a4331e5364501a7b Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 30 Jan 2025 09:13:21 +0100 Subject: [PATCH 414/481] Update encode_utf16 to mention it is native endian --- alloc/src/string.rs | 16 ++++++++-------- core/src/char/methods.rs | 6 +++--- core/src/str/mod.rs | 3 ++- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index 0c9535dfaa628..b29f740ef0f2a 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -712,8 +712,8 @@ impl String { } } - /// Decode a UTF-16–encoded vector `v` into a `String`, returning [`Err`] - /// if `v` contains any invalid data. + /// Decode a native endian UTF-16–encoded vector `v` into a `String`, + /// returning [`Err`] if `v` contains any invalid data. /// /// # Examples /// @@ -745,8 +745,8 @@ impl String { Ok(ret) } - /// Decode a UTF-16–encoded slice `v` into a `String`, replacing - /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD]. + /// Decode a native endian UTF-16–encoded slice `v` into a `String`, + /// replacing invalid data with [the replacement character (`U+FFFD`)][U+FFFD]. /// /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`], /// `from_utf16_lossy` returns a `String` since the UTF-16 to UTF-8 @@ -777,8 +777,8 @@ impl String { .collect() } - /// Decode a UTF-16LE–encoded vector `v` into a `String`, returning [`Err`] - /// if `v` contains any invalid data. + /// Decode a UTF-16LE–encoded vector `v` into a `String`, + /// returning [`Err`] if `v` contains any invalid data. /// /// # Examples /// @@ -852,8 +852,8 @@ impl String { } } - /// Decode a UTF-16BE–encoded vector `v` into a `String`, returning [`Err`] - /// if `v` contains any invalid data. + /// Decode a UTF-16BE–encoded vector `v` into a `String`, + /// returning [`Err`] if `v` contains any invalid data. /// /// # Examples /// diff --git a/core/src/char/methods.rs b/core/src/char/methods.rs index fb8a740aced13..ccfdbf0eb704d 100644 --- a/core/src/char/methods.rs +++ b/core/src/char/methods.rs @@ -92,7 +92,7 @@ impl char { #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const UNICODE_VERSION: (u8, u8, u8) = crate::unicode::UNICODE_VERSION; - /// Creates an iterator over the UTF-16 encoded code points in `iter`, + /// Creates an iterator over the native endian UTF-16 encoded code points in `iter`, /// returning unpaired surrogates as `Err`s. /// /// # Examples @@ -704,7 +704,7 @@ impl char { unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } } - /// Encodes this character as UTF-16 into the provided `u16` buffer, + /// Encodes this character as native endian UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// /// # Panics @@ -1828,7 +1828,7 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } } -/// Encodes a raw `u32` value as UTF-16 into the provided `u16` buffer, +/// Encodes a raw `u32` value as native endian UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// /// Unlike `char::encode_utf16`, this method also handles codepoints in the surrogate range. diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 8a473b398bb5f..39fa6c1a25fe9 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -1108,7 +1108,8 @@ impl str { LinesAny(self.lines()) } - /// Returns an iterator of `u16` over the string encoded as UTF-16. + /// Returns an iterator of `u16` over the string encoded + /// as native endian UTF-16 (without byte-order mark). /// /// # Examples /// From bc25d718fcc8530e78def43a23c67188eda022d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Feb 2025 12:33:40 +0100 Subject: [PATCH 415/481] rustc_allowed_through_unstable_modules: require deprecation message --- core/src/intrinsics/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index c0d435f99c0ca..bf07632d9928b 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -78,7 +78,11 @@ pub mod simd; use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; #[stable(feature = "drop_in_place", since = "1.8.0")] -#[rustc_allowed_through_unstable_modules] +#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] +#[cfg_attr( + not(bootstrap), + rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead" +)] #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] #[inline] pub unsafe fn drop_in_place(to_drop: *mut T) { From 9d86eb06b5a14b895ea12e278117b4060337bcae Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Fri, 31 Jan 2025 07:10:15 -0800 Subject: [PATCH 416/481] Docs for f16 and f128: correct a typo and add details --- core/src/primitive_docs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/primitive_docs.rs b/core/src/primitive_docs.rs index c5f029363e589..bbf5939fe1b05 100644 --- a/core/src/primitive_docs.rs +++ b/core/src/primitive_docs.rs @@ -1160,9 +1160,9 @@ impl (T,) {} /// /// Note that most common platforms will not support `f16` in hardware without enabling extra target /// features, with the notable exception of Apple Silicon (also known as M1, M2, etc.) processors. -/// Hardware support on x86-64 requires the avx512fp16 feature, while RISC-V requires Zhf. -/// Usually the fallback implementation will be to use `f32` hardware if it exists, and convert -/// between `f16` and `f32` when performing math. +/// Hardware support on x86/x86-64 requires the avx512fp16 or avx10.1 features, while RISC-V requires +/// Zfh, and Arm/AArch64 requires FEAT_FP16. Usually the fallback implementation will be to use `f32` +/// hardware if it exists, and convert between `f16` and `f32` when performing math. /// /// *[See also the `std::f16::consts` module](crate::f16::consts).* /// @@ -1344,10 +1344,10 @@ mod prim_f64 {} /// quad-precision values][wikipedia] for more information. /// /// Note that no platforms have hardware support for `f128` without enabling target specific features, -/// as for all instruction set architectures `f128` is considered an optional feature. -/// Only Power ISA ("PowerPC") and RISC-V specify it, and only certain microarchitectures -/// actually implement it. For x86-64 and AArch64, ISA support is not even specified, -/// so it will always be a software implementation significantly slower than `f64`. +/// as for all instruction set architectures `f128` is considered an optional feature. Only Power ISA +/// ("PowerPC") and RISC-V (via the Q extension) specify it, and only certain microarchitectures +/// actually implement it. For x86-64 and AArch64, ISA support is not even specified, so it will always +/// be a software implementation significantly slower than `f64`. /// /// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On /// x86 in particular, these functions do link but their results are always incorrect._ From 99c641fde18cee2f0520ca57ac7aaee2330100e9 Mon Sep 17 00:00:00 2001 From: Pyrode Date: Mon, 3 Feb 2025 17:48:39 +0530 Subject: [PATCH 417/481] OnceCell & OnceLock docs: Using (un)initialized consistently --- core/src/cell/once.rs | 53 ++++++++++++++++--------------- std/src/sync/once_lock.rs | 65 ++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/core/src/cell/once.rs b/core/src/cell/once.rs index 6a85791916a61..c6c96571d33c9 100644 --- a/core/src/cell/once.rs +++ b/core/src/cell/once.rs @@ -8,6 +8,9 @@ use crate::{fmt, mem}; /// only immutable references can be obtained unless one has a mutable reference to the cell /// itself. In the same vein, the cell can only be re-initialized with such a mutable reference. /// +/// A `OnceCell` can be thought of as a safe abstraction over uninitialized data that becomes +/// initialized once written. +/// /// For a thread-safe version of this struct, see [`std::sync::OnceLock`]. /// /// [`RefCell`]: crate::cell::RefCell @@ -35,7 +38,7 @@ pub struct OnceCell { } impl OnceCell { - /// Creates a new empty cell. + /// Creates a new uninitialized cell. #[inline] #[must_use] #[stable(feature = "once_cell", since = "1.70.0")] @@ -46,7 +49,7 @@ impl OnceCell { /// Gets the reference to the underlying value. /// - /// Returns `None` if the cell is empty. + /// Returns `None` if the cell is uninitialized. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get(&self) -> Option<&T> { @@ -56,19 +59,19 @@ impl OnceCell { /// Gets the mutable reference to the underlying value. /// - /// Returns `None` if the cell is empty. + /// Returns `None` if the cell is uninitialized. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get_mut(&mut self) -> Option<&mut T> { self.inner.get_mut().as_mut() } - /// Sets the contents of the cell to `value`. + /// Initializes the contents of the cell to `value`. /// /// # Errors /// - /// This method returns `Ok(())` if the cell was empty and `Err(value)` if - /// it was full. + /// This method returns `Ok(())` if the cell was uninitialized + /// and `Err(value)` if it was already initialized. /// /// # Examples /// @@ -92,13 +95,13 @@ impl OnceCell { } } - /// Sets the contents of the cell to `value` if the cell was empty, then - /// returns a reference to it. + /// Initializes the contents of the cell to `value` if the cell was + /// uninitialized, then returns a reference to it. /// /// # Errors /// - /// This method returns `Ok(&value)` if the cell was empty and - /// `Err(¤t_value, value)` if it was full. + /// This method returns `Ok(&value)` if the cell was uninitialized + /// and `Err((¤t_value, value))` if it was already initialized. /// /// # Examples /// @@ -130,12 +133,12 @@ impl OnceCell { Ok(slot.insert(value)) } - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. + /// Gets the contents of the cell, initializing it to `f()` + /// if the cell was uninitialized. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. Doing @@ -164,11 +167,11 @@ impl OnceCell { } /// Gets the mutable reference of the contents of the cell, - /// initializing it with `f` if the cell was empty. + /// initializing it to `f()` if the cell was uninitialized. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// # Examples @@ -199,13 +202,13 @@ impl OnceCell { } } - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. + /// Gets the contents of the cell, initializing it to `f()` if + /// the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. Doing @@ -239,12 +242,12 @@ impl OnceCell { } /// Gets the mutable reference of the contents of the cell, initializing - /// it with `f` if the cell was empty. If the cell was empty and `f` failed, - /// an error is returned. + /// it to `f()` if the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// # Examples @@ -256,7 +259,7 @@ impl OnceCell { /// /// let mut cell: OnceCell = OnceCell::new(); /// - /// // Failed initializers do not change the value + /// // Failed attempts to initialize the cell do not change its contents /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); /// assert!(cell.get().is_none()); /// @@ -295,7 +298,7 @@ impl OnceCell { /// Consumes the cell, returning the wrapped value. /// - /// Returns `None` if the cell was empty. + /// Returns `None` if the cell was uninitialized. /// /// # Examples /// @@ -321,7 +324,7 @@ impl OnceCell { /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. /// - /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. + /// Has no effect and returns `None` if the `OnceCell` is uninitialized. /// /// Safety is guaranteed by requiring a mutable reference. /// diff --git a/std/src/sync/once_lock.rs b/std/src/sync/once_lock.rs index 6fc0abbed9e15..8f769f2dca37e 100644 --- a/std/src/sync/once_lock.rs +++ b/std/src/sync/once_lock.rs @@ -13,6 +13,9 @@ use crate::sync::Once; /// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock /// doesn't allow additional inputs to its function after you call [`LazyLock::new(|| ...)`]. /// +/// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes +/// initialized once written. +/// /// [`OnceCell`]: crate::cell::OnceCell /// [`LazyLock`]: crate::sync::LazyLock /// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new @@ -126,7 +129,7 @@ pub struct OnceLock { } impl OnceLock { - /// Creates a new empty cell. + /// Creates a new uninitialized cell. #[inline] #[must_use] #[stable(feature = "once_cell", since = "1.70.0")] @@ -141,8 +144,8 @@ impl OnceLock { /// Gets the reference to the underlying value. /// - /// Returns `None` if the cell is empty, or being initialized. This - /// method never blocks. + /// Returns `None` if the cell is uninitialized, or being initialized. + /// This method never blocks. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get(&self) -> Option<&T> { @@ -156,7 +159,8 @@ impl OnceLock { /// Gets the mutable reference to the underlying value. /// - /// Returns `None` if the cell is empty. This method never blocks. + /// Returns `None` if the cell is uninitialized, or being initialized. + /// This method never blocks. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get_mut(&mut self) -> Option<&mut T> { @@ -194,12 +198,13 @@ impl OnceLock { unsafe { self.get_unchecked() } } - /// Sets the contents of this cell to `value`. + /// Initializes the contents of the cell to `value`. /// /// May block if another thread is currently attempting to initialize the cell. The cell is - /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// guaranteed to contain a value when `set` returns, though not necessarily the one provided. /// - /// Returns `Ok(())` if the cell's value was set by this call. + /// Returns `Ok(())` if the cell was uninitialized and + /// `Err(value)` if the cell was already initialized. /// /// # Examples /// @@ -228,13 +233,15 @@ impl OnceLock { } } - /// Sets the contents of this cell to `value` if the cell was empty, then - /// returns a reference to it. + /// Initializes the contents of the cell to `value` if the cell was uninitialized, + /// then returns a reference to it. /// /// May block if another thread is currently attempting to initialize the cell. The cell is - /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// guaranteed to contain a value when `try_insert` returns, though not necessarily the + /// one provided. /// - /// Returns `Ok(&value)` if the cell was empty and `Err(¤t_value, value)` if it was full. + /// Returns `Ok(&value)` if the cell was uninitialized and + /// `Err((¤t_value, value))` if it was already initialized. /// /// # Examples /// @@ -267,8 +274,8 @@ impl OnceLock { } } - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. + /// Gets the contents of the cell, initializing it to `f()` if the cell + /// was uninitialized. /// /// Many threads may call `get_or_init` concurrently with different /// initializing functions, but it is guaranteed that only one function @@ -276,7 +283,7 @@ impl OnceLock { /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. The @@ -306,13 +313,13 @@ impl OnceLock { } /// Gets the mutable reference of the contents of the cell, initializing - /// it with `f` if the cell was empty. + /// it to `f()` if the cell was uninitialized. /// /// This method never blocks. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// # Examples @@ -343,13 +350,13 @@ impl OnceLock { } } - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. + /// Gets the contents of the cell, initializing it to `f()` if + /// the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and + /// If `f()` panics, the panic is propagated to the caller, and /// the cell remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. @@ -395,14 +402,14 @@ impl OnceLock { } /// Gets the mutable reference of the contents of the cell, initializing - /// it with `f` if the cell was empty. If the cell was empty and `f` failed, - /// an error is returned. + /// it to `f()` if the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// This method never blocks. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and + /// If `f()` panics, the panic is propagated to the caller, and /// the cell remains uninitialized. /// /// # Examples @@ -414,7 +421,7 @@ impl OnceLock { /// /// let mut cell: OnceLock = OnceLock::new(); /// - /// // Failed initializers do not change the value + /// // Failed attempts to initialize the cell do not change its contents /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); /// assert!(cell.get().is_none()); /// @@ -438,7 +445,7 @@ impl OnceLock { } /// Consumes the `OnceLock`, returning the wrapped value. Returns - /// `None` if the cell was empty. + /// `None` if the cell was uninitialized. /// /// # Examples /// @@ -460,7 +467,7 @@ impl OnceLock { /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state. /// - /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized. + /// Has no effect and returns `None` if the `OnceLock` was uninitialized. /// /// Safety is guaranteed by requiring a mutable reference. /// @@ -526,7 +533,7 @@ impl OnceLock { /// # Safety /// - /// The value must be initialized + /// The cell must be initialized #[inline] unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); @@ -535,7 +542,7 @@ impl OnceLock { /// # Safety /// - /// The value must be initialized + /// The cell must be initialized #[inline] unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); @@ -560,7 +567,7 @@ impl UnwindSafe for OnceLock {} #[stable(feature = "once_cell", since = "1.70.0")] impl Default for OnceLock { - /// Creates a new empty cell. + /// Creates a new uninitialized cell. /// /// # Example /// From ab533c894cf1f5b1f8a3e16a8f9fcc1e690e7295 Mon Sep 17 00:00:00 2001 From: "Pascal S. de Kloe" Date: Wed, 8 Jan 2025 19:27:11 +0100 Subject: [PATCH 418/481] black_box integer-input on fmt benches --- coretests/benches/fmt.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/coretests/benches/fmt.rs b/coretests/benches/fmt.rs index ed478b0f1e055..ee8e981b46b97 100644 --- a/coretests/benches/fmt.rs +++ b/coretests/benches/fmt.rs @@ -124,42 +124,41 @@ fn write_str_macro_debug_ascii(bh: &mut Bencher) { #[bench] fn write_u128_max(bh: &mut Bencher) { bh.iter(|| { - test::black_box(format!("{}", u128::MAX)); + black_box(format!("{}", black_box(u128::MAX))); }); } #[bench] fn write_u128_min(bh: &mut Bencher) { bh.iter(|| { - let s = format!("{}", 0u128); - test::black_box(s); + black_box(format!("{}", black_box(u128::MIN))); }); } #[bench] fn write_u64_max(bh: &mut Bencher) { bh.iter(|| { - test::black_box(format!("{}", u64::MAX)); + black_box(format!("{}", black_box(u64::MAX))); }); } #[bench] fn write_u64_min(bh: &mut Bencher) { bh.iter(|| { - test::black_box(format!("{}", 0u64)); + black_box(format!("{}", black_box(u64::MIN))); }); } #[bench] fn write_u8_max(bh: &mut Bencher) { bh.iter(|| { - test::black_box(format!("{}", u8::MAX)); + black_box(format!("{}", black_box(u8::MAX))); }); } #[bench] fn write_u8_min(bh: &mut Bencher) { bh.iter(|| { - test::black_box(format!("{}", 0u8)); + black_box(format!("{}", black_box(u8::MIN))); }); } From 76ade3882e893baa11def9f0c1eccb0c3d2f8652 Mon Sep 17 00:00:00 2001 From: "Pascal S. de Kloe" Date: Wed, 8 Jan 2025 19:42:54 +0100 Subject: [PATCH 419/481] no unsafe pointer and no overflowing_literals in fmt::Display of integers --- core/src/fmt/num.rs | 143 +++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 68 deletions(-) diff --git a/core/src/fmt/num.rs b/core/src/fmt/num.rs index 683e45b35f70a..7166f106b8da2 100644 --- a/core/src/fmt/num.rs +++ b/core/src/fmt/num.rs @@ -192,7 +192,8 @@ macro_rules! impl_Debug { } // 2 digit decimal look up table -static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ +static DEC_DIGITS_LUT: &[u8; 200] = b"\ + 0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ 6061626364656667686970717273747576777879\ @@ -232,83 +233,89 @@ macro_rules! impl_Display { #[cfg(not(feature = "optimize_for_size"))] impl $unsigned { - fn _fmt(mut self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; - let mut buf = [MaybeUninit::::uninit(); SIZE]; - let mut curr = SIZE; - let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); - let lut_ptr = DEC_DIGITS_LUT.as_ptr(); - - // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we - // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. 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 { - // need at least 16 bits for the 4-characters-at-a-time to work. - #[allow(overflowing_literals)] - #[allow(unused_comparisons)] - // This block will be removed for smaller types at compile time and in the worst - // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. - if core::mem::size_of::<$unsigned>() >= 2 { - // eagerly decode 4 characters at a time - while self >= 10000 { - let rem = (self % 10000) as usize; - self /= 10000; - - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; - - // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since - // otherwise `curr < 0`. But then `n` was originally at least `10000^10` - // which is `10^40 > 2^128 > n`. - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2); - } - } - - // if we reach here numbers are <= 9999, so at most 4 chars long - let mut n = self as usize; // possibly reduce 64bit math + fn _fmt(self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1; + // Buffer decimals for $unsigned with right alignment. + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + // 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. + let mut remain = self; + + // Format per four digits from the lookup table. + // Four digits need a 16-bit $unsigned or wider. + while size_of::() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the while condition ensures at least 4 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 4) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 4; + + // pull two pairs + let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)"); + let quad = remain % scale; + remain /= scale; + let pair1 = (quad / 100) as usize; + let pair2 = (quad % 100) as usize; + buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]); + buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]); + buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]); + buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]); + } - // decode 2 more chars, if > 2 chars - if n >= 100 { - let d1 = (n % 100) << 1; - n /= 100; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); - } + // Format per two digits from the lookup table. + if remain > 9 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the while condition ensures at least 2 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 2) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 2; + + let pair = (remain % 100) as usize; + remain /= 100; + buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]); + buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]); + } - // if we reach here numbers are <= 100, so at most 2 chars long - // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough. - // decode last 1 or 2 chars - if n < 10 { - curr -= 1; - *buf_ptr.add(curr) = (n as u8) + b'0'; - } else { - let d1 = n << 1; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); - } + // Format the last remaining digit, if any. + if remain != 0 || self == 0 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the if condition ensures (at least) 1 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 1) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 1; + + // Either the compiler sees that remain < 10, or it prevents + // a boundary check up next. + let last = (remain & 15) as usize; + buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]); + // not used: remain = 0; } - // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid - // UTF-8 since `DEC_DIGITS_LUT` is - let buf_slice = unsafe { - str::from_utf8_unchecked( - slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) + // SAFETY: All buf content since offset is set. + let written = unsafe { buf.get_unchecked(offset..) }; + // SAFETY: Writes use ASCII from the lookup table exclusively. + let as_str = unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + MaybeUninit::slice_as_ptr(written), + written.len(), + )) }; - f.pad_integral(is_nonnegative, "", buf_slice) + f.pad_integral(is_nonnegative, "", as_str) } })* #[cfg(feature = "optimize_for_size")] fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const SIZE: usize = $u::MAX.ilog(10) as usize + 1; - let mut buf = [MaybeUninit::::uninit(); SIZE]; - let mut curr = buf.len(); + const MAX_DEC_N: usize = $u::MAX.ilog(10) 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); // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning From 5672cc0d4fcc2562a3c458b3692d366223b8a901 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:21:18 +0000 Subject: [PATCH 420/481] Move std::env unit tests to integration tests --- std/src/env.rs | 3 -- std/src/env/tests.rs | 120 ------------------------------------------- std/tests/env.rs | 120 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 123 deletions(-) delete mode 100644 std/src/env/tests.rs diff --git a/std/src/env.rs b/std/src/env.rs index bbd506127fb67..c665dfd36247f 100644 --- a/std/src/env.rs +++ b/std/src/env.rs @@ -10,9 +10,6 @@ #![stable(feature = "env", since = "1.0.0")] -#[cfg(test)] -mod tests; - use crate::error::Error; use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf}; diff --git a/std/src/env/tests.rs b/std/src/env/tests.rs deleted file mode 100644 index d021726106872..0000000000000 --- a/std/src/env/tests.rs +++ /dev/null @@ -1,120 +0,0 @@ -use super::*; - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)] -fn test_self_exe_path() { - let path = current_exe(); - assert!(path.is_ok()); - let path = path.unwrap(); - - // Hard to test this function - assert!(path.is_absolute()); -} - -#[test] -fn test() { - assert!((!Path::new("test-path").is_absolute())); - - #[cfg(not(target_env = "sgx"))] - current_dir().unwrap(); -} - -#[test] -#[cfg(windows)] -fn split_paths_windows() { - use crate::path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() - == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse(r#""""#, &mut [""])); - assert!(check_parse(";;", &mut ["", "", ""])); - assert!(check_parse(r"c:\", &mut [r"c:\"])); - assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); - assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"])); - assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); - assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); -} - -#[test] -#[cfg(unix)] -fn split_paths_unix() { - use crate::path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() - == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse("::", &mut ["", "", ""])); - assert!(check_parse("/", &mut ["/"])); - assert!(check_parse("/:", &mut ["/", ""])); - assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); -} - -#[test] -#[cfg(unix)] -fn join_paths_unix() { - use crate::ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin")); - assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); - assert!(join_paths(["/te:st"].iter().cloned()).is_err()); -} - -#[test] -#[cfg(windows)] -fn join_paths_windows() { - use crate::ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\")); - assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;")); - assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); - assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); -} - -#[test] -fn args_debug() { - assert_eq!( - format!("Args {{ inner: {:?} }}", args().collect::>()), - format!("{:?}", args()) - ); -} - -#[test] -fn args_os_debug() { - assert_eq!( - format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), - format!("{:?}", args_os()) - ); -} - -#[test] -fn vars_debug() { - assert_eq!( - format!("Vars {{ inner: {:?} }}", vars().collect::>()), - format!("{:?}", vars()) - ); -} - -#[test] -fn vars_os_debug() { - assert_eq!( - format!("VarsOs {{ inner: {:?} }}", vars_os().collect::>()), - format!("{:?}", vars_os()) - ); -} diff --git a/std/tests/env.rs b/std/tests/env.rs index 44fe84c989fb7..688c326a26aae 100644 --- a/std/tests/env.rs +++ b/std/tests/env.rs @@ -1,5 +1,6 @@ use std::env::*; use std::ffi::{OsStr, OsString}; +use std::path::Path; use rand::distributions::{Alphanumeric, DistString}; @@ -161,3 +162,122 @@ fn test_env_get_set_multithreaded() { let _ = getter.join(); let _ = setter.join(); } + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)] +fn test_self_exe_path() { + let path = current_exe(); + assert!(path.is_ok()); + let path = path.unwrap(); + + // Hard to test this function + assert!(path.is_absolute()); +} + +#[test] +fn test() { + assert!((!Path::new("test-path").is_absolute())); + + #[cfg(not(target_env = "sgx"))] + current_dir().unwrap(); +} + +#[test] +#[cfg(windows)] +fn split_paths_windows() { + use std::path::PathBuf; + + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() + == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse(r#""""#, &mut [""])); + assert!(check_parse(";;", &mut ["", "", ""])); + assert!(check_parse(r"c:\", &mut [r"c:\"])); + assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); + assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"])); + assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); + assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); +} + +#[test] +#[cfg(unix)] +fn split_paths_unix() { + use std::path::PathBuf; + + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() + == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse("::", &mut ["", "", ""])); + assert!(check_parse("/", &mut ["/"])); + assert!(check_parse("/:", &mut ["/", ""])); + assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); +} + +#[test] +#[cfg(unix)] +fn join_paths_unix() { + use std::ffi::OsStr; + + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin")); + assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); + assert!(join_paths(["/te:st"].iter().cloned()).is_err()); +} + +#[test] +#[cfg(windows)] +fn join_paths_windows() { + use std::ffi::OsStr; + + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\")); + assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;")); + assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); + assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); +} + +#[test] +fn args_debug() { + assert_eq!( + format!("Args {{ inner: {:?} }}", args().collect::>()), + format!("{:?}", args()) + ); +} + +#[test] +fn args_os_debug() { + assert_eq!( + format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), + format!("{:?}", args_os()) + ); +} + +#[test] +fn vars_debug() { + assert_eq!( + format!("Vars {{ inner: {:?} }}", vars().collect::>()), + format!("{:?}", vars()) + ); +} + +#[test] +fn vars_os_debug() { + assert_eq!( + format!("VarsOs {{ inner: {:?} }}", vars_os().collect::>()), + format!("{:?}", vars_os()) + ); +} From 966746d03eacf66a0cc25a9140ee67bfaf0fa8fc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:23:31 +0000 Subject: [PATCH 421/481] Move std::error unit tests to integration tests --- std/src/error.rs | 3 --- std/{src/error/tests.rs => tests/error.rs} | 10 ++++------ 2 files changed, 4 insertions(+), 9 deletions(-) rename std/{src/error/tests.rs => tests/error.rs} (98%) diff --git a/std/src/error.rs b/std/src/error.rs index b3e63aaf1c567..def5f984c88e4 100644 --- a/std/src/error.rs +++ b/std/src/error.rs @@ -1,9 +1,6 @@ #![doc = include_str!("../../core/src/error.md")] #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(test)] -mod tests; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::error::Error; #[unstable(feature = "error_generic_member_access", issue = "99301")] diff --git a/std/src/error/tests.rs b/std/tests/error.rs similarity index 98% rename from std/src/error/tests.rs rename to std/tests/error.rs index 88a9f33c07908..8fd6eb3c02065 100644 --- a/std/src/error/tests.rs +++ b/std/tests/error.rs @@ -1,7 +1,8 @@ -use core::error::Request; +#![feature(error_generic_member_access, error_reporter)] -use super::Error; -use crate::fmt; +use std::backtrace::Backtrace; +use std::error::{Error, Report, Request}; +use std::fmt; #[derive(Debug, PartialEq)] struct A; @@ -38,9 +39,6 @@ fn downcasting() { } } -use crate::backtrace::Backtrace; -use crate::error::Report; - #[derive(Debug)] struct SuperError { source: SuperErrorSideKick, From ddd6042d740f31446a763defc9d4b842ceed80c7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:36:11 +0000 Subject: [PATCH 422/481] Move std float unit tests to integration tests --- std/Cargo.toml | 4 ++ std/src/f128.rs | 3 -- std/src/f16.rs | 3 -- std/src/f32.rs | 3 -- std/src/f64.rs | 3 -- std/src/macros.rs | 15 ------- std/src/num.rs | 25 ----------- .../f128/tests.rs => tests/floats/f128.rs} | 10 ++--- std/{src/f16/tests.rs => tests/floats/f16.rs} | 7 ++-- std/{src/f32/tests.rs => tests/floats/f32.rs} | 8 ++-- std/{src/f64/tests.rs => tests/floats/f64.rs} | 7 ++-- std/tests/floats/lib.rs | 42 +++++++++++++++++++ 12 files changed, 59 insertions(+), 71 deletions(-) rename std/{src/f128/tests.rs => tests/floats/f128.rs} (99%) rename std/{src/f16/tests.rs => tests/floats/f16.rs} (99%) rename std/{src/f32/tests.rs => tests/floats/f32.rs} (99%) rename std/{src/f64/tests.rs => tests/floats/f64.rs} (99%) create mode 100644 std/tests/floats/lib.rs diff --git a/std/Cargo.toml b/std/Cargo.toml index 9eab75b06961f..8c407198ec3f3 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -130,6 +130,10 @@ name = "pipe-subprocess" path = "tests/pipe_subprocess.rs" harness = false +[[test]] +name = "floats" +path = "tests/floats/lib.rs" + [[bench]] name = "stdbenches" path = "benches/lib.rs" diff --git a/std/src/f128.rs b/std/src/f128.rs index d65f5ed61cfbc..89612fa747551 100644 --- a/std/src/f128.rs +++ b/std/src/f128.rs @@ -4,9 +4,6 @@ //! //! Mathematically significant numbers are provided in the `consts` sub-module. -#[cfg(test)] -mod tests; - #[unstable(feature = "f128", issue = "116909")] pub use core::f128::consts; diff --git a/std/src/f16.rs b/std/src/f16.rs index 5b0903bceabb4..cc523c93b4de7 100644 --- a/std/src/f16.rs +++ b/std/src/f16.rs @@ -4,9 +4,6 @@ //! //! Mathematically significant numbers are provided in the `consts` sub-module. -#[cfg(test)] -mod tests; - #[unstable(feature = "f16", issue = "116909")] pub use core::f16::consts; diff --git a/std/src/f32.rs b/std/src/f32.rs index f9b6723788ae3..260c499b7f4b9 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -12,9 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(test)] -mod tests; - #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::f32::{ diff --git a/std/src/f64.rs b/std/src/f64.rs index 0de55a15d48e8..7af646f8cfd60 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -12,9 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(test)] -mod tests; - #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::f64::{ diff --git a/std/src/macros.rs b/std/src/macros.rs index 1b0d7f3dbf2c9..e0f9f0bb5cee4 100644 --- a/std/src/macros.rs +++ b/std/src/macros.rs @@ -372,18 +372,3 @@ macro_rules! dbg { ($($crate::dbg!($val)),+,) }; } - -/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. -#[cfg(test)] -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; - ($a:expr, $b:expr, $lim:expr) => {{ - let (a, b) = (&$a, &$b); - let diff = (*a - *b).abs(); - assert!( - diff < $lim, - "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", - lim = $lim - ); - }}; -} diff --git a/std/src/num.rs b/std/src/num.rs index d2f679e7dde54..dd76081532f55 100644 --- a/std/src/num.rs +++ b/std/src/num.rs @@ -29,28 +29,3 @@ pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError} pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize}; #[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; - -#[cfg(test)] -use crate::fmt; -#[cfg(test)] -use crate::ops::{Add, Div, Mul, Rem, Sub}; - -/// Helper function for testing numeric operations -#[cfg(test)] -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} diff --git a/std/src/f128/tests.rs b/std/tests/floats/f128.rs similarity index 99% rename from std/src/f128/tests.rs rename to std/tests/floats/f128.rs index cbcf9f96239bb..d0e8b157e6b6f 100644 --- a/std/src/f128/tests.rs +++ b/std/tests/floats/f128.rs @@ -1,11 +1,11 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(reliable_f128)] -use crate::f128::consts; -use crate::num::FpCategory as Fp; +use std::f128::consts; +use std::num::FpCategory as Fp; #[cfg(reliable_f128_math)] -use crate::ops::Rem; -use crate::ops::{Add, Div, Mul, Sub}; +use std::ops::Rem; +use std::ops::{Add, Div, Mul, Sub}; // Note these tolerances make sense around zero, but not for more extreme exponents. @@ -762,8 +762,6 @@ fn test_ln_gamma() { #[test] fn test_real_consts() { - use super::consts; - let pi: f128 = consts::PI; let frac_pi_2: f128 = consts::FRAC_PI_2; let frac_pi_3: f128 = consts::FRAC_PI_3; diff --git a/std/src/f16/tests.rs b/std/tests/floats/f16.rs similarity index 99% rename from std/src/f16/tests.rs rename to std/tests/floats/f16.rs index 684ee3f3855b8..5180f3d40f3a7 100644 --- a/std/src/f16/tests.rs +++ b/std/tests/floats/f16.rs @@ -1,8 +1,8 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(reliable_f16)] -use crate::f16::consts; -use crate::num::{FpCategory as Fp, *}; +use std::f16::consts; +use std::num::FpCategory as Fp; /// Tolerance for results on the order of 10.0e-2 #[allow(unused)] @@ -54,7 +54,7 @@ macro_rules! assert_f16_biteq { #[test] fn test_num_f16() { - test_num(10f16, 2f16); + crate::test_num(10f16, 2f16); } #[test] @@ -734,7 +734,6 @@ fn test_ln_gamma() { #[test] fn test_real_consts() { // FIXME(f16_f128): add math tests when available - use super::consts; let pi: f16 = consts::PI; let frac_pi_2: f16 = consts::FRAC_PI_2; diff --git a/std/src/f32/tests.rs b/std/tests/floats/f32.rs similarity index 99% rename from std/src/f32/tests.rs rename to std/tests/floats/f32.rs index 99cfcfb231dad..bf7641986ada8 100644 --- a/std/src/f32/tests.rs +++ b/std/tests/floats/f32.rs @@ -1,5 +1,5 @@ -use crate::f32::consts; -use crate::num::{FpCategory as Fp, *}; +use std::f32::consts; +use std::num::FpCategory as Fp; /// Smallest number const TINY_BITS: u32 = 0x1; @@ -35,7 +35,7 @@ macro_rules! assert_f32_biteq { #[test] fn test_num_f32() { - test_num(10f32, 2f32); + crate::test_num(10f32, 2f32); } #[test] @@ -700,8 +700,6 @@ fn test_ln_gamma() { #[test] fn test_real_consts() { - use super::consts; - let pi: f32 = consts::PI; let frac_pi_2: f32 = consts::FRAC_PI_2; let frac_pi_3: f32 = consts::FRAC_PI_3; diff --git a/std/src/f64/tests.rs b/std/tests/floats/f64.rs similarity index 99% rename from std/src/f64/tests.rs rename to std/tests/floats/f64.rs index f5ba2c7b594e9..cbbfcd15efd26 100644 --- a/std/src/f64/tests.rs +++ b/std/tests/floats/f64.rs @@ -1,5 +1,5 @@ -use crate::f64::consts; -use crate::num::{FpCategory as Fp, *}; +use std::f64::consts; +use std::num::FpCategory as Fp; /// Smallest number const TINY_BITS: u64 = 0x1; @@ -35,7 +35,7 @@ macro_rules! assert_f64_biteq { #[test] fn test_num_f64() { - test_num(10f64, 2f64); + crate::test_num(10f64, 2f64); } #[test] @@ -680,7 +680,6 @@ fn test_ln_gamma() { #[test] fn test_real_consts() { - use super::consts; let pi: f64 = consts::PI; let frac_pi_2: f64 = consts::FRAC_PI_2; let frac_pi_3: f64 = consts::FRAC_PI_3; diff --git a/std/tests/floats/lib.rs b/std/tests/floats/lib.rs new file mode 100644 index 0000000000000..79813871ed940 --- /dev/null +++ b/std/tests/floats/lib.rs @@ -0,0 +1,42 @@ +#![feature(f16, f128, float_gamma, float_next_up_down, float_minimum_maximum)] + +use std::fmt; +use std::ops::{Add, Div, Mul, Rem, Sub}; + +/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!( + diff < $lim, + "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", + lim = $lim + ); + }}; +} + +/// Helper function for testing numeric operations +pub fn test_num(ten: T, two: T) +where + T: PartialEq + + Add + + Sub + + Mul + + Div + + Rem + + fmt::Debug + + Copy, +{ + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); +} + +mod f128; +mod f16; +mod f32; +mod f64; From 7f5116b292387b5635bdcc021b0ebd86c90ec9b0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:37:50 +0000 Subject: [PATCH 423/481] Move std::num unit tests to integration tests --- std/src/num.rs | 3 --- std/{src/num/tests.rs => tests/num.rs} | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) rename std/{src/num/tests.rs => tests/num.rs} (98%) diff --git a/std/src/num.rs b/std/src/num.rs index dd76081532f55..ffb8789c906ef 100644 --- a/std/src/num.rs +++ b/std/src/num.rs @@ -6,9 +6,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(test)] -mod tests; - #[stable(feature = "int_error_matching", since = "1.55.0")] pub use core::num::IntErrorKind; #[stable(feature = "generic_nonzero", since = "1.79.0")] diff --git a/std/src/num/tests.rs b/std/tests/num.rs similarity index 98% rename from std/src/num/tests.rs rename to std/tests/num.rs index df0df3f23f756..a7400f1c02df0 100644 --- a/std/src/num/tests.rs +++ b/std/tests/num.rs @@ -1,4 +1,4 @@ -use crate::ops::Mul; +use std::ops::Mul; #[test] fn test_saturating_add_uint() { @@ -190,8 +190,8 @@ fn test_uint_to_str_overflow() { assert_eq!(u64_val.to_string(), "0"); } -fn from_str(t: &str) -> Option { - crate::str::FromStr::from_str(t).ok() +fn from_str(t: &str) -> Option { + std::str::FromStr::from_str(t).ok() } #[test] From 4f93a9bc26eb3f5936c73f2a779cad4ec4b4e3a6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:39:09 +0000 Subject: [PATCH 424/481] Move std::panic unit tests to integration tests --- std/src/panic.rs | 3 --- std/{src/panic/tests.rs => tests/panic.rs} | 8 ++++---- 2 files changed, 4 insertions(+), 7 deletions(-) rename std/{src/panic/tests.rs => tests/panic.rs} (89%) diff --git a/std/src/panic.rs b/std/src/panic.rs index d649357a56d71..153189b8b0315 100644 --- a/std/src/panic.rs +++ b/std/src/panic.rs @@ -529,6 +529,3 @@ pub fn get_backtrace_style() -> Option { Err(new) => BacktraceStyle::from_u8(new), } } - -#[cfg(test)] -mod tests; diff --git a/std/src/panic/tests.rs b/std/tests/panic.rs similarity index 89% rename from std/src/panic/tests.rs rename to std/tests/panic.rs index b37d74011cc67..f13b931dd222e 100644 --- a/std/src/panic/tests.rs +++ b/std/tests/panic.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] -use crate::cell::RefCell; -use crate::panic::{AssertUnwindSafe, UnwindSafe}; -use crate::rc::Rc; -use crate::sync::{Arc, Mutex, RwLock}; +use std::cell::RefCell; +use std::panic::{AssertUnwindSafe, UnwindSafe}; +use std::rc::Rc; +use std::sync::{Arc, Mutex, RwLock}; struct Foo { a: i32, From d4ef07a08d1ecf299eb813206f90935571f3d3d4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:46:15 +0000 Subject: [PATCH 425/481] Move std::path unit tests to integration tests --- std/benches/lib.rs | 1 + std/benches/path.rs | 114 +++++++++++++++++ std/src/path.rs | 3 - std/{src/path/tests.rs => tests/path.rs} | 149 ++++------------------- 4 files changed, 139 insertions(+), 128 deletions(-) create mode 100644 std/benches/path.rs rename std/{src/path/tests.rs => tests/path.rs} (93%) diff --git a/std/benches/lib.rs b/std/benches/lib.rs index 1b21c230a0bf2..ae000d24d2816 100644 --- a/std/benches/lib.rs +++ b/std/benches/lib.rs @@ -5,3 +5,4 @@ extern crate test; mod hash; +mod path; diff --git a/std/benches/path.rs b/std/benches/path.rs new file mode 100644 index 0000000000000..094c00894a8ee --- /dev/null +++ b/std/benches/path.rs @@ -0,0 +1,114 @@ +use core::hint::black_box; +use std::collections::{BTreeSet, HashSet}; +use std::hash::{DefaultHasher, Hash, Hasher}; +use std::path::*; + +#[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... +fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { + let prefix = "my/home"; + let mut paths: Vec<_> = + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); + + paths.sort(); + + b.iter(|| { + black_box(paths.as_mut_slice()).sort_unstable(); + }); +} + +#[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... +fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { + let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; + let paths: Vec<_> = + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); + + let mut set = BTreeSet::new(); + + paths.iter().for_each(|p| { + set.insert(p.as_path()); + }); + + b.iter(|| { + set.remove(paths[500].as_path()); + set.insert(paths[500].as_path()); + }); +} + +#[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... +fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { + let prefix = "my/home"; + let paths: Vec<_> = + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); + + let mut set = BTreeSet::new(); + + paths.iter().for_each(|p| { + set.insert(p.as_path()); + }); + + b.iter(|| { + set.remove(paths[500].as_path()); + set.insert(paths[500].as_path()); + }); +} + +#[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... +fn bench_path_hashset(b: &mut test::Bencher) { + let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; + let paths: Vec<_> = + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); + + let mut set = HashSet::new(); + + paths.iter().for_each(|p| { + set.insert(p.as_path()); + }); + + b.iter(|| { + set.remove(paths[500].as_path()); + set.insert(black_box(paths[500].as_path())) + }); +} + +#[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... +fn bench_path_hashset_miss(b: &mut test::Bencher) { + let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; + let paths: Vec<_> = + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); + + let mut set = HashSet::new(); + + paths.iter().for_each(|p| { + set.insert(p.as_path()); + }); + + let probe = PathBuf::from(prefix).join("other"); + + b.iter(|| set.remove(black_box(probe.as_path()))); +} + +#[bench] +fn bench_hash_path_short(b: &mut test::Bencher) { + let mut hasher = DefaultHasher::new(); + let path = Path::new("explorer.exe"); + + b.iter(|| black_box(path).hash(&mut hasher)); + + black_box(hasher.finish()); +} + +#[bench] +fn bench_hash_path_long(b: &mut test::Bencher) { + let mut hasher = DefaultHasher::new(); + let path = + Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff"); + + b.iter(|| black_box(path).hash(&mut hasher)); + + black_box(hasher.finish()); +} diff --git a/std/src/path.rs b/std/src/path.rs index 7fd08a97f1f20..97e17acadeac7 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -67,9 +67,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(test)] -mod tests; - use core::clone::CloneToUninit; use crate::borrow::{Borrow, Cow}; diff --git a/std/src/path/tests.rs b/std/tests/path.rs similarity index 93% rename from std/src/path/tests.rs rename to std/tests/path.rs index 3f96ac4672aff..978402b6fdaea 100644 --- a/std/src/path/tests.rs +++ b/std/tests/path.rs @@ -1,10 +1,19 @@ -use core::hint::black_box; - -use super::*; -use crate::collections::{BTreeSet, HashSet}; -use crate::hash::DefaultHasher; -use crate::mem::MaybeUninit; -use crate::ptr; +#![feature( + clone_to_uninit, + path_add_extension, + path_file_prefix, + maybe_uninit_slice, + os_string_pathbuf_leak +)] + +use std::clone::CloneToUninit; +use std::ffi::OsStr; +use std::hash::{DefaultHasher, Hash, Hasher}; +use std::mem::MaybeUninit; +use std::path::*; +use std::ptr; +use std::rc::Rc; +use std::sync::Arc; #[allow(unknown_lints, unused_macro_rules)] macro_rules! t ( @@ -110,7 +119,7 @@ macro_rules! t ( #[test] fn into() { - use crate::borrow::Cow; + use std::borrow::Cow; let static_path = Path::new("/home/foo"); let static_cow_path: Cow<'static, Path> = static_path.into(); @@ -1525,7 +1534,7 @@ pub fn test_with_added_extension() { #[test] fn test_eq_receivers() { - use crate::borrow::Cow; + use std::borrow::Cow; let borrowed: &Path = Path::new("foo/bar"); let mut owned: PathBuf = PathBuf::new(); @@ -1550,7 +1559,7 @@ fn test_eq_receivers() { #[test] pub fn test_compare() { - use crate::hash::{DefaultHasher, Hash, Hasher}; + use std::hash::{DefaultHasher, Hash, Hasher}; fn hash(t: T) -> u64 { let mut s = DefaultHasher::new(); @@ -1867,12 +1876,12 @@ fn test_ord() { #[test] #[cfg(any(unix, target_os = "wasi"))] fn test_unix_absolute() { - use crate::path::absolute; + use std::path::absolute; assert!(absolute("").is_err()); let relative = "a/b"; - let mut expected = crate::env::current_dir().unwrap(); + let mut expected = std::env::current_dir().unwrap(); expected.push(relative); assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str()); @@ -1888,7 +1897,7 @@ fn test_unix_absolute() { ); // Test leading `.` and `..` components - let curdir = crate::env::current_dir().unwrap(); + let curdir = std::env::current_dir().unwrap(); assert_eq!(absolute("./a").unwrap().as_os_str(), curdir.join("a").as_os_str()); assert_eq!(absolute("../a").unwrap().as_os_str(), curdir.join("../a").as_os_str()); // return /pwd/../a } @@ -1896,12 +1905,12 @@ fn test_unix_absolute() { #[test] #[cfg(windows)] fn test_windows_absolute() { - use crate::path::absolute; + use std::path::absolute; // An empty path is an error. assert!(absolute("").is_err()); let relative = r"a\b"; - let mut expected = crate::env::current_dir().unwrap(); + let mut expected = std::env::current_dir().unwrap(); expected.push(relative); assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str()); @@ -1953,116 +1962,6 @@ fn test_extension_path_sep_alternate() { assert_eq!(path, Path::new("path/to/file.d\\test")); } -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { - let prefix = "my/home"; - let mut paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - paths.sort(); - - b.iter(|| { - black_box(paths.as_mut_slice()).sort_unstable(); - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { - let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = BTreeSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - b.iter(|| { - set.remove(paths[500].as_path()); - set.insert(paths[500].as_path()); - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { - let prefix = "my/home"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = BTreeSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - b.iter(|| { - set.remove(paths[500].as_path()); - set.insert(paths[500].as_path()); - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_hashset(b: &mut test::Bencher) { - let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = HashSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - b.iter(|| { - set.remove(paths[500].as_path()); - set.insert(black_box(paths[500].as_path())) - }); -} - -#[bench] -#[cfg_attr(miri, ignore)] // Miri isn't fast... -fn bench_path_hashset_miss(b: &mut test::Bencher) { - let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; - let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); - - let mut set = HashSet::new(); - - paths.iter().for_each(|p| { - set.insert(p.as_path()); - }); - - let probe = PathBuf::from(prefix).join("other"); - - b.iter(|| set.remove(black_box(probe.as_path()))); -} - -#[bench] -fn bench_hash_path_short(b: &mut test::Bencher) { - let mut hasher = DefaultHasher::new(); - let path = Path::new("explorer.exe"); - - b.iter(|| black_box(path).hash(&mut hasher)); - - black_box(hasher.finish()); -} - -#[bench] -fn bench_hash_path_long(b: &mut test::Bencher) { - let mut hasher = DefaultHasher::new(); - let path = - Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff"); - - b.iter(|| black_box(path).hash(&mut hasher)); - - black_box(hasher.finish()); -} - #[test] fn clone_to_uninit() { let a = Path::new("hello.txt"); From 6b6ffdd90bde9cba935aa18b8ad9891165e336b9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:49:46 +0000 Subject: [PATCH 426/481] Move std::time unit tests to integration tests --- std/benches/lib.rs | 1 + std/benches/time.rs | 47 ++++++++++++++++++++ std/src/time.rs | 3 -- std/{src/time/tests.rs => tests/time.rs} | 55 +++--------------------- 4 files changed, 53 insertions(+), 53 deletions(-) create mode 100644 std/benches/time.rs rename std/{src/time/tests.rs => tests/time.rs} (81%) diff --git a/std/benches/lib.rs b/std/benches/lib.rs index ae000d24d2816..e749d9c0f7998 100644 --- a/std/benches/lib.rs +++ b/std/benches/lib.rs @@ -6,3 +6,4 @@ extern crate test; mod hash; mod path; +mod time; diff --git a/std/benches/time.rs b/std/benches/time.rs new file mode 100644 index 0000000000000..552481cad928a --- /dev/null +++ b/std/benches/time.rs @@ -0,0 +1,47 @@ +use std::time::Instant; + +#[cfg(not(target_arch = "wasm32"))] +use test::{Bencher, black_box}; + +macro_rules! bench_instant_threaded { + ($bench_name:ident, $thread_count:expr) => { + #[bench] + #[cfg(not(target_arch = "wasm32"))] + fn $bench_name(b: &mut Bencher) -> std::thread::Result<()> { + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; + + let running = Arc::new(AtomicBool::new(true)); + + let threads: Vec<_> = (0..$thread_count) + .map(|_| { + let flag = Arc::clone(&running); + std::thread::spawn(move || { + while flag.load(Ordering::Relaxed) { + black_box(Instant::now()); + } + }) + }) + .collect(); + + b.iter(|| { + let a = Instant::now(); + let b = Instant::now(); + assert!(b >= a); + }); + + running.store(false, Ordering::Relaxed); + + for t in threads { + t.join()?; + } + Ok(()) + } + }; +} + +bench_instant_threaded!(instant_contention_01_threads, 0); +bench_instant_threaded!(instant_contention_02_threads, 1); +bench_instant_threaded!(instant_contention_04_threads, 3); +bench_instant_threaded!(instant_contention_08_threads, 7); +bench_instant_threaded!(instant_contention_16_threads, 15); diff --git a/std/src/time.rs b/std/src/time.rs index 9f4f8a0d0880c..88b3e9e0ceba0 100644 --- a/std/src/time.rs +++ b/std/src/time.rs @@ -31,9 +31,6 @@ #![stable(feature = "time", since = "1.3.0")] -#[cfg(test)] -mod tests; - #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; #[stable(feature = "duration_checked_float", since = "1.66.0")] diff --git a/std/src/time/tests.rs b/std/tests/time.rs similarity index 81% rename from std/src/time/tests.rs rename to std/tests/time.rs index e88f2d5e80676..40709eae37cfc 100644 --- a/std/src/time/tests.rs +++ b/std/tests/time.rs @@ -1,9 +1,7 @@ -use core::fmt::Debug; +#![feature(duration_constants)] -#[cfg(not(target_arch = "wasm32"))] -use test::{Bencher, black_box}; - -use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; +use std::fmt::Debug; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; macro_rules! assert_almost_eq { ($a:expr, $b:expr) => {{ @@ -29,10 +27,10 @@ fn instant_monotonic() { #[test] #[cfg(not(target_arch = "wasm32"))] -fn instant_monotonic_concurrent() -> crate::thread::Result<()> { +fn instant_monotonic_concurrent() -> std::thread::Result<()> { let threads: Vec<_> = (0..8) .map(|_| { - crate::thread::spawn(|| { + std::thread::spawn(|| { let mut old = Instant::now(); let count = if cfg!(miri) { 1_000 } else { 5_000_000 }; for _ in 0..count { @@ -229,46 +227,3 @@ fn big_math() { check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub); check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub); } - -macro_rules! bench_instant_threaded { - ($bench_name:ident, $thread_count:expr) => { - #[bench] - #[cfg(not(target_arch = "wasm32"))] - fn $bench_name(b: &mut Bencher) -> crate::thread::Result<()> { - use crate::sync::Arc; - use crate::sync::atomic::{AtomicBool, Ordering}; - - let running = Arc::new(AtomicBool::new(true)); - - let threads: Vec<_> = (0..$thread_count) - .map(|_| { - let flag = Arc::clone(&running); - crate::thread::spawn(move || { - while flag.load(Ordering::Relaxed) { - black_box(Instant::now()); - } - }) - }) - .collect(); - - b.iter(|| { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - }); - - running.store(false, Ordering::Relaxed); - - for t in threads { - t.join()?; - } - Ok(()) - } - }; -} - -bench_instant_threaded!(instant_contention_01_threads, 0); -bench_instant_threaded!(instant_contention_02_threads, 1); -bench_instant_threaded!(instant_contention_04_threads, 3); -bench_instant_threaded!(instant_contention_08_threads, 7); -bench_instant_threaded!(instant_contention_16_threads, 15); From 5c1d6f6a1b7d770efd9357ed248cfc2e1add5ece Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:25:12 +0000 Subject: [PATCH 427/481] Move std::thread_local unit tests to integration tests --- std/Cargo.toml | 4 ++++ std/src/thread/local.rs | 6 ------ .../local => tests/thread_local}/dynamic_tests.rs | 6 +++--- std/tests/thread_local/lib.rs | 4 ++++ std/{src/thread/local => tests/thread_local}/tests.rs | 10 +++++----- 5 files changed, 16 insertions(+), 14 deletions(-) rename std/{src/thread/local => tests/thread_local}/dynamic_tests.rs (89%) create mode 100644 std/tests/thread_local/lib.rs rename std/{src/thread/local => tests/thread_local}/tests.rs (98%) diff --git a/std/Cargo.toml b/std/Cargo.toml index 8c407198ec3f3..445b37461c19e 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -134,6 +134,10 @@ harness = false name = "floats" path = "tests/floats/lib.rs" +[[test]] +name = "thread_local" +path = "tests/thread_local/lib.rs" + [[bench]] name = "stdbenches" path = "benches/lib.rs" diff --git a/std/src/thread/local.rs b/std/src/thread/local.rs index c003503ca8b09..ca04aa4ada497 100644 --- a/std/src/thread/local.rs +++ b/std/src/thread/local.rs @@ -2,12 +2,6 @@ #![unstable(feature = "thread_local_internals", issue = "none")] -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - -#[cfg(test)] -mod dynamic_tests; - use crate::cell::{Cell, RefCell}; use crate::error::Error; use crate::fmt; diff --git a/std/src/thread/local/dynamic_tests.rs b/std/tests/thread_local/dynamic_tests.rs similarity index 89% rename from std/src/thread/local/dynamic_tests.rs rename to std/tests/thread_local/dynamic_tests.rs index dd18004164824..454462b392510 100644 --- a/std/src/thread/local/dynamic_tests.rs +++ b/std/tests/thread_local/dynamic_tests.rs @@ -1,6 +1,6 @@ -use crate::cell::RefCell; -use crate::collections::HashMap; -use crate::thread_local; +use std::cell::RefCell; +use std::collections::HashMap; +use std::thread_local; #[test] fn smoke() { diff --git a/std/tests/thread_local/lib.rs b/std/tests/thread_local/lib.rs new file mode 100644 index 0000000000000..c52914354253c --- /dev/null +++ b/std/tests/thread_local/lib.rs @@ -0,0 +1,4 @@ +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod tests; + +mod dynamic_tests; diff --git a/std/src/thread/local/tests.rs b/std/tests/thread_local/tests.rs similarity index 98% rename from std/src/thread/local/tests.rs rename to std/tests/thread_local/tests.rs index 9d4f52a09218e..aa020c2559cc5 100644 --- a/std/src/thread/local/tests.rs +++ b/std/tests/thread_local/tests.rs @@ -1,8 +1,8 @@ -use crate::cell::{Cell, UnsafeCell}; -use crate::sync::atomic::{AtomicU8, Ordering}; -use crate::sync::{Arc, Condvar, Mutex}; -use crate::thread::{self, Builder, LocalKey}; -use crate::thread_local; +use std::cell::{Cell, UnsafeCell}; +use std::sync::atomic::{AtomicU8, Ordering}; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread::{self, Builder, LocalKey}; +use std::thread_local; #[derive(Clone, Default)] struct Signal(Arc<(Mutex, Condvar)>); From 6e786a8498294854f8394d0d2f3da7f2ed09a59a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:04:40 +0000 Subject: [PATCH 428/481] Move std::sync unit tests to integration tests This removes two minor OnceLock tests which test private methods. The rest of the tests should be more than enough to catch mistakes in those private methods. Also makes ReentrantLock::try_lock public. And finally it makes the mpmc tests actually run. --- std/Cargo.toml | 4 +++ std/src/sync/barrier.rs | 3 -- std/src/sync/lazy_lock.rs | 3 -- std/src/sync/{mpsc/mod.rs => mpsc.rs} | 13 +++----- std/src/sync/once_lock.rs | 3 -- std/src/sync/poison/condvar.rs | 3 -- std/src/sync/poison/mutex.rs | 3 -- std/src/sync/poison/once.rs | 3 -- std/src/sync/poison/rwlock.rs | 3 -- std/src/sync/reentrant_lock.rs | 8 ++--- .../tests.rs => tests/sync/barrier.rs} | 6 ++-- .../tests.rs => tests/sync/condvar.rs} | 10 +++--- .../tests.rs => tests/sync/lazy_lock.rs} | 12 +++---- std/tests/sync/lib.rs | 32 +++++++++++++++++++ .../sync/mpmc/tests.rs => tests/sync/mpmc.rs} | 5 +-- .../sync/mpsc/tests.rs => tests/sync/mpsc.rs} | 5 +-- .../sync_tests.rs => tests/sync/mpsc_sync.rs} | 9 +++--- .../mutex/tests.rs => tests/sync/mutex.rs} | 14 ++++---- .../once/tests.rs => tests/sync/once.rs} | 12 +++---- .../tests.rs => tests/sync/once_lock.rs} | 20 +++--------- .../tests.rs => tests/sync/reentrant_lock.rs} | 7 ++-- .../rwlock/tests.rs => tests/sync/rwlock.rs} | 22 ++++++------- 22 files changed, 101 insertions(+), 99 deletions(-) rename std/src/sync/{mpsc/mod.rs => mpsc.rs} (99%) rename std/{src/sync/barrier/tests.rs => tests/sync/barrier.rs} (89%) rename std/{src/sync/poison/condvar/tests.rs => tests/sync/condvar.rs} (97%) rename std/{src/sync/lazy_lock/tests.rs => tests/sync/lazy_lock.rs} (93%) create mode 100644 std/tests/sync/lib.rs rename std/{src/sync/mpmc/tests.rs => tests/sync/mpmc.rs} (99%) rename std/{src/sync/mpsc/tests.rs => tests/sync/mpsc.rs} (99%) rename std/{src/sync/mpsc/sync_tests.rs => tests/sync/mpsc_sync.rs} (99%) rename std/{src/sync/poison/mutex/tests.rs => tests/sync/mutex.rs} (97%) rename std/{src/sync/poison/once/tests.rs => tests/sync/once.rs} (94%) rename std/{src/sync/once_lock/tests.rs => tests/sync/once_lock.rs} (92%) rename std/{src/sync/reentrant_lock/tests.rs => tests/sync/reentrant_lock.rs} (91%) rename std/{src/sync/poison/rwlock/tests.rs => tests/sync/rwlock.rs} (98%) diff --git a/std/Cargo.toml b/std/Cargo.toml index 445b37461c19e..be2ea7fb19382 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -130,6 +130,10 @@ name = "pipe-subprocess" path = "tests/pipe_subprocess.rs" harness = false +[[test]] +name = "sync" +path = "tests/sync/lib.rs" + [[test]] name = "floats" path = "tests/floats/lib.rs" diff --git a/std/src/sync/barrier.rs b/std/src/sync/barrier.rs index 862753e4765dc..067ff66d9af73 100644 --- a/std/src/sync/barrier.rs +++ b/std/src/sync/barrier.rs @@ -1,6 +1,3 @@ -#[cfg(test)] -mod tests; - use crate::fmt; // FIXME(nonpoison_mutex,nonpoison_condvar): switch to nonpoison versions once they are available use crate::sync::{Condvar, Mutex}; diff --git a/std/src/sync/lazy_lock.rs b/std/src/sync/lazy_lock.rs index 98c83d8d326ca..78cf8841efefb 100644 --- a/std/src/sync/lazy_lock.rs +++ b/std/src/sync/lazy_lock.rs @@ -350,6 +350,3 @@ unsafe impl Sync for LazyLock {} impl RefUnwindSafe for LazyLock {} #[stable(feature = "lazy_cell", since = "1.80.0")] impl UnwindSafe for LazyLock {} - -#[cfg(test)] -mod tests; diff --git a/std/src/sync/mpsc/mod.rs b/std/src/sync/mpsc.rs similarity index 99% rename from std/src/sync/mpsc/mod.rs rename to std/src/sync/mpsc.rs index c86b546e01169..f942937c14d11 100644 --- a/std/src/sync/mpsc/mod.rs +++ b/std/src/sync/mpsc.rs @@ -137,12 +137,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod sync_tests; - // MPSC channels are built as a wrapper around MPMC channels, which // were ported from the `crossbeam-channel` crate. MPMC channels are // not exposed publicly, but if you are curious about the implementation, @@ -737,9 +731,10 @@ impl SyncSender { // Attempts to send for a value on this receiver, returning an error if the // corresponding channel has hung up, or if it waits more than `timeout`. // - // This method is currently private and only used for tests. - #[allow(unused)] - fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError> { + // This method is currently only used for tests. + #[unstable(issue = "none", feature = "std_internals")] + #[doc(hidden)] + pub fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError> { self.inner.send_timeout(t, timeout) } } diff --git a/std/src/sync/once_lock.rs b/std/src/sync/once_lock.rs index 8f769f2dca37e..21e6b65a744f8 100644 --- a/std/src/sync/once_lock.rs +++ b/std/src/sync/once_lock.rs @@ -681,6 +681,3 @@ unsafe impl<#[may_dangle] T> Drop for OnceLock { } } } - -#[cfg(test)] -mod tests; diff --git a/std/src/sync/poison/condvar.rs b/std/src/sync/poison/condvar.rs index a6e2389c93baf..7f0f3f652bcb7 100644 --- a/std/src/sync/poison/condvar.rs +++ b/std/src/sync/poison/condvar.rs @@ -1,6 +1,3 @@ -#[cfg(test)] -mod tests; - use crate::fmt; use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex}; use crate::sys::sync as sys; diff --git a/std/src/sync/poison/mutex.rs b/std/src/sync/poison/mutex.rs index fb43ada637543..9362c764173a8 100644 --- a/std/src/sync/poison/mutex.rs +++ b/std/src/sync/poison/mutex.rs @@ -1,6 +1,3 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; diff --git a/std/src/sync/poison/once.rs b/std/src/sync/poison/once.rs index 528b11ca0c1e6..d2938b7a0c12e 100644 --- a/std/src/sync/poison/once.rs +++ b/std/src/sync/poison/once.rs @@ -3,9 +3,6 @@ //! This primitive is meant to be used to run one-time initialization. An //! example use case would be for initializing an FFI library. -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; diff --git a/std/src/sync/poison/rwlock.rs b/std/src/sync/poison/rwlock.rs index 1519baf99a8fd..f9d9321f5f2d8 100644 --- a/std/src/sync/poison/rwlock.rs +++ b/std/src/sync/poison/rwlock.rs @@ -1,6 +1,3 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; diff --git a/std/src/sync/reentrant_lock.rs b/std/src/sync/reentrant_lock.rs index 0140e0d21299f..e009eb410efc0 100644 --- a/std/src/sync/reentrant_lock.rs +++ b/std/src/sync/reentrant_lock.rs @@ -1,6 +1,3 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] -mod tests; - use cfg_if::cfg_if; use crate::cell::UnsafeCell; @@ -324,7 +321,10 @@ impl ReentrantLock { /// Otherwise, an RAII guard is returned. /// /// This function does not block. - pub(crate) fn try_lock(&self) -> Option> { + // FIXME maybe make it a public part of the API? + #[unstable(issue = "none", feature = "std_internals")] + #[doc(hidden)] + pub fn try_lock(&self) -> Option> { let this_thread = current_id(); // Safety: We only touch lock_count when we own the inner mutex. // Additionally, we only call `self.owner.set()` while holding diff --git a/std/src/sync/barrier/tests.rs b/std/tests/sync/barrier.rs similarity index 89% rename from std/src/sync/barrier/tests.rs rename to std/tests/sync/barrier.rs index 0fbcd9988127b..8aefff9d5071c 100644 --- a/std/src/sync/barrier/tests.rs +++ b/std/tests/sync/barrier.rs @@ -1,6 +1,6 @@ -use crate::sync::mpsc::{TryRecvError, channel}; -use crate::sync::{Arc, Barrier}; -use crate::thread; +use std::sync::mpsc::{TryRecvError, channel}; +use std::sync::{Arc, Barrier}; +use std::thread; #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads diff --git a/std/src/sync/poison/condvar/tests.rs b/std/tests/sync/condvar.rs similarity index 97% rename from std/src/sync/poison/condvar/tests.rs rename to std/tests/sync/condvar.rs index f9e9066bc92a2..834de6bb1c295 100644 --- a/std/src/sync/poison/condvar/tests.rs +++ b/std/tests/sync/condvar.rs @@ -1,8 +1,8 @@ -use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sync::mpsc::channel; -use crate::sync::{Arc, Condvar, Mutex}; -use crate::thread; -use crate::time::Duration; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::channel; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; +use std::time::Duration; #[test] fn smoke() { diff --git a/std/src/sync/lazy_lock/tests.rs b/std/tests/sync/lazy_lock.rs similarity index 93% rename from std/src/sync/lazy_lock/tests.rs rename to std/tests/sync/lazy_lock.rs index 7d7dde5434990..6c14b79f2ce7c 100644 --- a/std/src/sync/lazy_lock/tests.rs +++ b/std/tests/sync/lazy_lock.rs @@ -1,8 +1,8 @@ -use crate::cell::LazyCell; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sync::{LazyLock, Mutex, OnceLock}; -use crate::{panic, thread}; +use std::cell::LazyCell; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; +use std::sync::{LazyLock, Mutex, OnceLock}; +use std::{panic, thread}; fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { thread::spawn(f).join().unwrap() @@ -149,7 +149,7 @@ fn is_sync_send() { #[should_panic = "has previously been poisoned"] fn lazy_force_mut_panic() { let mut lazy = LazyLock::::new(|| panic!()); - crate::panic::catch_unwind(crate::panic::AssertUnwindSafe(|| { + panic::catch_unwind(panic::AssertUnwindSafe(|| { let _ = LazyLock::force_mut(&mut lazy); })) .unwrap_err(); diff --git a/std/tests/sync/lib.rs b/std/tests/sync/lib.rs new file mode 100644 index 0000000000000..6bf320d52f21a --- /dev/null +++ b/std/tests/sync/lib.rs @@ -0,0 +1,32 @@ +#![feature(lazy_get)] +#![feature(mapped_lock_guards)] +#![feature(mpmc_channel)] +#![feature(once_cell_try)] +#![feature(once_wait)] +#![feature(lock_value_accessors)] +#![feature(reentrant_lock)] +#![feature(rwlock_downgrade)] +#![feature(std_internals)] +#![allow(internal_features)] + +mod barrier; +mod condvar; +mod lazy_lock; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod mpmc; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod mpsc; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod mpsc_sync; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod mutex; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod once; +mod once_lock; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod reentrant_lock; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod rwlock; + +#[path = "../common/mod.rs"] +mod common; diff --git a/std/src/sync/mpmc/tests.rs b/std/tests/sync/mpmc.rs similarity index 99% rename from std/src/sync/mpmc/tests.rs rename to std/tests/sync/mpmc.rs index ab14050df6c98..81b92297f76a3 100644 --- a/std/src/sync/mpmc/tests.rs +++ b/std/tests/sync/mpmc.rs @@ -1,5 +1,6 @@ -use super::*; -use crate::{env, thread}; +use std::sync::mpmc::*; +use std::time::{Duration, Instant}; +use std::{env, thread}; pub fn stress_factor() -> usize { match env::var("RUST_TEST_STRESS") { diff --git a/std/src/sync/mpsc/tests.rs b/std/tests/sync/mpsc.rs similarity index 99% rename from std/src/sync/mpsc/tests.rs rename to std/tests/sync/mpsc.rs index 13892fa0d18e4..1d8edfde44bed 100644 --- a/std/src/sync/mpsc/tests.rs +++ b/std/tests/sync/mpsc.rs @@ -1,5 +1,6 @@ -use super::*; -use crate::{env, thread}; +use std::sync::mpsc::*; +use std::time::{Duration, Instant}; +use std::{env, thread}; pub fn stress_factor() -> usize { match env::var("RUST_TEST_STRESS") { diff --git a/std/src/sync/mpsc/sync_tests.rs b/std/tests/sync/mpsc_sync.rs similarity index 99% rename from std/src/sync/mpsc/sync_tests.rs rename to std/tests/sync/mpsc_sync.rs index 49b65c8efe692..a7f326d201b00 100644 --- a/std/src/sync/mpsc/sync_tests.rs +++ b/std/tests/sync/mpsc_sync.rs @@ -1,7 +1,8 @@ -use super::*; -use crate::rc::Rc; -use crate::sync::mpmc::SendTimeoutError; -use crate::{env, thread}; +use std::rc::Rc; +use std::sync::mpmc::SendTimeoutError; +use std::sync::mpsc::*; +use std::time::Duration; +use std::{env, thread}; pub fn stress_factor() -> usize { match env::var("RUST_TEST_STRESS") { diff --git a/std/src/sync/poison/mutex/tests.rs b/std/tests/sync/mutex.rs similarity index 97% rename from std/src/sync/poison/mutex/tests.rs rename to std/tests/sync/mutex.rs index 395c8aada089a..74c627201073e 100644 --- a/std/src/sync/poison/mutex/tests.rs +++ b/std/tests/sync/mutex.rs @@ -1,10 +1,10 @@ -use crate::fmt::Debug; -use crate::ops::FnMut; -use crate::panic::{self, AssertUnwindSafe}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sync::mpsc::channel; -use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError}; -use crate::{hint, mem, thread}; +use std::fmt::Debug; +use std::ops::FnMut; +use std::panic::{self, AssertUnwindSafe}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::mpsc::channel; +use std::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError}; +use std::{hint, mem, thread}; struct Packet(Arc<(Mutex, Condvar)>); diff --git a/std/src/sync/poison/once/tests.rs b/std/tests/sync/once.rs similarity index 94% rename from std/src/sync/poison/once/tests.rs rename to std/tests/sync/once.rs index ce96468aeb6e1..a3ffc73fe06b9 100644 --- a/std/src/sync/poison/once/tests.rs +++ b/std/tests/sync/once.rs @@ -1,9 +1,9 @@ -use super::Once; -use crate::sync::atomic::AtomicBool; -use crate::sync::atomic::Ordering::Relaxed; -use crate::sync::mpsc::channel; -use crate::time::Duration; -use crate::{panic, thread}; +use std::sync::Once; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::mpsc::channel; +use std::time::Duration; +use std::{panic, thread}; #[test] fn smoke_once() { diff --git a/std/src/sync/once_lock/tests.rs b/std/tests/sync/once_lock.rs similarity index 92% rename from std/src/sync/once_lock/tests.rs rename to std/tests/sync/once_lock.rs index 5113d436c3c99..1ce273b5a7a40 100644 --- a/std/src/sync/once_lock/tests.rs +++ b/std/tests/sync/once_lock.rs @@ -1,8 +1,8 @@ -use crate::sync::OnceLock; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sync::mpsc::channel; -use crate::{panic, thread}; +use std::sync::OnceLock; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; +use std::sync::mpsc::channel; +use std::{panic, thread}; fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { thread::spawn(f).join().unwrap() @@ -33,15 +33,6 @@ fn sync_once_cell_get_mut() { assert_eq!(c.get_mut(), Some(&mut 92)); } -#[test] -fn sync_once_cell_get_unchecked() { - let c = OnceLock::new(); - c.set(92).unwrap(); - unsafe { - assert_eq!(c.get_unchecked(), &92); - } -} - #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_once_cell_drop() { @@ -88,7 +79,6 @@ fn get_or_try_init() { let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); assert!(res.is_err()); - assert!(!cell.is_initialized()); assert!(cell.get().is_none()); assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); diff --git a/std/src/sync/reentrant_lock/tests.rs b/std/tests/sync/reentrant_lock.rs similarity index 91% rename from std/src/sync/reentrant_lock/tests.rs rename to std/tests/sync/reentrant_lock.rs index aeef0289d28f8..2b7b87e36234a 100644 --- a/std/src/sync/reentrant_lock/tests.rs +++ b/std/tests/sync/reentrant_lock.rs @@ -1,7 +1,6 @@ -use super::ReentrantLock; -use crate::cell::RefCell; -use crate::sync::Arc; -use crate::thread; +use std::cell::RefCell; +use std::sync::{Arc, ReentrantLock}; +use std::thread; #[test] fn smoke() { diff --git a/std/src/sync/poison/rwlock/tests.rs b/std/tests/sync/rwlock.rs similarity index 98% rename from std/src/sync/poison/rwlock/tests.rs rename to std/tests/sync/rwlock.rs index 057c2f1a5d7a7..bd4bc7a14bc8e 100644 --- a/std/src/sync/poison/rwlock/tests.rs +++ b/std/tests/sync/rwlock.rs @@ -1,15 +1,15 @@ -use rand::Rng; - -use crate::fmt::Debug; -use crate::ops::FnMut; -use crate::panic::{self, AssertUnwindSafe}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sync::mpsc::channel; -use crate::sync::{ +use std::fmt::Debug; +use std::ops::FnMut; +use std::panic::{self, AssertUnwindSafe}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::mpsc::channel; +use std::sync::{ Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError, }; -use crate::{hint, mem, thread}; +use std::{hint, mem, thread}; + +use rand::Rng; #[derive(Eq, PartialEq, Debug)] struct NonCopy(i32); @@ -57,7 +57,7 @@ fn frob() { let tx = tx.clone(); let r = r.clone(); thread::spawn(move || { - let mut rng = crate::test_helpers::test_rng(); + let mut rng = crate::common::test_rng(); for _ in 0..M { if rng.gen_bool(1.0 / (N as f64)) { drop(r.write().unwrap()); @@ -704,7 +704,7 @@ fn test_downgrade_atomic() { // Wait for a good amount of time so that evil threads go to sleep. // Note: this is not strictly necessary... - let eternity = crate::time::Duration::from_millis(42); + let eternity = std::time::Duration::from_millis(42); thread::sleep(eternity); // Once everyone is asleep, set the value to `NEW_VALUE`. From 4664667a4112ef4ede92196c7c7693ce6c68d69f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Jan 2025 13:35:50 +0000 Subject: [PATCH 429/481] Fix benchmarking of libstd --- std/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/std/Cargo.toml b/std/Cargo.toml index be2ea7fb19382..944c34385572d 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "The Rust Standard Library" edition = "2021" +autobenches = false [lib] crate-type = ["dylib", "rlib"] From 6fd2540e2f27da61ffefada05ed8cc13e5475d75 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:23:19 +0000 Subject: [PATCH 430/481] Fix for SGX --- std/tests/sync/once_lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/tests/sync/once_lock.rs b/std/tests/sync/once_lock.rs index 1ce273b5a7a40..ac9aaa8892eff 100644 --- a/std/tests/sync/once_lock.rs +++ b/std/tests/sync/once_lock.rs @@ -164,7 +164,7 @@ fn sync_once_cell_does_not_leak_partially_constructed_boxes() { break; } #[cfg(target_env = "sgx")] - crate::thread::yield_now(); + std::thread::yield_now(); } }); } From a487707cef0dfc30bccde9283596bc63c48ffe69 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:29:05 +0000 Subject: [PATCH 431/481] Move env modifying tests to a separate integration test --- std/tests/env.rs | 160 -------------------------------------- std/tests/env_modify.rs | 166 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 160 deletions(-) create mode 100644 std/tests/env_modify.rs diff --git a/std/tests/env.rs b/std/tests/env.rs index 688c326a26aae..e754cf8263b0f 100644 --- a/std/tests/env.rs +++ b/std/tests/env.rs @@ -1,167 +1,7 @@ use std::env::*; -use std::ffi::{OsStr, OsString}; use std::path::Path; -use rand::distributions::{Alphanumeric, DistString}; - mod common; -use std::thread; - -use common::test_rng; - -#[track_caller] -fn make_rand_name() -> OsString { - let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10)); - let n = OsString::from(n); - assert!(var_os(&n).is_none()); - n -} - -fn eq(a: Option, b: Option<&str>) { - assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); -} - -#[test] -fn test_set_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - eq(var_os(&n), Some("VALUE")); -} - -#[test] -fn test_remove_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_set_var_overwrite() { - let n = make_rand_name(); - set_var(&n, "1"); - set_var(&n, "2"); - eq(var_os(&n), Some("2")); - set_var(&n, ""); - eq(var_os(&n), Some("")); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_var_big() { - let mut s = "".to_string(); - let mut i = 0; - while i < 100 { - s.push_str("aaaaaaaaaa"); - i += 1; - } - let n = make_rand_name(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_env_set_get_huge() { - let n = make_rand_name(); - let s = "x".repeat(10000); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_env_set_var() { - let n = make_rand_name(); - - let mut e = vars_os(); - set_var(&n, "VALUE"); - assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); - - assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); -} - -#[test] -#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))] -#[allow(deprecated)] -fn env_home_dir() { - use std::path::PathBuf; - - fn var_to_os_string(var: Result) -> Option { - match var { - Ok(var) => Some(OsString::from(var)), - Err(VarError::NotUnicode(var)) => Some(var), - _ => None, - } - } - - cfg_if::cfg_if! { - if #[cfg(unix)] { - let oldhome = var_to_os_string(var("HOME")); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - if cfg!(target_os = "android") { - assert!(home_dir().is_none()); - } else { - // When HOME is not set, some platforms return `None`, - // but others return `Some` with a default. - // Just check that it is not "/home/MountainView". - assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - } - - if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } - } else if #[cfg(windows)] { - let oldhome = var_to_os_string(var("HOME")); - let olduserprofile = var_to_os_string(var("USERPROFILE")); - - remove_var("HOME"); - remove_var("USERPROFILE"); - - assert!(home_dir().is_some()); - - set_var("HOME", "/home/PaloAlto"); - assert_ne!(home_dir(), Some(PathBuf::from("/home/PaloAlto")), "HOME must not be used"); - - set_var("USERPROFILE", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - set_var("USERPROFILE", ""); - assert_ne!(home_dir(), Some(PathBuf::from("")), "Empty USERPROFILE must be ignored"); - - remove_var("USERPROFILE"); - - if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } - if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); } - } - } -} - -#[test] // miri shouldn't detect any data race in this fn -#[cfg_attr(any(not(miri), target_os = "emscripten"), ignore)] -fn test_env_get_set_multithreaded() { - let getter = thread::spawn(|| { - for _ in 0..100 { - let _ = var_os("foo"); - } - }); - - let setter = thread::spawn(|| { - for _ in 0..100 { - set_var("foo", "bar"); - } - }); - - let _ = getter.join(); - let _ = setter.join(); -} #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)] diff --git a/std/tests/env_modify.rs b/std/tests/env_modify.rs new file mode 100644 index 0000000000000..6074744735005 --- /dev/null +++ b/std/tests/env_modify.rs @@ -0,0 +1,166 @@ +// These tests are in a separate integration test as they modify the environment, +// and would otherwise cause some other tests to fail. + +use std::env::*; +use std::ffi::{OsStr, OsString}; + +use rand::distributions::{Alphanumeric, DistString}; + +mod common; +use std::thread; + +use common::test_rng; + +#[track_caller] +fn make_rand_name() -> OsString { + let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10)); + let n = OsString::from(n); + assert!(var_os(&n).is_none()); + n +} + +fn eq(a: Option, b: Option<&str>) { + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); +} + +#[test] +fn test_set_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + eq(var_os(&n), Some("VALUE")); +} + +#[test] +fn test_remove_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_set_var_overwrite() { + let n = make_rand_name(); + set_var(&n, "1"); + set_var(&n, "2"); + eq(var_os(&n), Some("2")); + set_var(&n, ""); + eq(var_os(&n), Some("")); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_var_big() { + let mut s = "".to_string(); + let mut i = 0; + while i < 100 { + s.push_str("aaaaaaaaaa"); + i += 1; + } + let n = make_rand_name(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_env_set_get_huge() { + let n = make_rand_name(); + let s = "x".repeat(10000); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_env_set_var() { + let n = make_rand_name(); + + let mut e = vars_os(); + set_var(&n, "VALUE"); + assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); + + assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); +} + +#[test] +#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))] +#[allow(deprecated)] +fn env_home_dir() { + use std::path::PathBuf; + + fn var_to_os_string(var: Result) -> Option { + match var { + Ok(var) => Some(OsString::from(var)), + Err(VarError::NotUnicode(var)) => Some(var), + _ => None, + } + } + + cfg_if::cfg_if! { + if #[cfg(unix)] { + let oldhome = var_to_os_string(var("HOME")); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + if cfg!(target_os = "android") { + assert!(home_dir().is_none()); + } else { + // When HOME is not set, some platforms return `None`, + // but others return `Some` with a default. + // Just check that it is not "/home/MountainView". + assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + } + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + } else if #[cfg(windows)] { + let oldhome = var_to_os_string(var("HOME")); + let olduserprofile = var_to_os_string(var("USERPROFILE")); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + assert!(home_dir().is_some()); + + set_var("HOME", "/home/PaloAlto"); + assert_ne!(home_dir(), Some(PathBuf::from("/home/PaloAlto")), "HOME must not be used"); + + set_var("USERPROFILE", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + set_var("USERPROFILE", ""); + assert_ne!(home_dir(), Some(PathBuf::from("")), "Empty USERPROFILE must be ignored"); + + remove_var("USERPROFILE"); + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); } + } + } +} + +#[test] // miri shouldn't detect any data race in this fn +#[cfg_attr(any(not(miri), target_os = "emscripten"), ignore)] +fn test_env_get_set_multithreaded() { + let getter = thread::spawn(|| { + for _ in 0..100 { + let _ = var_os("foo"); + } + }); + + let setter = thread::spawn(|| { + for _ in 0..100 { + set_var("foo", "bar"); + } + }); + + let _ = getter.join(); + let _ = setter.join(); +} From 06f613416f32df3925eaf901c72d7dc04c70eddd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:54:18 +0000 Subject: [PATCH 432/481] Remove stabilized feature gate --- std/tests/floats/lib.rs | 2 +- std/tests/sync/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/std/tests/floats/lib.rs b/std/tests/floats/lib.rs index 79813871ed940..ad82f1a44e711 100644 --- a/std/tests/floats/lib.rs +++ b/std/tests/floats/lib.rs @@ -1,4 +1,4 @@ -#![feature(f16, f128, float_gamma, float_next_up_down, float_minimum_maximum)] +#![feature(f16, f128, float_gamma, float_minimum_maximum)] use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; diff --git a/std/tests/sync/lib.rs b/std/tests/sync/lib.rs index 6bf320d52f21a..51190f0894fb7 100644 --- a/std/tests/sync/lib.rs +++ b/std/tests/sync/lib.rs @@ -2,7 +2,6 @@ #![feature(mapped_lock_guards)] #![feature(mpmc_channel)] #![feature(once_cell_try)] -#![feature(once_wait)] #![feature(lock_value_accessors)] #![feature(reentrant_lock)] #![feature(rwlock_downgrade)] From 193c52f15010943e31443d8dbc1d005e1a869f1e Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sun, 26 Jan 2025 13:27:34 -0700 Subject: [PATCH 433/481] std::range --- std/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/src/lib.rs b/std/src/lib.rs index acb3a0578e505..7c18226874cc8 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -530,6 +530,8 @@ pub use core::option; pub use core::pin; #[stable(feature = "rust1", since = "1.0.0")] pub use core::ptr; +#[unstable(feature = "new_range_api", issue = "125687")] +pub use core::range; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; #[stable(feature = "rust1", since = "1.0.0")] From c6a49489c35a32b775859c8216c048fe0828e31c Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Mon, 27 Jan 2025 13:32:10 -0700 Subject: [PATCH 434/481] implement unstable `new_range` feature for RFC 3550, tracking issue #123741 --- core/src/range.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/range.rs b/core/src/range.rs index 427526fd14b91..6a62928873fe8 100644 --- a/core/src/range.rs +++ b/core/src/range.rs @@ -48,6 +48,7 @@ pub use crate::ops::{Bound, OneSidedRange, RangeBounds, RangeFull, RangeTo, Rang /// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum()); /// ``` +#[cfg_attr(not(bootstrap), lang = "RangeCopy")] #[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct Range { @@ -205,6 +206,7 @@ impl From> for Range { /// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum()); /// ``` +#[cfg_attr(not(bootstrap), lang = "RangeInclusiveCopy")] #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct RangeInclusive { @@ -388,6 +390,7 @@ impl From> for RangeInclusive { /// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 }); /// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum()); /// ``` +#[cfg_attr(not(bootstrap), lang = "RangeFromCopy")] #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct RangeFrom { From 56b6ff5c7a7d13b4ef691d94c4b53c5f789b5c63 Mon Sep 17 00:00:00 2001 From: ricci009 Date: Mon, 3 Feb 2025 17:21:32 -0500 Subject: [PATCH 435/481] primitive type migration from mod.rs to primitives.rs --- core/src/ffi/mod.rs | 175 ++----------------------------------- core/src/ffi/primitives.rs | 174 ++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 168 deletions(-) create mode 100644 core/src/ffi/primitives.rs diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 51687a3adcdd4..50968c57adc62 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -37,175 +37,14 @@ pub use self::va_list::{VaList, VaListImpl}; )] pub mod va_list; -macro_rules! type_alias { - { - $Docfile:tt, $Alias:ident = $Real:ty; - $( $Cfg:tt )* - } => { - #[doc = include_str!($Docfile)] - $( $Cfg )* - #[stable(feature = "core_ffi_c", since = "1.64.0")] - pub type $Alias = $Real; - } -} - -type_alias! { "c_char.md", c_char = c_char_definition::c_char; #[doc(cfg(all()))] } - -type_alias! { "c_schar.md", c_schar = i8; } -type_alias! { "c_uchar.md", c_uchar = u8; } -type_alias! { "c_short.md", c_short = i16; } -type_alias! { "c_ushort.md", c_ushort = u16; } - -type_alias! { "c_int.md", c_int = c_int_definition::c_int; #[doc(cfg(all()))] } -type_alias! { "c_uint.md", c_uint = c_int_definition::c_uint; #[doc(cfg(all()))] } - -type_alias! { "c_long.md", c_long = c_long_definition::c_long; #[doc(cfg(all()))] } -type_alias! { "c_ulong.md", c_ulong = c_long_definition::c_ulong; #[doc(cfg(all()))] } - -type_alias! { "c_longlong.md", c_longlong = i64; } -type_alias! { "c_ulonglong.md", c_ulonglong = u64; } - -type_alias! { "c_float.md", c_float = f32; } -type_alias! { "c_double.md", c_double = f64; } - -/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++). -/// -/// This type is currently always [`usize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_size_t = usize; - -/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++). -/// -/// This type is currently always [`isize`], however in the future there may be -/// platforms where this is not the case. +mod primitives; +#[stable(feature = "core_ffi_c", since = "1.64.0")] +pub use self::primitives::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, +}; #[unstable(feature = "c_size_t", issue = "88345")] -pub type c_ptrdiff_t = isize; - -/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type. -/// -/// This type is currently always [`isize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_ssize_t = isize; - -mod c_char_definition { - cfg_if! { - // These are the targets on which c_char is unsigned. Usually the - // signedness is the same for all target_os values on a given architecture - // but there are some exceptions (see isSignedCharDefault() in clang). - // - // aarch64: - // Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the Arm® - // 64-bit Architecture (AArch64) says C/C++ char is unsigned byte. - // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs64/aapcs64.rst#arm-c-and-c-language-mappings - // arm: - // Section 8 "Arm C and C++ Language Mappings" in Procedure Call Standard for the Arm® - // Architecture says C/C++ char is unsigned byte. - // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs32/aapcs32.rst#arm-c-and-c-language-mappings - // csky: - // Section 2.1.2 "Primary Data Type" in C-SKY V2 CPU Applications Binary Interface - // Standards Manual says ANSI C char is unsigned byte. - // https://github.com/c-sky/csky-doc/blob/9f7121f7d40970ba5cc0f15716da033db2bb9d07/C-SKY_V2_CPU_Applications_Binary_Interface_Standards_Manual.pdf - // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). - // hexagon: - // Section 3.1 "Basic data type" in Qualcomm Hexagon™ Application - // Binary Interface User Guide says "By default, the `char` data type is unsigned." - // https://docs.qualcomm.com/bundle/publicresource/80-N2040-23_REV_K_Qualcomm_Hexagon_Application_Binary_Interface_User_Guide.pdf - // msp430: - // Section 2.1 "Basic Types" in MSP430 Embedded Application Binary - // Interface says "The char type is unsigned by default". - // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf - // powerpc/powerpc64: - // - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC - // Processor Supplement says ANSI C char is unsigned byte - // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf - // - PPC64 ELFv1: Section 3.1.4 "Fundamental Types" in 64-bit PowerPC ELF Application - // Binary Interface Supplement 1.9 says ANSI C is unsigned byte - // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUND-TYPE - // - PPC64 ELFv2: Section 2.1.2.2 "Fundamental Types" in 64-Bit ELF V2 ABI Specification - // says char is unsigned byte - // https://openpowerfoundation.org/specifications/64bitelfabi/ - // - AIX: XL C for AIX Language Reference says "By default, char behaves like an unsigned char." - // https://www.ibm.com/docs/en/xl-c-aix/13.1.3?topic=specifiers-character-types - // riscv32/riscv64: - // C/C++ type representations section in RISC-V Calling Conventions - // page in RISC-V ELF psABI Document says "char is unsigned." - // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/draft-20240829-13bfa9f54634cb60d86b9b333e109f077805b4b3/riscv-cc.adoc#cc-type-representations - // s390x: - // - ELF: "Table 1.1.: Scalar types" in ELF Application Binary Interface s390x Supplement - // Version 1.6.1 categorize ISO C char in unsigned integer - // https://github.com/IBM/s390x-abi/releases/tag/v1.6.1 - // - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char." - // https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types - // xtensa: - // Section 2.17.1 "Data Types and Alignment" of Xtensa LX Microprocessor Overview handbook - // says "`char` type is unsigned by default". - // https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf - // - // On the following operating systems, c_char is signed by default, regardless of architecture. - // Darwin (macOS, iOS, etc.): - // Apple targets' c_char is signed by default even on arm - // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Handle-data-types-and-data-alignment-properly - // Windows: - // Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char - // are promoted to int as if from type signed char by default, unless the /J compilation - // option is used." - // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types - // L4Re: - // The kernel builds with -funsigned-char on all targets (but useserspace follows the - // architecture defaults). As we only have a target for userspace apps so there are no - // special cases for L4Re below. - // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 - if #[cfg(all( - not(windows), - not(target_vendor = "apple"), - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "csky", - target_arch = "hexagon", - target_arch = "msp430", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "s390x", - target_arch = "xtensa", - ) - ))] { - pub(super) type c_char = u8; - } else { - // On every other target, c_char is signed. - pub(super) type c_char = i8; - } - } -} - -mod c_int_definition { - cfg_if! { - if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { - pub(super) type c_int = i16; - pub(super) type c_uint = u16; - } else { - pub(super) type c_int = i32; - pub(super) type c_uint = u32; - } - } -} - -mod c_long_definition { - cfg_if! { - if #[cfg(all(target_pointer_width = "64", not(windows)))] { - pub(super) type c_long = i64; - pub(super) type c_ulong = u64; - } else { - // The minimal size of `long` in the C standard is 32 bits - pub(super) type c_long = i32; - pub(super) type c_ulong = u32; - } - } -} +pub use self::primitives::{c_ptrdiff_t, c_size_t, c_ssize_t}; // N.B., for LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in diff --git a/core/src/ffi/primitives.rs b/core/src/ffi/primitives.rs new file mode 100644 index 0000000000000..ece3c7538dabb --- /dev/null +++ b/core/src/ffi/primitives.rs @@ -0,0 +1,174 @@ +//! Defines primitive types that match C's type definitions for FFI compatibility. +//! +//! This module is intentionally standalone to facilitate parsing when retrieving +//! core C types. + +macro_rules! type_alias { + { + $Docfile:tt, $Alias:ident = $Real:ty; + $( $Cfg:tt )* + } => { + #[doc = include_str!($Docfile)] + $( $Cfg )* + #[stable(feature = "core_ffi_c", since = "1.64.0")] + pub type $Alias = $Real; + } +} + +type_alias! { "c_char.md", c_char = c_char_definition::c_char; #[doc(cfg(all()))] } + +type_alias! { "c_schar.md", c_schar = i8; } +type_alias! { "c_uchar.md", c_uchar = u8; } +type_alias! { "c_short.md", c_short = i16; } +type_alias! { "c_ushort.md", c_ushort = u16; } + +type_alias! { "c_int.md", c_int = c_int_definition::c_int; #[doc(cfg(all()))] } +type_alias! { "c_uint.md", c_uint = c_int_definition::c_uint; #[doc(cfg(all()))] } + +type_alias! { "c_long.md", c_long = c_long_definition::c_long; #[doc(cfg(all()))] } +type_alias! { "c_ulong.md", c_ulong = c_long_definition::c_ulong; #[doc(cfg(all()))] } + +type_alias! { "c_longlong.md", c_longlong = i64; } +type_alias! { "c_ulonglong.md", c_ulonglong = u64; } + +type_alias! { "c_float.md", c_float = f32; } +type_alias! { "c_double.md", c_double = f64; } + +mod c_char_definition { + cfg_if! { + // These are the targets on which c_char is unsigned. Usually the + // signedness is the same for all target_os values on a given architecture + // but there are some exceptions (see isSignedCharDefault() in clang). + // + // aarch64: + // Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the Arm® + // 64-bit Architecture (AArch64) says C/C++ char is unsigned byte. + // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs64/aapcs64.rst#arm-c-and-c-language-mappings + // arm: + // Section 8 "Arm C and C++ Language Mappings" in Procedure Call Standard for the Arm® + // Architecture says C/C++ char is unsigned byte. + // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs32/aapcs32.rst#arm-c-and-c-language-mappings + // csky: + // Section 2.1.2 "Primary Data Type" in C-SKY V2 CPU Applications Binary Interface + // Standards Manual says ANSI C char is unsigned byte. + // https://github.com/c-sky/csky-doc/blob/9f7121f7d40970ba5cc0f15716da033db2bb9d07/C-SKY_V2_CPU_Applications_Binary_Interface_Standards_Manual.pdf + // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). + // hexagon: + // Section 3.1 "Basic data type" in Qualcomm Hexagon™ Application + // Binary Interface User Guide says "By default, the `char` data type is unsigned." + // https://docs.qualcomm.com/bundle/publicresource/80-N2040-23_REV_K_Qualcomm_Hexagon_Application_Binary_Interface_User_Guide.pdf + // msp430: + // Section 2.1 "Basic Types" in MSP430 Embedded Application Binary + // Interface says "The char type is unsigned by default". + // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf + // powerpc/powerpc64: + // - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC + // Processor Supplement says ANSI C char is unsigned byte + // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf + // - PPC64 ELFv1: Section 3.1.4 "Fundamental Types" in 64-bit PowerPC ELF Application + // Binary Interface Supplement 1.9 says ANSI C is unsigned byte + // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUND-TYPE + // - PPC64 ELFv2: Section 2.1.2.2 "Fundamental Types" in 64-Bit ELF V2 ABI Specification + // says char is unsigned byte + // https://openpowerfoundation.org/specifications/64bitelfabi/ + // - AIX: XL C for AIX Language Reference says "By default, char behaves like an unsigned char." + // https://www.ibm.com/docs/en/xl-c-aix/13.1.3?topic=specifiers-character-types + // riscv32/riscv64: + // C/C++ type representations section in RISC-V Calling Conventions + // page in RISC-V ELF psABI Document says "char is unsigned." + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/draft-20240829-13bfa9f54634cb60d86b9b333e109f077805b4b3/riscv-cc.adoc#cc-type-representations + // s390x: + // - ELF: "Table 1.1.: Scalar types" in ELF Application Binary Interface s390x Supplement + // Version 1.6.1 categorize ISO C char in unsigned integer + // https://github.com/IBM/s390x-abi/releases/tag/v1.6.1 + // - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char." + // https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types + // xtensa: + // Section 2.17.1 "Data Types and Alignment" of Xtensa LX Microprocessor Overview handbook + // says "`char` type is unsigned by default". + // https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf + // + // On the following operating systems, c_char is signed by default, regardless of architecture. + // Darwin (macOS, iOS, etc.): + // Apple targets' c_char is signed by default even on arm + // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Handle-data-types-and-data-alignment-properly + // Windows: + // Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char + // are promoted to int as if from type signed char by default, unless the /J compilation + // option is used." + // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types + // L4Re: + // The kernel builds with -funsigned-char on all targets (but useserspace follows the + // architecture defaults). As we only have a target for userspace apps so there are no + // special cases for L4Re below. + // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 + if #[cfg(all( + not(windows), + not(target_vendor = "apple"), + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "csky", + target_arch = "hexagon", + target_arch = "msp430", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "s390x", + target_arch = "xtensa", + ) + ))] { + pub(super) type c_char = u8; + } else { + // On every other target, c_char is signed. + pub(super) type c_char = i8; + } + } +} + +mod c_long_definition { + cfg_if! { + if #[cfg(all(target_pointer_width = "64", not(windows)))] { + pub(super) type c_long = i64; + pub(super) type c_ulong = u64; + } else { + // The minimal size of `long` in the C standard is 32 bits + pub(super) type c_long = i32; + pub(super) type c_ulong = u32; + } + } +} + +/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++). +/// +/// This type is currently always [`usize`], however in the future there may be +/// platforms where this is not the case. +#[unstable(feature = "c_size_t", issue = "88345")] +pub type c_size_t = usize; + +/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++). +/// +/// This type is currently always [`isize`], however in the future there may be +/// platforms where this is not the case. +#[unstable(feature = "c_size_t", issue = "88345")] +pub type c_ptrdiff_t = isize; + +/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type. +/// +/// This type is currently always [`isize`], however in the future there may be +/// platforms where this is not the case. +#[unstable(feature = "c_size_t", issue = "88345")] +pub type c_ssize_t = isize; + +mod c_int_definition { + cfg_if! { + if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { + pub(super) type c_int = i16; + pub(super) type c_uint = u16; + } else { + pub(super) type c_int = i32; + pub(super) type c_uint = u32; + } + } +} From 6b0040b9c69a9f40a70471872275da93a21d723f Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 1 Feb 2025 13:09:28 -0700 Subject: [PATCH 436/481] add UnsafeCell direct access APIs --- core/src/cell.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/core/src/cell.rs b/core/src/cell.rs index 20187e478aac5..320d8176011fd 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -2118,6 +2118,35 @@ impl UnsafeCell { pub const fn into_inner(self) -> T { self.value } + + /// Replace the value in this `UnsafeCell` and return the old value. + /// + /// # Safety + /// + /// The caller must take care to avoid aliasing and data races. + /// + /// - It is Undefined Behavior to allow calls to race with + /// any other access to the wrapped value. + /// - It is Undefined Behavior to call this while any other + /// reference(s) to the wrapped value are alive. + /// + /// # Examples + /// + /// ``` + /// #![feature(unsafe_cell_access)] + /// use std::cell::UnsafeCell; + /// + /// let uc = UnsafeCell::new(5); + /// + /// let old = unsafe { uc.replace(10) }; + /// assert_eq!(old, 5); + /// ``` + #[inline] + #[unstable(feature = "unsafe_cell_access", issue = "136327")] + pub const unsafe fn replace(&self, value: T) -> T { + // SAFETY: pointer comes from `&self` so naturally satisfies invariants. + unsafe { ptr::replace(self.get(), value) } + } } impl UnsafeCell { @@ -2230,6 +2259,61 @@ impl UnsafeCell { // no guarantee for user code that this will work in future versions of the compiler! this as *const T as *mut T } + + /// Get a shared reference to the value within the `UnsafeCell`. + /// + /// # Safety + /// + /// - It is Undefined Behavior to call this while any mutable + /// reference to the wrapped value is alive. + /// - Mutating the wrapped value while the returned + /// reference is alive is Undefined Behavior. + /// + /// # Examples + /// + /// ``` + /// #![feature(unsafe_cell_access)] + /// use std::cell::UnsafeCell; + /// + /// let uc = UnsafeCell::new(5); + /// + /// let val = unsafe { uc.as_ref_unchecked() }; + /// assert_eq!(val, &5); + /// ``` + #[inline] + #[unstable(feature = "unsafe_cell_access", issue = "136327")] + pub const unsafe fn as_ref_unchecked(&self) -> &T { + // SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants. + unsafe { self.get().as_ref_unchecked() } + } + + /// Get an exclusive reference to the value within the `UnsafeCell`. + /// + /// # Safety + /// + /// - It is Undefined Behavior to call this while any other + /// reference(s) to the wrapped value are alive. + /// - Mutating the wrapped value through other means while the + /// returned reference is alive is Undefined Behavior. + /// + /// # Examples + /// + /// ``` + /// #![feature(unsafe_cell_access)] + /// use std::cell::UnsafeCell; + /// + /// let uc = UnsafeCell::new(5); + /// + /// unsafe { *uc.as_mut_unchecked() += 1; } + /// assert_eq!(uc.into_inner(), 6); + /// ``` + #[inline] + #[unstable(feature = "unsafe_cell_access", issue = "136327")] + #[allow(clippy::mut_from_ref)] + pub const unsafe fn as_mut_unchecked(&self) -> &mut T { + // SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants. + unsafe { self.get().as_mut_unchecked() } + } } #[stable(feature = "unsafe_cell_default", since = "1.10.0")] From afca9ef2ba32eeb21d26fc84612bcb66940696dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Feb 2025 12:05:23 +0100 Subject: [PATCH 437/481] std::fs: further simplify dirent64 handling --- std/src/sys/pal/unix/fs.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index fdf011c19482a..6c41781fe850c 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -740,29 +740,27 @@ impl Iterator for ReadDir { // to `byte_offset` and thus does not require the full extent of `*entry_ptr` // to be in bounds of the same allocation, only the offset of the field // being referenced. - macro_rules! entry_field_ptr { - ($field:ident) => { - &raw const (*entry_ptr).$field - }; - } // d_name is guaranteed to be null-terminated. - let name = CStr::from_ptr(entry_field_ptr!(d_name).cast()); + let name = CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()); let name_bytes = name.to_bytes(); if name_bytes == b"." || name_bytes == b".." { continue; } + // When loading from a field, we can skip the `&raw const`; `(*entry_ptr).d_ino` as + // a value expression will do the right thing: `byte_offset` to the field and then + // only access those bytes. #[cfg(not(target_os = "vita"))] let entry = dirent64_min { - d_ino: *entry_field_ptr!(d_ino) as u64, + d_ino: (*entry_ptr).d_ino as u64, #[cfg(not(any( target_os = "solaris", target_os = "illumos", target_os = "aix", target_os = "nto", )))] - d_type: *entry_field_ptr!(d_type) as u8, + d_type: (*entry_ptr).d_type as u8, }; #[cfg(target_os = "vita")] From c26d414d59b29692c2fc3c182d3f5f5502864d4e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 3 Feb 2025 16:37:59 +0100 Subject: [PATCH 438/481] For NonZero impl macros, give unsigned impls access to the corresponding signed type There was a macro parameter giving signed impls access to the corresponding unsigned type, but not the other way around. This will allow implementing methods converting in both directions. --- core/src/num/nonzero.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 61e83ebfad7de..3becbc9bade30 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -474,6 +474,7 @@ macro_rules! nonzero_integer { #[$stability:meta] Self = $Ty:ident, Primitive = $signedness:ident $Int:ident, + SignedPrimitive = $Sint:ty, UnsignedPrimitive = $Uint:ty, // Used in doc comments. @@ -905,6 +906,7 @@ macro_rules! nonzero_integer { nonzero_integer_signedness_dependent_methods! { Primitive = $signedness $Int, + SignedPrimitive = $Sint, UnsignedPrimitive = $Uint, } @@ -1128,6 +1130,7 @@ macro_rules! nonzero_integer { ( Self = $Ty:ident, Primitive = unsigned $Int:ident, + SignedPrimitive = $Sint:ident, rot = $rot:literal, rot_op = $rot_op:literal, rot_result = $rot_result:literal, @@ -1140,6 +1143,7 @@ macro_rules! nonzero_integer { #[stable(feature = "nonzero", since = "1.28.0")] Self = $Ty, Primitive = unsigned $Int, + SignedPrimitive = $Sint, UnsignedPrimitive = $Int, rot = $rot, rot_op = $rot_op, @@ -1154,7 +1158,7 @@ macro_rules! nonzero_integer { ( Self = $Ty:ident, Primitive = signed $Int:ident, - UnsignedPrimitive = $UInt:ident, + UnsignedPrimitive = $Uint:ident, rot = $rot:literal, rot_op = $rot_op:literal, rot_result = $rot_result:literal, @@ -1166,7 +1170,8 @@ macro_rules! nonzero_integer { #[stable(feature = "signed_nonzero", since = "1.34.0")] Self = $Ty, Primitive = signed $Int, - UnsignedPrimitive = $UInt, + SignedPrimitive = $Int, + UnsignedPrimitive = $Uint, rot = $rot, rot_op = $rot_op, rot_result = $rot_result, @@ -1286,6 +1291,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // Associated items for unsigned nonzero types only. ( Primitive = unsigned $Int:ident, + SignedPrimitive = $Sint:ty, UnsignedPrimitive = $Uint:ty, ) => { /// The smallest value that can be represented by this non-zero @@ -1625,6 +1631,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // Associated items for signed nonzero types only. ( Primitive = signed $Int:ident, + SignedPrimitive = $Sint:ty, UnsignedPrimitive = $Uint:ty, ) => { /// The smallest value that can be represented by this non-zero @@ -2041,6 +2048,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, + SignedPrimitive = i8, rot = 2, rot_op = "0x82", rot_result = "0xa", @@ -2052,6 +2060,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroU16, Primitive = unsigned u16, + SignedPrimitive = i16, rot = 4, rot_op = "0xa003", rot_result = "0x3a", @@ -2063,6 +2072,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroU32, Primitive = unsigned u32, + SignedPrimitive = i32, rot = 8, rot_op = "0x10000b3", rot_result = "0xb301", @@ -2074,6 +2084,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroU64, Primitive = unsigned u64, + SignedPrimitive = i64, rot = 12, rot_op = "0xaa00000000006e1", rot_result = "0x6e10aa", @@ -2085,6 +2096,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroU128, Primitive = unsigned u128, + SignedPrimitive = i128, rot = 16, rot_op = "0x13f40000000000000000000000004f76", rot_result = "0x4f7613f4", @@ -2097,6 +2109,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, + SignedPrimitive = isize, rot = 4, rot_op = "0xa003", rot_result = "0x3a", @@ -2109,6 +2122,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, + SignedPrimitive = isize, rot = 8, rot_op = "0x10000b3", rot_result = "0xb301", @@ -2121,6 +2135,7 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, + SignedPrimitive = isize, rot = 12, rot_op = "0xaa00000000006e1", rot_result = "0x6e10aa", From 54d096ef2fe4f295929fde7ae0f497231aa31804 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 3 Feb 2025 16:55:34 +0100 Subject: [PATCH 439/481] Add `cast_signed` and `cast_unsigned` methods for `NonZero` types --- core/src/num/nonzero.rs | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 3becbc9bade30..a115acf42b126 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -1626,6 +1626,29 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // results will be sqrt(1), which is 1, so a result can't be zero. unsafe { Self::new_unchecked(result) } } + + /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(integer_sign_cast)] + /// # use std::num::NonZero; + /// + #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::MAX;")] + /// + #[doc = concat!("assert_eq!(n.cast_signed(), NonZero::new(-1", stringify!($Sint), ").unwrap());")] + /// ``` + #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn cast_signed(self) -> NonZero<$Sint> { + // SAFETY: `self.get()` can't be zero + unsafe { NonZero::new_unchecked(self.get().cast_signed()) } + } }; // Associated items for signed nonzero types only. @@ -2042,6 +2065,30 @@ macro_rules! nonzero_integer_signedness_dependent_methods { // SAFETY: negation of nonzero cannot yield zero values. unsafe { Self::new_unchecked(result) } } + + /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(integer_sign_cast)] + /// # use std::num::NonZero; + /// + #[doc = concat!("let n = NonZero::new(-1", stringify!($Int), ").unwrap();")] + /// + #[doc = concat!("assert_eq!(n.cast_unsigned(), NonZero::<", stringify!($Uint), ">::MAX);")] + /// ``` + #[unstable(feature = "integer_sign_cast", issue = "125882")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn cast_unsigned(self) -> NonZero<$Uint> { + // SAFETY: `self.get()` can't be zero + unsafe { NonZero::new_unchecked(self.get().cast_unsigned()) } + } + }; } From 5d40d795508153a4d75e88a0f083c27a23471f8d Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 3 Feb 2025 23:59:43 +0100 Subject: [PATCH 440/481] Add note about `FnPtr` being exposed as public bound --- core/src/marker.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/marker.rs b/core/src/marker.rs index 18ada14d101b5..1a8ef20dd7b9d 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -1077,6 +1077,9 @@ marker_impls! { } /// A common trait implemented by all function pointers. +// +// Note that while the trait is internal and unstable it is nevertheless +// exposed as a public bound of the stable `core::ptr::fn_addr_eq` function. #[unstable( feature = "fn_ptr_trait", issue = "none", From aaeee0195ff43438dcf737ac2a8ad5de532b69a4 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 19 Jan 2025 23:38:09 -0800 Subject: [PATCH 441/481] Add `unchecked_disjoint_bitor` with fallback intrinsic implementation --- core/src/intrinsics/fallback.rs | 40 ++++++++++++++++++++++ core/src/intrinsics/mod.rs | 19 +++++++++++ core/src/lib.rs | 1 + core/src/num/uint_macros.rs | 59 +++++++++++++++++++++++++++++++-- 4 files changed, 116 insertions(+), 3 deletions(-) diff --git a/core/src/intrinsics/fallback.rs b/core/src/intrinsics/fallback.rs index 70484e4d0f2a1..dca211eba80ee 100644 --- a/core/src/intrinsics/fallback.rs +++ b/core/src/intrinsics/fallback.rs @@ -110,3 +110,43 @@ impl const CarryingMulAdd for i128 { (low, high) } } + +#[const_trait] +#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] +pub trait DisjointBitOr: Copy + 'static { + /// This is always just `assume((self & other) == 0); self | other`. + /// + /// It's essential that the assume is there so that this is sufficient to + /// specify the UB for MIRI, rather than it needing to re-implement it. + /// + /// # Safety + /// See [`super::disjoint_bitor`]. + unsafe fn disjoint_bitor(self, other: Self) -> Self; +} +macro_rules! zero { + (bool) => { + false + }; + ($t:ident) => { + 0 + }; +} +macro_rules! impl_disjoint_bitor { + ($($t:ident,)+) => {$( + #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] + impl const DisjointBitOr for $t { + #[inline] + unsafe fn disjoint_bitor(self, other: Self) -> Self { + // SAFETY: our precondition is that there are no bits in common, + // so this is just telling that to the backend. + unsafe { super::assume((self & other) == zero!($t)) }; + self | other + } + } + )+}; +} +impl_disjoint_bitor! { + bool, + u8, u16, u32, u64, u128, usize, + i8, i16, i32, i64, i128, isize, +} diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index bf07632d9928b..75743520df1d8 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3248,6 +3248,25 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi unimplemented!() } +/// Combine two values which have no bits in common. +/// +/// This allows the backend to implement it as `a + b` *or* `a | b`, +/// depending which us easier to implement on a specific target. +/// +/// # Safety +/// +/// Requires that `(a & b) == 0`, or equivalently that `(a | b) == (a + b)`. +/// +/// Otherwise it's immediate UB. +#[rustc_const_unstable(feature = "disjoint_bitor", issue = "135758")] +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[miri::intrinsic_fallback_is_spec] // the fallbacks all `assume` to tell MIRI +pub const unsafe fn disjoint_bitor(a: T, b: T) -> T { + // SAFETY: same preconditions as this function. + unsafe { fallback::DisjointBitOr::disjoint_bitor(a, b) } +} + /// Performs checked integer addition. /// /// Note that, unlike most intrinsics, this is safe to call; diff --git a/core/src/lib.rs b/core/src/lib.rs index c18e0405f7293..b9471f169797c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -117,6 +117,7 @@ #![feature(const_eval_select)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] +#![feature(disjoint_bitor)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index c8433b3bb168a..c909ab56ac835 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -1187,6 +1187,52 @@ macro_rules! uint_impl { self % rhs } + /// Same value as + #[doc = concat!("`<", stringify!($SelfT), " as BitOr>::bitor(self, other)`")] + /// but UB if any bit position is set in both inputs. + /// + /// This is a situational μoptimization for places where you'd rather use + /// addition on some platforms and bitwise or on other platforms, based on + /// exactly which instructions combine better with whatever else you're + /// doing. Note that there's no reason to bother using this for places + /// where it's clear from the operations involved that they can't overlap. + /// For example, if you're combining `u16`s into a `u32` with + /// `((a as u32) << 16) | (b as u32)`, that's fine, as the backend will + /// know those sides of the `|` are disjoint without needing help. + /// + /// # Examples + /// + /// ``` + /// #![feature(disjoint_bitor)] + /// + /// // SAFETY: `1` and `4` have no bits in common. + /// unsafe { + #[doc = concat!(" assert_eq!(1_", stringify!($SelfT), ".unchecked_disjoint_bitor(4), 5);")] + /// } + /// ``` + /// + /// # Safety + /// + /// Requires that `(self | other) == 0`, otherwise it's immediate UB. + /// + /// Equivalently, requires that `(self | other) == (self + other)`. + #[unstable(feature = "disjoint_bitor", issue = "135758")] + #[rustc_const_unstable(feature = "disjoint_bitor", issue = "135758")] + #[inline] + pub const unsafe fn unchecked_disjoint_bitor(self, other: Self) -> Self { + assert_unsafe_precondition!( + check_language_ub, + concat!(stringify!($SelfT), "::unchecked_disjoint_bitor cannot have overlapping bits"), + ( + lhs: $SelfT = self, + rhs: $SelfT = other, + ) => (lhs & rhs) == 0, + ); + + // SAFETY: Same precondition + unsafe { intrinsics::disjoint_bitor(self, other) } + } + /// Returns the logarithm of the number with respect to an arbitrary base, /// rounded down. /// @@ -2346,15 +2392,22 @@ macro_rules! uint_impl { /// assert_eq!((sum1, sum0), (9, 6)); /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { // note: longer-term this should be done via an intrinsic, but this has been shown // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic - let (a, b) = self.overflowing_add(rhs); - let (c, d) = a.overflowing_add(carry as $SelfT); - (c, b | d) + let (a, c1) = self.overflowing_add(rhs); + let (b, c2) = a.overflowing_add(carry as $SelfT); + // Ideally LLVM would know this is disjoint without us telling them, + // but it doesn't + // SAFETY: Only one of `c1` and `c2` can be set. + // For c1 to be set we need to have overflowed, but if we did then + // `a` is at most `MAX-1`, which means that `c2` cannot possibly + // overflow because it's adding at most `1` (since it came from `bool`) + (b, unsafe { intrinsics::disjoint_bitor(c1, c2) }) } /// Calculates `self` + `rhs` with a signed `rhs`. From 78bc332f7fc184463e2b43643b2d35eafedbfd50 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 22 Jan 2025 01:00:59 -0800 Subject: [PATCH 442/481] PR feedback --- core/src/intrinsics/fallback.rs | 12 +++++------- core/src/intrinsics/mod.rs | 3 ++- core/src/num/uint_macros.rs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/core/src/intrinsics/fallback.rs b/core/src/intrinsics/fallback.rs index dca211eba80ee..eec5c4d646d07 100644 --- a/core/src/intrinsics/fallback.rs +++ b/core/src/intrinsics/fallback.rs @@ -114,13 +114,8 @@ impl const CarryingMulAdd for i128 { #[const_trait] #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] pub trait DisjointBitOr: Copy + 'static { - /// This is always just `assume((self & other) == 0); self | other`. - /// - /// It's essential that the assume is there so that this is sufficient to - /// specify the UB for MIRI, rather than it needing to re-implement it. - /// - /// # Safety - /// See [`super::disjoint_bitor`]. + /// See [`super::disjoint_bitor`]; we just need the trait indirection to handle + /// different types since calling intrinsics with generics doesn't work. unsafe fn disjoint_bitor(self, other: Self) -> Self; } macro_rules! zero { @@ -135,8 +130,11 @@ macro_rules! impl_disjoint_bitor { ($($t:ident,)+) => {$( #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] impl const DisjointBitOr for $t { + #[cfg_attr(miri, track_caller)] #[inline] unsafe fn disjoint_bitor(self, other: Self) -> Self { + // Note that the assume here is required for UB detection in Miri! + // SAFETY: our precondition is that there are no bits in common, // so this is just telling that to the backend. unsafe { super::assume((self & other) == zero!($t)) }; diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 75743520df1d8..916c949df8e15 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3261,7 +3261,8 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi #[rustc_const_unstable(feature = "disjoint_bitor", issue = "135758")] #[rustc_nounwind] #[cfg_attr(not(bootstrap), rustc_intrinsic)] -#[miri::intrinsic_fallback_is_spec] // the fallbacks all `assume` to tell MIRI +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[miri::intrinsic_fallback_is_spec] // the fallbacks all `assume` to tell Miri pub const unsafe fn disjoint_bitor(a: T, b: T) -> T { // SAFETY: same preconditions as this function. unsafe { fallback::DisjointBitOr::disjoint_bitor(a, b) } diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index c909ab56ac835..f2d41fd93d5ca 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -1213,7 +1213,7 @@ macro_rules! uint_impl { /// /// # Safety /// - /// Requires that `(self | other) == 0`, otherwise it's immediate UB. + /// Requires that `(self & other) == 0`, otherwise it's immediate UB. /// /// Equivalently, requires that `(self | other) == (self + other)`. #[unstable(feature = "disjoint_bitor", issue = "135758")] From e09f85388d83ec3801f94985e893db85e3e41151 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 31 Jan 2025 22:31:43 -0800 Subject: [PATCH 443/481] More PR feedback --- core/src/intrinsics/mod.rs | 2 +- core/src/num/uint_macros.rs | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 916c949df8e15..1362b9897dce5 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -3251,7 +3251,7 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi /// Combine two values which have no bits in common. /// /// This allows the backend to implement it as `a + b` *or* `a | b`, -/// depending which us easier to implement on a specific target. +/// depending which is easier to implement on a specific target. /// /// # Safety /// diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index f2d41fd93d5ca..29f6791ee6ad2 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -1187,13 +1187,11 @@ macro_rules! uint_impl { self % rhs } - /// Same value as - #[doc = concat!("`<", stringify!($SelfT), " as BitOr>::bitor(self, other)`")] - /// but UB if any bit position is set in both inputs. + /// Same value as `self | other`, but UB if any bit position is set in both inputs. /// - /// This is a situational μoptimization for places where you'd rather use - /// addition on some platforms and bitwise or on other platforms, based on - /// exactly which instructions combine better with whatever else you're + /// This is a situational micro-optimization for places where you'd rather + /// use addition on some platforms and bitwise or on other platforms, based + /// on exactly which instructions combine better with whatever else you're /// doing. Note that there's no reason to bother using this for places /// where it's clear from the operations involved that they can't overlap. /// For example, if you're combining `u16`s into a `u32` with From eaf50e76775c67681b4cc4b70803979edb8b22b8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 2 Dec 2024 20:35:13 +0000 Subject: [PATCH 444/481] Contracts core intrinsics. These are hooks to: 1. control whether contract checks are run 2. allow 3rd party tools to intercept and reintepret the results of running contracts. --- core/src/intrinsics/mod.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 1362b9897dce5..014471964b274 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -4064,6 +4064,38 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } +/// 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 +/// checking is turned on, so that we can specify contracts in libstd +/// and let an end user opt into turning them on. +#[cfg(not(bootstrap))] +#[rustc_const_unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[inline(always)] +#[rustc_intrinsic] +pub const fn contract_checks() -> bool { + // FIXME: should this be `false` or `cfg!(contract_checks)`? + + // cfg!(contract_checks) + false +} + +#[cfg(not(bootstrap))] +#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[rustc_intrinsic] +pub fn contract_check_requires bool>(c: C) -> bool { + c() +} + +#[cfg(not(bootstrap))] +#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[rustc_intrinsic] +pub fn contract_check_ensures<'a, Ret, C: FnOnce(&'a Ret) -> bool>(ret: &'a Ret, c: C) -> bool { + c(ret) +} + /// The intrinsic will return the size stored in that vtable. /// /// # Safety From d7a2384c95ed0025660b0035465e9e003ce25bcf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 2 Dec 2024 21:16:35 +0000 Subject: [PATCH 445/481] contracts: added lang items that act as hooks for rustc-injected code to invoke. see test for an example of the kind of injected code that is anticipated here. --- core/src/contracts.rs | 33 +++++++++++++++++++++++++++++++++ core/src/lib.rs | 5 +++++ 2 files changed, 38 insertions(+) create mode 100644 core/src/contracts.rs diff --git a/core/src/contracts.rs b/core/src/contracts.rs new file mode 100644 index 0000000000000..c13565d59d58f --- /dev/null +++ b/core/src/contracts.rs @@ -0,0 +1,33 @@ +//! Unstable module containing the unstable contracts lang items and attribute macros. + +/// Emitted by rustc as a desugaring of `#[requires(PRED)] fn foo(x: X) { ... }` +/// into: `fn foo(x: X) { check_requires(|| PRED) ... }` +#[cfg(not(bootstrap))] +#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[lang = "contract_check_requires"] +#[track_caller] +pub fn check_requires bool>(c: C) { + if core::intrinsics::contract_checks() { + assert!(core::intrinsics::contract_check_requires(c), "failed requires check"); + } +} + +/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` +/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` +/// (including the implicit return of the tail expression, if any). +#[cfg(not(bootstrap))] +#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[lang = "contract_build_check_ensures"] +#[track_caller] +pub fn build_check_ensures(c: C) -> impl (FnOnce(Ret) -> Ret) + Copy +where + C: for<'a> FnOnce(&'a Ret) -> bool + Copy + 'static, +{ + #[track_caller] + move |ret| { + if core::intrinsics::contract_checks() { + assert!(core::intrinsics::contract_check_ensures(&ret, c), "failed ensures check"); + } + ret + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index b9471f169797c..f0777a2b566ac 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -114,6 +114,7 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(const_carrying_mul_add)] +#![feature(closure_track_caller)] #![feature(const_eval_select)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] @@ -247,6 +248,10 @@ pub mod autodiff { pub use crate::macros::builtin::autodiff; } +#[cfg(not(bootstrap))] +#[unstable(feature = "rustc_contracts", issue = "none")] +pub mod contracts; + #[unstable(feature = "cfg_match", issue = "115585")] pub use crate::macros::cfg_match; From caf8418205e88106bb8a8aebbb4574db8f7a3be3 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 8 Jan 2025 16:38:25 -0800 Subject: [PATCH 446/481] Express contracts as part of function header and lower it to the contract lang items includes post-developed commit: do not suggest internal-only keywords as corrections to parse failures. includes post-developed commit: removed tabs that creeped in into rustfmt tool source code. includes post-developed commit, placating rustfmt self dogfooding. includes post-developed commit: add backquotes to prevent markdown checking from trying to treat an attr as a markdown hyperlink/ includes post-developed commit: fix lowering to keep contracts from being erroneously inherited by nested bodies (like closures). Rebase Conflicts: - compiler/rustc_parse/src/parser/diagnostics.rs - compiler/rustc_parse/src/parser/item.rs - compiler/rustc_span/src/hygiene.rs Remove contracts keywords from diagnostic messages --- core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index f0777a2b566ac..318d57df16921 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -113,8 +113,8 @@ #![feature(bigint_helper_methods)] #![feature(bstr)] #![feature(bstr_internals)] -#![feature(const_carrying_mul_add)] #![feature(closure_track_caller)] +#![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] From 92bf898ce872da06f1e3e90d3e29ba4a64b77cce Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 3 Dec 2024 02:52:29 +0000 Subject: [PATCH 447/481] Desugars contract into the internal AST extensions Check ensures on early return due to Try / Yeet Expand these two expressions to include a call to contract checking --- core/src/contracts.rs | 5 +++++ core/src/macros/mod.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/core/src/contracts.rs b/core/src/contracts.rs index c13565d59d58f..3efd2df0a3832 100644 --- a/core/src/contracts.rs +++ b/core/src/contracts.rs @@ -1,5 +1,10 @@ //! Unstable module containing the unstable contracts lang items and attribute macros. +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::contracts_ensures as ensures; +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::contracts_requires as requires; + /// Emitted by rustc as a desugaring of `#[requires(PRED)] fn foo(x: X) { ... }` /// into: `fn foo(x: X) { check_requires(|| PRED) ... }` #[cfg(not(bootstrap))] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 3669051ce82d3..1a5d2973dfc3f 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1777,6 +1777,32 @@ pub(crate) mod builtin { /* compiler built-in */ } + /// Attribute macro applied to a function to give it a post-condition. + /// + /// The attribute carries an argument token-tree which is + /// eventually parsed as a unary closure expression that is + /// invoked on a reference to the return value. + #[cfg(not(bootstrap))] + #[unstable(feature = "rustc_contracts", issue = "none")] + #[allow_internal_unstable(core_intrinsics)] + #[rustc_builtin_macro] + pub macro contracts_ensures($item:item) { + /* compiler built-in */ + } + + /// Attribute macro applied to a function to give it a precondition. + /// + /// The attribute carries an argument token-tree which is + /// eventually parsed as an boolean expression with access to the + /// function's formal parameters + #[cfg(not(bootstrap))] + #[unstable(feature = "rustc_contracts", issue = "none")] + #[allow_internal_unstable(core_intrinsics)] + #[rustc_builtin_macro] + pub macro contracts_requires($item:item) { + /* compiler built-in */ + } + /// Attribute macro applied to a function to register it as a handler for allocation failure. /// /// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html). From 7cb9137b8d5bb55e33700ecd599a13c0949697a3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 3 Dec 2024 16:13:00 +0000 Subject: [PATCH 448/481] Separate contract feature gates for the internal machinery The extended syntax for function signature that includes contract clauses should never be user exposed versus the interface we want to ship externally eventually. --- core/src/contracts.rs | 4 ++-- core/src/intrinsics/mod.rs | 8 ++++---- core/src/lib.rs | 2 +- core/src/macros/mod.rs | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/src/contracts.rs b/core/src/contracts.rs index 3efd2df0a3832..b155dbc213ee8 100644 --- a/core/src/contracts.rs +++ b/core/src/contracts.rs @@ -8,7 +8,7 @@ pub use crate::macros::builtin::contracts_requires as requires; /// Emitted by rustc as a desugaring of `#[requires(PRED)] fn foo(x: X) { ... }` /// into: `fn foo(x: X) { check_requires(|| PRED) ... }` #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[lang = "contract_check_requires"] #[track_caller] pub fn check_requires bool>(c: C) { @@ -21,7 +21,7 @@ pub fn check_requires bool>(c: C) { /// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` /// (including the implicit return of the tail expression, if any). #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[lang = "contract_build_check_ensures"] #[track_caller] pub fn build_check_ensures(c: C) -> impl (FnOnce(Ret) -> Ret) + Copy diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 014471964b274..de5a6859adace 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -4071,8 +4071,8 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) /// checking is turned on, so that we can specify contracts in libstd /// and let an end user opt into turning them on. #[cfg(not(bootstrap))] -#[rustc_const_unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] -#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[rustc_const_unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] +#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[inline(always)] #[rustc_intrinsic] pub const fn contract_checks() -> bool { @@ -4083,14 +4083,14 @@ pub const fn contract_checks() -> bool { } #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_requires bool>(c: C) -> bool { c() } #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts", issue = "none" /* compiler-team#759 */)] +#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_ensures<'a, Ret, C: FnOnce(&'a Ret) -> bool>(ret: &'a Ret, c: C) -> bool { c(ret) diff --git a/core/src/lib.rs b/core/src/lib.rs index 318d57df16921..a416ef80af63f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -249,7 +249,7 @@ pub mod autodiff { } #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts", issue = "none")] +#[unstable(feature = "rustc_contracts", issue = "133866")] pub mod contracts; #[unstable(feature = "cfg_match", issue = "115585")] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 1a5d2973dfc3f..cb37530e90db8 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1783,8 +1783,8 @@ pub(crate) mod builtin { /// eventually parsed as a unary closure expression that is /// invoked on a reference to the return value. #[cfg(not(bootstrap))] - #[unstable(feature = "rustc_contracts", issue = "none")] - #[allow_internal_unstable(core_intrinsics)] + #[unstable(feature = "rustc_contracts", issue = "133866")] + #[allow_internal_unstable(rustc_contracts_internals)] #[rustc_builtin_macro] pub macro contracts_ensures($item:item) { /* compiler built-in */ @@ -1796,8 +1796,8 @@ pub(crate) mod builtin { /// eventually parsed as an boolean expression with access to the /// function's formal parameters #[cfg(not(bootstrap))] - #[unstable(feature = "rustc_contracts", issue = "none")] - #[allow_internal_unstable(core_intrinsics)] + #[unstable(feature = "rustc_contracts", issue = "133866")] + #[allow_internal_unstable(rustc_contracts_internals)] #[rustc_builtin_macro] pub macro contracts_requires($item:item) { /* compiler built-in */ From d53bf4328710a541f4f1701187d44f067f079fc4 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 17 Jan 2025 14:49:10 -0800 Subject: [PATCH 449/481] Improve contracts intrisics and remove wrapper function 1. Document the new intrinsics. 2. Make the intrinsics actually check the contract if enabled, and remove `contract::check_requires` function. 3. Use panic with no unwind in case contract is using to check for safety, we probably don't want to unwind. Following the same reasoning as UB checks. --- core/src/contracts.rs | 27 +++++---------------------- core/src/intrinsics/mod.rs | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/core/src/contracts.rs b/core/src/contracts.rs index b155dbc213ee8..0668cacb92c60 100644 --- a/core/src/contracts.rs +++ b/core/src/contracts.rs @@ -1,38 +1,21 @@ //! Unstable module containing the unstable contracts lang items and attribute macros. +#![cfg(not(bootstrap))] -#[cfg(not(bootstrap))] -pub use crate::macros::builtin::contracts_ensures as ensures; -#[cfg(not(bootstrap))] -pub use crate::macros::builtin::contracts_requires as requires; - -/// Emitted by rustc as a desugaring of `#[requires(PRED)] fn foo(x: X) { ... }` -/// into: `fn foo(x: X) { check_requires(|| PRED) ... }` -#[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] -#[lang = "contract_check_requires"] -#[track_caller] -pub fn check_requires bool>(c: C) { - if core::intrinsics::contract_checks() { - assert!(core::intrinsics::contract_check_requires(c), "failed requires check"); - } -} +pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires}; /// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` /// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` /// (including the implicit return of the tail expression, if any). -#[cfg(not(bootstrap))] #[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[lang = "contract_build_check_ensures"] #[track_caller] -pub fn build_check_ensures(c: C) -> impl (FnOnce(Ret) -> Ret) + Copy +pub fn build_check_ensures(cond: C) -> impl (Fn(Ret) -> Ret) + Copy where - C: for<'a> FnOnce(&'a Ret) -> bool + Copy + 'static, + C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static, { #[track_caller] move |ret| { - if core::intrinsics::contract_checks() { - assert!(core::intrinsics::contract_check_ensures(&ret, c), "failed ensures check"); - } + crate::intrinsics::contract_check_ensures(&ret, cond); ret } } diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index de5a6859adace..c3b95c7950360 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -4082,18 +4082,32 @@ pub const fn contract_checks() -> bool { false } +/// Check if the pre-condition `cond` has been met. +/// +/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition +/// returns false. #[cfg(not(bootstrap))] #[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] +#[lang = "contract_check_requires"] #[rustc_intrinsic] -pub fn contract_check_requires bool>(c: C) -> bool { - c() +pub fn contract_check_requires bool>(cond: C) { + if contract_checks() && !cond() { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed requires check"); + } } +/// Check if the post-condition `cond` has been met. +/// +/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition +/// returns false. #[cfg(not(bootstrap))] #[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] #[rustc_intrinsic] -pub fn contract_check_ensures<'a, Ret, C: FnOnce(&'a Ret) -> bool>(ret: &'a Ret, c: C) -> bool { - c(ret) +pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { + if contract_checks() && !cond(ret) { + crate::panicking::panic_nounwind("failed ensures check"); + } } /// The intrinsic will return the size stored in that vtable. From 644dfa4c5de016b8a87b5c50e58c872c85b4cbe7 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 30 Jan 2025 17:06:09 -0800 Subject: [PATCH 450/481] Rename rustc_contract to contract This has now been approved as a language feature and no longer needs a `rustc_` prefix. Also change the `contracts` feature to be marked as incomplete and `contracts_internals` as internal. --- core/src/contracts.rs | 2 +- core/src/intrinsics/mod.rs | 8 ++++---- core/src/lib.rs | 2 +- core/src/macros/mod.rs | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/contracts.rs b/core/src/contracts.rs index 0668cacb92c60..c769e219e4d49 100644 --- a/core/src/contracts.rs +++ b/core/src/contracts.rs @@ -6,7 +6,7 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_require /// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` /// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` /// (including the implicit return of the tail expression, if any). -#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] +#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[lang = "contract_build_check_ensures"] #[track_caller] pub fn build_check_ensures(cond: C) -> impl (Fn(Ret) -> Ret) + Copy diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index c3b95c7950360..3b249c835f237 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -4071,8 +4071,8 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) /// checking is turned on, so that we can specify contracts in libstd /// and let an end user opt into turning them on. #[cfg(not(bootstrap))] -#[rustc_const_unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] -#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] +#[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[inline(always)] #[rustc_intrinsic] pub const fn contract_checks() -> bool { @@ -4087,7 +4087,7 @@ pub const fn contract_checks() -> bool { /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] +#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[lang = "contract_check_requires"] #[rustc_intrinsic] pub fn contract_check_requires bool>(cond: C) { @@ -4102,7 +4102,7 @@ pub fn contract_check_requires bool>(cond: C) { /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts_internals", issue = "133866" /* compiler-team#759 */)] +#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { if contract_checks() && !cond(ret) { diff --git a/core/src/lib.rs b/core/src/lib.rs index a416ef80af63f..49ce1bbcf3980 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -249,7 +249,7 @@ pub mod autodiff { } #[cfg(not(bootstrap))] -#[unstable(feature = "rustc_contracts", issue = "133866")] +#[unstable(feature = "contracts", issue = "128044")] pub mod contracts; #[unstable(feature = "cfg_match", issue = "115585")] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index cb37530e90db8..4c6fd196bd31c 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -1783,8 +1783,8 @@ pub(crate) mod builtin { /// eventually parsed as a unary closure expression that is /// invoked on a reference to the return value. #[cfg(not(bootstrap))] - #[unstable(feature = "rustc_contracts", issue = "133866")] - #[allow_internal_unstable(rustc_contracts_internals)] + #[unstable(feature = "contracts", issue = "128044")] + #[allow_internal_unstable(contracts_internals)] #[rustc_builtin_macro] pub macro contracts_ensures($item:item) { /* compiler built-in */ @@ -1796,8 +1796,8 @@ pub(crate) mod builtin { /// eventually parsed as an boolean expression with access to the /// function's formal parameters #[cfg(not(bootstrap))] - #[unstable(feature = "rustc_contracts", issue = "133866")] - #[allow_internal_unstable(rustc_contracts_internals)] + #[unstable(feature = "contracts", issue = "128044")] + #[allow_internal_unstable(contracts_internals)] #[rustc_builtin_macro] pub macro contracts_requires($item:item) { /* compiler built-in */ From a75a25f4689b3c57bc753775caba6c2cc796d7c8 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 3 Feb 2025 19:18:07 +0000 Subject: [PATCH 451/481] Mark `std::fmt::from_fn` as `#[must_use]` --- core/src/fmt/builders.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/fmt/builders.rs b/core/src/fmt/builders.rs index 1862be0e86c5d..665b05b12ec07 100644 --- a/core/src/fmt/builders.rs +++ b/core/src/fmt/builders.rs @@ -1228,6 +1228,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// assert_eq!(format!("{:?}", wrapped), "'a'"); /// ``` #[unstable(feature = "debug_closure_helpers", issue = "117729")] +#[must_use = "returns a type implementing Debug and Display, which do not have any effects unless they are used"] pub fn from_fn) -> fmt::Result>(f: F) -> FromFn { FromFn(f) } From 1dc62392ddc79e53b57d72e16860da2f6328badb Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 19 Jan 2025 22:23:35 +0530 Subject: [PATCH 452/481] uefi: process: Add support for command environment variables Set environment variables before launching the process and restore the prior variables after the program exists. This is the same implementation as the one used by UEFI Shell Execute [0]. [0]: https://github.com/tianocore/edk2/blob/2d2642f4832ebc45cb7d5ba9430b933d953b94f2/ShellPkg/Application/Shell/ShellProtocol.c#L1700 Signed-off-by: Ayush Singh --- std/src/sys/pal/uefi/process.rs | 65 +++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/std/src/sys/pal/uefi/process.rs b/std/src/sys/pal/uefi/process.rs index 3077a72eac661..0757f1cb490d4 100644 --- a/std/src/sys/pal/uefi/process.rs +++ b/std/src/sys/pal/uefi/process.rs @@ -1,6 +1,7 @@ use r_efi::protocols::simple_text_output; use super::helpers; +use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; use crate::num::{NonZero, NonZeroI32}; @@ -21,6 +22,7 @@ pub struct Command { args: Vec, stdout: Option, stderr: Option, + env: CommandEnv, } // passed back to std::process with the pipes connected to the child, if any @@ -40,7 +42,13 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } + Command { + prog: program.to_os_string(), + args: Vec::new(), + stdout: None, + stderr: None, + env: Default::default(), + } } pub fn arg(&mut self, arg: &OsStr) { @@ -48,7 +56,7 @@ impl Command { } pub fn env_mut(&mut self) -> &mut CommandEnv { - panic!("unsupported") + &mut self.env } pub fn cwd(&mut self, _dir: &OsStr) { @@ -76,7 +84,7 @@ impl Command { } pub fn get_envs(&self) -> CommandEnvs<'_> { - panic!("unsupported") + self.env.iter() } pub fn get_current_dir(&self) -> Option<&Path> { @@ -140,8 +148,30 @@ impl Command { cmd.stderr_inherit() }; + let env = env_changes(&self.env); + + // Set any new vars + if let Some(e) = &env { + for (k, (_, v)) in e { + match v { + Some(v) => crate::env::set_var(k, v), + None => crate::env::remove_var(k), + } + } + } + let stat = cmd.start_image()?; + // Rollback any env changes + if let Some(e) = env { + for (k, (v, _)) in e { + match v { + Some(v) => crate::env::set_var(k, v), + None => crate::env::remove_var(k), + } + } + } + let stdout = cmd.stdout()?; let stderr = cmd.stderr()?; @@ -725,3 +755,32 @@ mod uefi_command_internal { res.into_boxed_slice() } } + +/// Create a map of environment variable changes. Allows efficient setting and rolling back of +/// enviroment variable changes. +/// +/// Entry: (Old Value, New Value) +fn env_changes(env: &CommandEnv) -> Option, Option)>> { + if env.is_unchanged() { + return None; + } + + let mut result = BTreeMap::, Option)>::new(); + + // Check if we want to clear all prior variables + if env.does_clear() { + for (k, v) in crate::env::vars_os() { + result.insert(k.into(), (Some(v), None)); + } + } + + for (k, v) in env.iter() { + let v: Option = v.map(Into::into); + result + .entry(k.into()) + .and_modify(|cur| *cur = (cur.0.clone(), v.clone())) + .or_insert((crate::env::var_os(k), v)); + } + + Some(result) +} From 57c6481f8096d414a0c25b5aba875b8f6a39b775 Mon Sep 17 00:00:00 2001 From: joboet Date: Sun, 2 Feb 2025 18:53:52 +0100 Subject: [PATCH 453/481] std: move network code into `sys` As per #117276, this PR moves `sys_common::net` and the `sys::pal::net` into the newly created `sys::net` module. In order to support #135141, I've moved all the current network code into a separate `connection` module, future functions like `hostname` can live in separate modules. I'll probably do a follow-up PR and clean up some of the actual code, this is mostly just a reorganization. --- std/src/net/socket_addr.rs | 3 +- std/src/net/tcp.rs | 3 +- std/src/net/udp.rs | 3 +- std/src/os/fd/net.rs | 4 +- std/src/os/hermit/io/net.rs | 2 +- std/src/os/solid/io.rs | 4 +- std/src/os/windows/io/raw.rs | 8 +- std/src/sys/mod.rs | 1 + .../{pal/sgx/net.rs => net/connection/sgx.rs} | 2 +- .../net.rs => sys/net/connection/socket.rs} | 30 +- .../connection/socket/hermit.rs} | 13 +- .../net.rs => net/connection/socket/solid.rs} | 24 +- .../net/connection/socket}/tests.rs | 0 .../net.rs => net/connection/socket/unix.rs} | 10 +- .../connection/socket/wasip2.rs} | 2 +- .../connection/socket/windows.rs} | 21 +- .../net.rs => net/connection/unsupported.rs} | 0 .../wasi/net.rs => net/connection/wasip1.rs} | 5 +- .../xous/net => net/connection/xous}/dns.rs | 0 .../xous/net => net/connection/xous}/mod.rs | 0 .../connection/xous}/tcplistener.rs | 0 .../net => net/connection/xous}/tcpstream.rs | 0 .../xous/net => net/connection/xous}/udp.rs | 0 std/src/sys/net/mod.rs | 36 ++ std/src/sys/pal/hermit/mod.rs | 1 - std/src/sys/pal/sgx/mod.rs | 1 - std/src/sys/pal/solid/error.rs | 3 +- std/src/sys/pal/solid/mod.rs | 3 +- std/src/sys/pal/teeos/mod.rs | 1 - std/src/sys/pal/teeos/net.rs | 369 ------------ std/src/sys/pal/uefi/mod.rs | 2 - std/src/sys/pal/unix/l4re.rs | 564 ------------------ std/src/sys/pal/unix/mod.rs | 6 - std/src/sys/pal/unsupported/mod.rs | 1 - std/src/sys/pal/wasi/mod.rs | 4 +- std/src/sys/pal/wasip2/mod.rs | 1 - std/src/sys/pal/wasm/mod.rs | 2 - std/src/sys/pal/windows/mod.rs | 3 +- std/src/sys/pal/xous/mod.rs | 1 - std/src/sys/pal/zkvm/mod.rs | 2 - std/src/sys_common/mod.rs | 14 - 41 files changed, 113 insertions(+), 1036 deletions(-) rename std/src/sys/{pal/sgx/net.rs => net/connection/sgx.rs} (99%) rename std/src/{sys_common/net.rs => sys/net/connection/socket.rs} (97%) rename std/src/sys/{pal/hermit/net.rs => net/connection/socket/hermit.rs} (98%) rename std/src/sys/{pal/solid/net.rs => net/connection/socket/solid.rs} (95%) rename std/src/{sys_common/net => sys/net/connection/socket}/tests.rs (100%) rename std/src/sys/{pal/unix/net.rs => net/connection/socket/unix.rs} (99%) rename std/src/sys/{pal/wasip2/net.rs => net/connection/socket/wasip2.rs} (99%) rename std/src/sys/{pal/windows/net.rs => net/connection/socket/windows.rs} (95%) rename std/src/sys/{pal/unsupported/net.rs => net/connection/unsupported.rs} (100%) rename std/src/sys/{pal/wasi/net.rs => net/connection/wasip1.rs} (99%) rename std/src/sys/{pal/xous/net => net/connection/xous}/dns.rs (100%) rename std/src/sys/{pal/xous/net => net/connection/xous}/mod.rs (100%) rename std/src/sys/{pal/xous/net => net/connection/xous}/tcplistener.rs (100%) rename std/src/sys/{pal/xous/net => net/connection/xous}/tcpstream.rs (100%) rename std/src/sys/{pal/xous/net => net/connection/xous}/udp.rs (100%) create mode 100644 std/src/sys/net/mod.rs delete mode 100644 std/src/sys/pal/teeos/net.rs delete mode 100644 std/src/sys/pal/unix/l4re.rs diff --git a/std/src/net/socket_addr.rs b/std/src/net/socket_addr.rs index ba9c948a2e96f..e8355cc31d7a5 100644 --- a/std/src/net/socket_addr.rs +++ b/std/src/net/socket_addr.rs @@ -6,8 +6,7 @@ mod tests; pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use crate::sys::net::netc as c; -use crate::sys_common::net::LookupHost; +use crate::sys::net::{LookupHost, netc as c}; use crate::sys_common::{FromInner, IntoInner}; use crate::{io, iter, mem, option, slice, vec}; diff --git a/std/src/net/tcp.rs b/std/src/net/tcp.rs index 67a0f7e439d55..9b68f872955c0 100644 --- a/std/src/net/tcp.rs +++ b/std/src/net/tcp.rs @@ -15,7 +15,8 @@ use crate::io::prelude::*; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::iter::FusedIterator; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; -use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp}; +use crate::sys::net as net_imp; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; /// A TCP stream between a local and a remote socket. diff --git a/std/src/net/udp.rs b/std/src/net/udp.rs index 674c5fb7d6ea3..3eb798ad34aaa 100644 --- a/std/src/net/udp.rs +++ b/std/src/net/udp.rs @@ -12,7 +12,8 @@ mod tests; use crate::fmt; use crate::io::{self, ErrorKind}; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; -use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp}; +use crate::sys::net as net_imp; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; /// A UDP socket. diff --git a/std/src/os/fd/net.rs b/std/src/os/fd/net.rs index 843f45f7f5f98..34479ca0e190e 100644 --- a/std/src/os/fd/net.rs +++ b/std/src/os/fd/net.rs @@ -1,6 +1,6 @@ use crate::os::fd::owned::OwnedFd; use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{net, sys}; macro_rules! impl_as_raw_fd { @@ -24,7 +24,7 @@ macro_rules! impl_from_raw_fd { unsafe fn from_raw_fd(fd: RawFd) -> net::$t { unsafe { let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); - net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + net::$t::from_inner(sys::net::$t::from_inner(socket)) } } } diff --git a/std/src/os/hermit/io/net.rs b/std/src/os/hermit/io/net.rs index 7a774345b231a..233bc885fc733 100644 --- a/std/src/os/hermit/io/net.rs +++ b/std/src/os/hermit/io/net.rs @@ -23,7 +23,7 @@ macro_rules! impl_from_raw_fd { unsafe fn from_raw_fd(fd: RawFd) -> net::$t { unsafe { let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); - net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + net::$t::from_inner(sys::net::$t::from_inner(socket)) } } } diff --git a/std/src/os/solid/io.rs b/std/src/os/solid/io.rs index b8601b533fe0d..b8c3440542d00 100644 --- a/std/src/os/solid/io.rs +++ b/std/src/os/solid/io.rs @@ -48,7 +48,7 @@ use crate::marker::PhantomData; use crate::mem::ManuallyDrop; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, net, sys}; /// Raw file descriptors. @@ -387,7 +387,7 @@ macro_rules! impl_from_raw_fd { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::$t { let socket = unsafe { sys::net::Socket::from_raw_fd(fd) }; - net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + net::$t::from_inner(sys::net::$t::from_inner(socket)) } } )*}; diff --git a/std/src/os/windows/io/raw.rs b/std/src/os/windows/io/raw.rs index 6658248d574c9..c0517fab95068 100644 --- a/std/src/os/windows/io/raw.rs +++ b/std/src/os/windows/io/raw.rs @@ -6,7 +6,7 @@ use crate::os::windows::io::{AsHandle, AsSocket}; use crate::os::windows::io::{OwnedHandle, OwnedSocket}; use crate::os::windows::raw; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fs, io, net, ptr, sys}; /// Raw HANDLEs. @@ -262,7 +262,7 @@ impl FromRawSocket for net::TcpStream { unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { unsafe { let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) + net::TcpStream::from_inner(sys::net::TcpStream::from_inner(sock)) } } } @@ -272,7 +272,7 @@ impl FromRawSocket for net::TcpListener { unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { unsafe { let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) + net::TcpListener::from_inner(sys::net::TcpListener::from_inner(sock)) } } } @@ -282,7 +282,7 @@ impl FromRawSocket for net::UdpSocket { unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { unsafe { let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) + net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(sock)) } } } diff --git a/std/src/sys/mod.rs b/std/src/sys/mod.rs index f17dd47decedc..39a0bc6e337c6 100644 --- a/std/src/sys/mod.rs +++ b/std/src/sys/mod.rs @@ -12,6 +12,7 @@ pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; pub mod exit_guard; +pub mod net; pub mod os_str; pub mod path; pub mod random; diff --git a/std/src/sys/pal/sgx/net.rs b/std/src/sys/net/connection/sgx.rs similarity index 99% rename from std/src/sys/pal/sgx/net.rs rename to std/src/sys/net/connection/sgx.rs index c966886d16344..b390a5eac5f74 100644 --- a/std/src/sys/pal/sgx/net.rs +++ b/std/src/sys/net/connection/sgx.rs @@ -1,7 +1,7 @@ -use super::abi::usercalls; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::Arc; +use crate::sys::abi::usercalls; use crate::sys::fd::FileDesc; use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported}; use crate::time::Duration; diff --git a/std/src/sys_common/net.rs b/std/src/sys/net/connection/socket.rs similarity index 97% rename from std/src/sys_common/net.rs rename to std/src/sys/net/connection/socket.rs index 74306978d2284..6fe3430b53f79 100644 --- a/std/src/sys_common/net.rs +++ b/std/src/sys/net/connection/socket.rs @@ -5,11 +5,31 @@ use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::sys::common::small_c_string::run_with_cstr; -use crate::sys::net::{Socket, cvt, cvt_gai, cvt_r, init, netc as c, wrlen_t}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, fmt, mem, ptr}; +cfg_if::cfg_if! { + if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_family = "unix")] { + mod unix; + pub use unix::*; + } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] { + mod wasip2; + pub use wasip2::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } +} + +use netc as c; + cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", @@ -24,11 +44,11 @@ cfg_if::cfg_if! { target_os = "nuttx", target_vendor = "apple", ))] { - use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; - use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; } else { - use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP; - use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; + use c::IPV6_ADD_MEMBERSHIP; + use c::IPV6_DROP_MEMBERSHIP; } } diff --git a/std/src/sys/pal/hermit/net.rs b/std/src/sys/net/connection/socket/hermit.rs similarity index 98% rename from std/src/sys/pal/hermit/net.rs rename to std/src/sys/net/connection/socket/hermit.rs index 4e12374203e38..42179dcc9156d 100644 --- a/std/src/sys/pal/hermit/net.rs +++ b/std/src/sys/net/connection/socket/hermit.rs @@ -2,21 +2,20 @@ use core::ffi::c_int; -use super::fd::FileDesc; +pub(crate) use hermit_abi as netc; + use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; +use crate::sys::fd::FileDesc; +use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys::time::Instant; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; +pub use crate::sys::{cvt, cvt_r}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, mem}; -#[allow(unused_extern_crates)] -pub extern crate hermit_abi as netc; - -pub use crate::sys::{cvt, cvt_r}; - +#[expect(non_camel_case_types)] pub type wrlen_t = usize; pub fn cvt_gai(err: i32) -> io::Result<()> { diff --git a/std/src/sys/pal/solid/net.rs b/std/src/sys/net/connection/socket/solid.rs similarity index 95% rename from std/src/sys/pal/solid/net.rs rename to std/src/sys/net/connection/socket/solid.rs index 5f6436807e27e..f85ecbb883ee7 100644 --- a/std/src/sys/pal/solid/net.rs +++ b/std/src/sys/net/connection/socket/solid.rs @@ -1,24 +1,23 @@ use libc::{c_int, c_void, size_t}; use self::netc::{MSG_PEEK, sockaddr, socklen_t}; -use super::abi; use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; +use crate::sys::abi; +use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, mem, ptr, str}; pub mod netc { - pub use super::super::abi::sockets::*; + pub use crate::sys::abi::sockets::*; } +#[expect(non_camel_case_types)] pub type wrlen_t = size_t; -const READ_LIMIT: usize = libc::ssize_t::MAX as usize; - const fn max_iov() -> usize { // Judging by the source code, it's unlimited, but specify a lower // value just in case. @@ -78,7 +77,7 @@ fn last_error() -> io::Error { io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() }) } -pub(super) fn error_name(er: abi::ER) -> Option<&'static str> { +pub fn error_name(er: abi::ER) -> Option<&'static str> { unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok() } @@ -87,7 +86,7 @@ pub fn is_interrupted(er: abi::ER) -> bool { er == netc::SOLID_NET_ERR_BASE - libc::EINTR } -pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind { +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { let errno = netc::SOLID_NET_ERR_BASE - er; match errno as libc::c_int { libc::ECONNREFUSED => ErrorKind::ConnectionRefused, @@ -268,17 +267,6 @@ impl Socket { self.recv_from_with_flags(buf, MSG_PEEK) } - pub fn write(&self, buf: &[u8]) -> io::Result { - let ret = cvt(unsafe { - netc::write( - self.as_raw_fd(), - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), READ_LIMIT), - ) - })?; - Ok(ret as usize) - } - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { netc::writev( diff --git a/std/src/sys_common/net/tests.rs b/std/src/sys/net/connection/socket/tests.rs similarity index 100% rename from std/src/sys_common/net/tests.rs rename to std/src/sys/net/connection/socket/tests.rs diff --git a/std/src/sys/pal/unix/net.rs b/std/src/sys/net/connection/socket/unix.rs similarity index 99% rename from std/src/sys/pal/unix/net.rs rename to std/src/sys/net/connection/socket/unix.rs index d73b9fd5eb882..da6316055273f 100644 --- a/std/src/sys/pal/unix/net.rs +++ b/std/src/sys/net/connection/socket/unix.rs @@ -5,8 +5,8 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; -use crate::sys::pal::unix::IsMinusOne; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; +use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; +use crate::sys::pal::IsMinusOne; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; use crate::{cmp, mem}; @@ -19,11 +19,11 @@ cfg_if::cfg_if! { } } -pub use crate::sys::{cvt, cvt_r}; +pub(crate) use libc as netc; -#[allow(unused_extern_crates)] -pub extern crate libc as netc; +pub use crate::sys::{cvt, cvt_r}; +#[expect(non_camel_case_types)] pub type wrlen_t = size_t; pub struct Socket(FileDesc); diff --git a/std/src/sys/pal/wasip2/net.rs b/std/src/sys/net/connection/socket/wasip2.rs similarity index 99% rename from std/src/sys/pal/wasip2/net.rs rename to std/src/sys/net/connection/socket/wasip2.rs index f009a51821f35..9d1c05a473e4d 100644 --- a/std/src/sys/pal/wasip2/net.rs +++ b/std/src/sys/net/connection/socket/wasip2.rs @@ -6,8 +6,8 @@ use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys::unsupported; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; use crate::{cmp, mem, str}; diff --git a/std/src/sys/pal/windows/net.rs b/std/src/sys/net/connection/socket/windows.rs similarity index 95% rename from std/src/sys/pal/windows/net.rs rename to std/src/sys/net/connection/socket/windows.rs index a92853c642c06..80cf37eaf0580 100644 --- a/std/src/sys/pal/windows/net.rs +++ b/std/src/sys/net/connection/socket/windows.rs @@ -9,7 +9,7 @@ use crate::os::windows::io::{ }; use crate::sync::OnceLock; use crate::sys::c; -use crate::sys_common::{AsInner, FromInner, IntoInner, net}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, mem, ptr, sys}; @@ -110,6 +110,7 @@ pub mod netc { } } +#[expect(missing_debug_implementations)] pub struct Socket(OwnedSocket); static WSA_CLEANUP: OnceLock i32> = OnceLock::new(); @@ -400,12 +401,12 @@ impl Socket { let error = unsafe { c::WSAGetLastError() }; if error == c::WSAESHUTDOWN { - Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?)) + Ok((0, super::sockaddr_to_addr(&storage, addrlen as usize)?)) } else { Err(io::Error::from_raw_os_error(error)) } } - _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), + _ => Ok((result as usize, super::sockaddr_to_addr(&storage, addrlen as usize)?)), } } @@ -450,11 +451,11 @@ impl Socket { } None => 0, }; - net::setsockopt(self, c::SOL_SOCKET, kind, timeout) + super::setsockopt(self, c::SOL_SOCKET, kind, timeout) } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: u32 = net::getsockopt(self, c::SOL_SOCKET, kind)?; + let raw: u32 = super::getsockopt(self, c::SOL_SOCKET, kind)?; if raw == 0 { Ok(None) } else { @@ -487,26 +488,26 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; - net::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) + super::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) } pub fn linger(&self) -> io::Result> { - let val: c::LINGER = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = super::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) + super::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } pub fn nodelay(&self) -> io::Result { - let raw: c::BOOL = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; + let raw: c::BOOL = super::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; Ok(raw != 0) } pub fn take_error(&self) -> io::Result> { - let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; + let raw: c_int = super::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/std/src/sys/pal/unsupported/net.rs b/std/src/sys/net/connection/unsupported.rs similarity index 100% rename from std/src/sys/pal/unsupported/net.rs rename to std/src/sys/net/connection/unsupported.rs diff --git a/std/src/sys/pal/wasi/net.rs b/std/src/sys/net/connection/wasip1.rs similarity index 99% rename from std/src/sys/pal/wasi/net.rs rename to std/src/sys/net/connection/wasip1.rs index a648679982812..27e3a528af497 100644 --- a/std/src/sys/pal/wasi/net.rs +++ b/std/src/sys/net/connection/wasip1.rs @@ -1,12 +1,11 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use super::err2io; -use super::fd::WasiFd; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys::unsupported; +use crate::sys::fd::WasiFd; +use crate::sys::{err2io, unsupported}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; diff --git a/std/src/sys/pal/xous/net/dns.rs b/std/src/sys/net/connection/xous/dns.rs similarity index 100% rename from std/src/sys/pal/xous/net/dns.rs rename to std/src/sys/net/connection/xous/dns.rs diff --git a/std/src/sys/pal/xous/net/mod.rs b/std/src/sys/net/connection/xous/mod.rs similarity index 100% rename from std/src/sys/pal/xous/net/mod.rs rename to std/src/sys/net/connection/xous/mod.rs diff --git a/std/src/sys/pal/xous/net/tcplistener.rs b/std/src/sys/net/connection/xous/tcplistener.rs similarity index 100% rename from std/src/sys/pal/xous/net/tcplistener.rs rename to std/src/sys/net/connection/xous/tcplistener.rs diff --git a/std/src/sys/pal/xous/net/tcpstream.rs b/std/src/sys/net/connection/xous/tcpstream.rs similarity index 100% rename from std/src/sys/pal/xous/net/tcpstream.rs rename to std/src/sys/net/connection/xous/tcpstream.rs diff --git a/std/src/sys/pal/xous/net/udp.rs b/std/src/sys/net/connection/xous/udp.rs similarity index 100% rename from std/src/sys/pal/xous/net/udp.rs rename to std/src/sys/net/connection/xous/udp.rs diff --git a/std/src/sys/net/mod.rs b/std/src/sys/net/mod.rs new file mode 100644 index 0000000000000..5aa197fbc0df3 --- /dev/null +++ b/std/src/sys/net/mod.rs @@ -0,0 +1,36 @@ +cfg_if::cfg_if! { + if #[cfg(any( + all(target_family = "unix", not(target_os = "l4re")), + target_os = "windows", + target_os = "hermit", + all(target_os = "wasi", target_env = "p2"), + target_os = "solid_asp3", + ))] { + mod connection { + mod socket; + pub use socket::*; + } + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod connection { + mod sgx; + pub use sgx::*; + } + } else if #[cfg(all(target_os = "wasi", target_env = "p1"))] { + mod connection { + mod wasip1; + pub use wasip1::*; + } + } else if #[cfg(target_os = "xous")] { + mod connection { + mod xous; + pub use xous::*; + } + } else { + mod connection { + mod unsupported; + pub use unsupported::*; + } + } +} + +pub use connection::*; diff --git a/std/src/sys/pal/hermit/mod.rs b/std/src/sys/pal/hermit/mod.rs index d833c9d632c6d..032007aa4dca5 100644 --- a/std/src/sys/pal/hermit/mod.rs +++ b/std/src/sys/pal/hermit/mod.rs @@ -24,7 +24,6 @@ pub mod fd; pub mod fs; pub mod futex; pub mod io; -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/sgx/mod.rs b/std/src/sys/pal/sgx/mod.rs index ce8a2fed4bc6b..0f5935d0c7184 100644 --- a/std/src/sys/pal/sgx/mod.rs +++ b/std/src/sys/pal/sgx/mod.rs @@ -17,7 +17,6 @@ pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; mod libunwind_integration; -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/solid/error.rs b/std/src/sys/pal/solid/error.rs index e092497856d43..b399463c0c280 100644 --- a/std/src/sys/pal/solid/error.rs +++ b/std/src/sys/pal/solid/error.rs @@ -1,6 +1,7 @@ pub use self::itron::error::{ItronError as SolidError, expect_success}; -use super::{abi, itron, net}; +use super::{abi, itron}; use crate::io::ErrorKind; +use crate::sys::net; /// Describe the specified SOLID error code. Returns `None` if it's an /// undefined error code. diff --git a/std/src/sys/pal/solid/mod.rs b/std/src/sys/pal/solid/mod.rs index d41042be51844..caf848a4e9b07 100644 --- a/std/src/sys/pal/solid/mod.rs +++ b/std/src/sys/pal/solid/mod.rs @@ -24,7 +24,6 @@ pub mod env; pub(crate) mod error; pub mod fs; pub mod io; -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; @@ -51,7 +50,7 @@ pub fn unsupported_err() -> crate::io::Error { #[inline] pub fn is_interrupted(code: i32) -> bool { - net::is_interrupted(code) + crate::sys::net::is_interrupted(code) } pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { diff --git a/std/src/sys/pal/teeos/mod.rs b/std/src/sys/pal/teeos/mod.rs index a9900f55b1926..a9904e66664e3 100644 --- a/std/src/sys/pal/teeos/mod.rs +++ b/std/src/sys/pal/teeos/mod.rs @@ -15,7 +15,6 @@ pub mod env; pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/teeos/net.rs b/std/src/sys/pal/teeos/net.rs deleted file mode 100644 index fed95205027a7..0000000000000 --- a/std/src/sys/pal/teeos/net.rs +++ /dev/null @@ -1,369 +0,0 @@ -use crate::fmt; -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; -use crate::sys::unsupported; -use crate::time::Duration; - -pub struct TcpStream(!); - -impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unsupported() - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn read_timeout(&self) -> io::Result> { - self.0 - } - - pub fn write_timeout(&self) -> io::Result> { - self.0 - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { - self.0 - } - - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 - } - - pub fn is_read_vectored(&self) -> bool { - self.0 - } - - pub fn write(&self, _: &[u8]) -> io::Result { - self.0 - } - - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - self.0 - } - - pub fn is_write_vectored(&self) -> bool { - self.0 - } - - pub fn peer_addr(&self) -> io::Result { - self.0 - } - - pub fn socket_addr(&self) -> io::Result { - self.0 - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_linger(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn linger(&self) -> io::Result> { - self.0 - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn nodelay(&self) -> io::Result { - self.0 - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn ttl(&self) -> io::Result { - self.0 - } - - pub fn take_error(&self) -> io::Result> { - self.0 - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 - } -} - -impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub struct TcpListener(!); - -impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - self.0 - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn ttl(&self) -> io::Result { - self.0 - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn only_v6(&self) -> io::Result { - self.0 - } - - pub fn take_error(&self) -> io::Result> { - self.0 - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 - } -} - -impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub struct UdpSocket(!); - -impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() - } - - pub fn peer_addr(&self) -> io::Result { - self.0 - } - - pub fn socket_addr(&self) -> io::Result { - self.0 - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.0 - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.0 - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn read_timeout(&self) -> io::Result> { - self.0 - } - - pub fn write_timeout(&self) -> io::Result> { - self.0 - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn broadcast(&self) -> io::Result { - self.0 - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn multicast_loop_v4(&self) -> io::Result { - self.0 - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - self.0 - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn multicast_loop_v6(&self) -> io::Result { - self.0 - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - self.0 - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - self.0 - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - self.0 - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - self.0 - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn ttl(&self) -> io::Result { - self.0 - } - - pub fn take_error(&self) -> io::Result> { - self.0 - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn send(&self, _: &[u8]) -> io::Result { - self.0 - } - - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { - self.0 - } -} - -impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub struct LookupHost(!); - -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - self.0 - } -} - -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result { - unsupported() - } -} - -#[allow(nonstandard_style)] -pub mod netc { - pub const AF_INET: u8 = 0; - pub const AF_INET6: u8 = 1; - pub type sa_family_t = u8; - - #[derive(Copy, Clone)] - pub struct in_addr { - pub s_addr: u32, - } - - #[derive(Copy, Clone)] - pub struct sockaddr_in { - pub sin_family: sa_family_t, - pub sin_port: u16, - pub sin_addr: in_addr, - } - - #[derive(Copy, Clone)] - pub struct in6_addr { - pub s6_addr: [u8; 16], - } - - #[derive(Copy, Clone)] - pub struct sockaddr_in6 { - pub sin6_family: sa_family_t, - pub sin6_port: u16, - pub sin6_addr: in6_addr, - pub sin6_flowinfo: u32, - pub sin6_scope_id: u32, - } -} - -pub type Socket = UdpSocket; diff --git a/std/src/sys/pal/uefi/mod.rs b/std/src/sys/pal/uefi/mod.rs index 111bed7a7eb64..07025a304bfd7 100644 --- a/std/src/sys/pal/uefi/mod.rs +++ b/std/src/sys/pal/uefi/mod.rs @@ -19,8 +19,6 @@ pub mod fs; pub mod helpers; #[path = "../unsupported/io.rs"] pub mod io; -#[path = "../unsupported/net.rs"] -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/unix/l4re.rs b/std/src/sys/pal/unix/l4re.rs deleted file mode 100644 index 37dd370c5146c..0000000000000 --- a/std/src/sys/pal/unix/l4re.rs +++ /dev/null @@ -1,564 +0,0 @@ -macro_rules! unimpl { - () => { - return Err(io::const_error!( - io::ErrorKind::Unsupported, - "No networking available on L4Re.", - )); - }; -} - -pub mod net { - #![allow(warnings)] - use crate::fmt; - use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; - use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; - use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; - use crate::sys::fd::FileDesc; - use crate::sys_common::{AsInner, FromInner, IntoInner}; - use crate::time::Duration; - - #[allow(unused_extern_crates)] - pub extern crate libc as netc; - - pub struct Socket(FileDesc); - impl Socket { - pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result { - unimpl!(); - } - - pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result { - unimpl!(); - } - - pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> { - unimpl!(); - } - - pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> { - unimpl!(); - } - - pub fn accept( - &self, - _: *mut libc::sockaddr, - _: *mut libc::socklen_t, - ) -> io::Result { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> { - unimpl!(); - } - - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - unimpl!(); - } - - pub fn is_read_vectored(&self) -> bool { - false - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn write(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - unimpl!(); - } - - pub fn is_write_vectored(&self) -> bool { - false - } - - pub fn set_timeout(&self, _: Option, _: libc::c_int) -> io::Result<()> { - unimpl!(); - } - - pub fn timeout(&self, _: libc::c_int) -> io::Result> { - unimpl!(); - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - unimpl!(); - } - - pub fn set_linger(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn linger(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn nodelay(&self) -> io::Result { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - // This is used by sys_common code to abstract over Windows and Unix. - pub fn as_raw(&self) -> RawFd { - self.as_raw_fd() - } - } - - impl AsInner for Socket { - #[inline] - fn as_inner(&self) -> &FileDesc { - &self.0 - } - } - - impl FromInner for Socket { - fn from_inner(file_desc: FileDesc) -> Socket { - Socket(file_desc) - } - } - - impl IntoInner for Socket { - fn into_inner(self) -> FileDesc { - self.0 - } - } - - impl AsFd for Socket { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } - } - - impl AsRawFd for Socket { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } - } - - impl IntoRawFd for Socket { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } - } - - impl FromRawFd for Socket { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - Self(FromRawFd::from_raw_fd(raw_fd)) - } - } - - pub struct TcpStream { - inner: Socket, - } - - impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { - unimpl!(); - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unimpl!(); - } - - #[inline] - pub fn socket(&self) -> &Socket { - &self.inner - } - - pub fn into_socket(self) -> Socket { - self.inner - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn read_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn write_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> { - unimpl!(); - } - - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - unimpl!(); - } - - pub fn is_read_vectored(&self) -> bool { - false - } - - pub fn write(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - unimpl!(); - } - - pub fn is_write_vectored(&self) -> bool { - false - } - - pub fn peer_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_linger(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn linger(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn nodelay(&self) -> io::Result { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for TcpStream { - fn from_inner(socket: Socket) -> TcpStream { - TcpStream { inner: socket } - } - } - - impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "No networking support available on L4Re") - } - } - - pub struct TcpListener { - inner: Socket, - } - - impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { - unimpl!(); - } - - #[inline] - pub fn socket(&self) -> &Socket { - &self.inner - } - - pub fn into_socket(self) -> Socket { - self.inner - } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn only_v6(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for TcpListener { - fn from_inner(socket: Socket) -> TcpListener { - TcpListener { inner: socket } - } - } - - impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "No networking support available on L4Re.") - } - } - - pub struct UdpSocket { - inner: Socket, - } - - impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { - unimpl!(); - } - - #[inline] - pub fn socket(&self) -> &Socket { - &self.inner - } - - pub fn into_socket(self) -> Socket { - self.inner - } - - pub fn peer_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn read_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn write_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn broadcast(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_loop_v4(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_loop_v6(&self) -> io::Result { - unimpl!(); - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - unimpl!(); - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - unimpl!(); - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn send(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for UdpSocket { - fn from_inner(socket: Socket) -> UdpSocket { - UdpSocket { inner: socket } - } - } - - impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "No networking support on L4Re available.") - } - } - - pub struct LookupHost { - original: *mut libc::addrinfo, - cur: *mut libc::addrinfo, - } - - impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - None - } - } - - impl LookupHost { - pub fn port(&self) -> u16 { - 0 // unimplemented - } - } - - unsafe impl Sync for LookupHost {} - unsafe impl Send for LookupHost {} - - impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result { - unimpl!(); - } - } - - impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result { - unimpl!(); - } - } -} diff --git a/std/src/sys/pal/unix/mod.rs b/std/src/sys/pal/unix/mod.rs index 3cc1cae8d000e..6862399b9425c 100644 --- a/std/src/sys/pal/unix/mod.rs +++ b/std/src/sys/pal/unix/mod.rs @@ -14,14 +14,8 @@ pub mod futex; pub mod io; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod kernel_copy; -#[cfg(target_os = "l4re")] -mod l4re; #[cfg(target_os = "linux")] pub mod linux; -#[cfg(not(target_os = "l4re"))] -pub mod net; -#[cfg(target_os = "l4re")] -pub use self::l4re::net; pub mod os; pub mod pipe; pub mod process; diff --git a/std/src/sys/pal/unsupported/mod.rs b/std/src/sys/pal/unsupported/mod.rs index 01d516f7568bf..4941dd4918c86 100644 --- a/std/src/sys/pal/unsupported/mod.rs +++ b/std/src/sys/pal/unsupported/mod.rs @@ -4,7 +4,6 @@ pub mod args; pub mod env; pub mod fs; pub mod io; -pub mod net; pub mod os; pub mod pipe; pub mod process; diff --git a/std/src/sys/pal/wasi/mod.rs b/std/src/sys/pal/wasi/mod.rs index 361802d101dfb..312ad28ab51c8 100644 --- a/std/src/sys/pal/wasi/mod.rs +++ b/std/src/sys/pal/wasi/mod.rs @@ -22,7 +22,6 @@ pub mod fs; pub mod futex; pub mod io; -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; @@ -45,5 +44,4 @@ mod helpers; // import conflict rules. If we glob export `helpers` and `common` together, // then the compiler complains about conflicts. -use helpers::err2io; -pub use helpers::{abort_internal, decode_error_kind, is_interrupted}; +pub(crate) use helpers::{abort_internal, decode_error_kind, err2io, is_interrupted}; diff --git a/std/src/sys/pal/wasip2/mod.rs b/std/src/sys/pal/wasip2/mod.rs index 320712fdcc9fe..234e946d3b8ca 100644 --- a/std/src/sys/pal/wasip2/mod.rs +++ b/std/src/sys/pal/wasip2/mod.rs @@ -20,7 +20,6 @@ pub mod futex; #[path = "../wasi/io.rs"] pub mod io; -pub mod net; #[path = "../wasi/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/std/src/sys/pal/wasm/mod.rs b/std/src/sys/pal/wasm/mod.rs index 41fe019f11027..1280f3532001a 100644 --- a/std/src/sys/pal/wasm/mod.rs +++ b/std/src/sys/pal/wasm/mod.rs @@ -23,8 +23,6 @@ pub mod env; pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; -#[path = "../unsupported/net.rs"] -pub mod net; #[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/std/src/sys/pal/windows/mod.rs b/std/src/sys/pal/windows/mod.rs index 4282dbb54934f..f9aa049ca9ae6 100644 --- a/std/src/sys/pal/windows/mod.rs +++ b/std/src/sys/pal/windows/mod.rs @@ -22,7 +22,6 @@ pub mod fs; pub mod futex; pub mod handle; pub mod io; -pub mod net; pub mod os; pub mod pipe; pub mod process; @@ -63,7 +62,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { - net::cleanup(); + crate::sys::net::cleanup(); } #[inline] diff --git a/std/src/sys/pal/xous/mod.rs b/std/src/sys/pal/xous/mod.rs index a64cd06856006..8ba2b6e2f20fd 100644 --- a/std/src/sys/pal/xous/mod.rs +++ b/std/src/sys/pal/xous/mod.rs @@ -7,7 +7,6 @@ pub mod env; pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/zkvm/mod.rs b/std/src/sys/pal/zkvm/mod.rs index 6ea057720296d..9e9ae86107033 100644 --- a/std/src/sys/pal/zkvm/mod.rs +++ b/std/src/sys/pal/zkvm/mod.rs @@ -18,8 +18,6 @@ pub mod env; pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; -#[path = "../unsupported/net.rs"] -pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys_common/mod.rs b/std/src/sys_common/mod.rs index 4f7a131f6bb90..959fbd4ca0a11 100644 --- a/std/src/sys_common/mod.rs +++ b/std/src/sys_common/mod.rs @@ -26,20 +26,6 @@ pub mod process; pub mod wstr; pub mod wtf8; -cfg_if::cfg_if! { - if #[cfg(any( - all(unix, not(target_os = "l4re")), - windows, - target_os = "hermit", - target_os = "solid_asp3", - all(target_os = "wasi", target_env = "p2") - ))] { - pub mod net; - } else { - pub use crate::sys::net; - } -} - // common error constructors /// A trait for viewing representations from std types From c1437eeeebabfdd586bd056b57ed3e18144b19d4 Mon Sep 17 00:00:00 2001 From: may Date: Mon, 3 Feb 2025 23:25:24 +0100 Subject: [PATCH 454/481] implement inherent str constructors --- core/src/str/mod.rs | 176 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 39fa6c1a25fe9..17fb43b7830eb 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -160,6 +160,182 @@ impl str { self.len() == 0 } + /// Converts a slice of bytes to a string slice. + /// + /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice + /// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between + /// the two. Not all byte slices are valid string slices, however: [`&str`] requires + /// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid + /// UTF-8, and then does the conversion. + /// + /// [`&str`]: str + /// [byteslice]: slice + /// + /// If you are sure that the byte slice is valid UTF-8, and you don't want to + /// incur the overhead of the validity check, there is an unsafe version of + /// this function, [`from_utf8_unchecked`], which has the same + /// behavior but skips the check. + /// + /// If you need a `String` instead of a `&str`, consider + /// [`String::from_utf8`][string]. + /// + /// [string]: ../std/string/struct.String.html#method.from_utf8 + /// + /// Because you can stack-allocate a `[u8; N]`, and you can take a + /// [`&[u8]`][byteslice] of it, this function is one way to have a + /// stack-allocated string. There is an example of this in the + /// examples section below. + /// + /// [byteslice]: slice + /// + /// # Errors + /// + /// Returns `Err` if the slice is not UTF-8 with a description as to why the + /// provided slice is not UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// // We can use the ? (try) operator to check if the bytes are valid + /// let sparkle_heart = str::from_utf8(&sparkle_heart)?; + /// + /// assert_eq!("💖", sparkle_heart); + /// # Ok::<_, str::Utf8Error>(()) + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// use std::str; + /// + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// assert!(str::from_utf8(&sparkle_heart).is_err()); + /// ``` + /// + /// See the docs for [`Utf8Error`] for more details on the kinds of + /// errors that can be returned. + /// + /// A "stack allocated string": + /// + /// ``` + /// use std::str; + /// + /// // some bytes, in a stack-allocated array + /// let sparkle_heart = [240, 159, 146, 150]; + /// + /// // We know these bytes are valid, so just use `unwrap()`. + /// let sparkle_heart: &str = str::from_utf8(&sparkle_heart).unwrap(); + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { + converts::from_utf8(v) + } + + /// Converts a mutable slice of bytes to a mutable string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // "Hello, Rust!" as a mutable vector + /// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; + /// + /// // As we know these bytes are valid, we can use `unwrap()` + /// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); + /// + /// assert_eq!("Hello, Rust!", outstr); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// use std::str; + /// + /// // Some invalid bytes in a mutable vector + /// let mut invalid = vec![128, 223]; + /// + /// assert!(str::from_utf8_mut(&mut invalid).is_err()); + /// ``` + /// See the docs for [`Utf8Error`] for more details on the kinds of + /// errors that can be returned. + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] + pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + converts::from_utf8_mut(v) + } + + /// Converts a slice of bytes to a string slice without checking + /// that the string contains valid UTF-8. + /// + /// See the safe version, [`from_utf8`], for more information. + /// + /// # Safety + /// + /// The bytes passed in must be valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// let sparkle_heart = unsafe { + /// str::from_utf8_unchecked(&sparkle_heart) + /// }; + /// + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { + // SAFETY: converts::from_utf8_unchecked has the same safety requirements as this function. + unsafe { converts::from_utf8_unchecked(v) } + } + + /// Converts a slice of bytes to a string slice without checking + /// that the string contains valid UTF-8; mutable version. + /// + /// See the immutable version, [`from_utf8_unchecked()`] for more information. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// let mut heart = vec![240, 159, 146, 150]; + /// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; + /// + /// assert_eq!("💖", heart); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "inherent_str_constructors", issue = "131114")] + pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + // SAFETY: converts::from_utf8_unchecked_mut has the same safety requirements as this function. + unsafe { converts::from_utf8_unchecked_mut(v) } + } + /// Checks that `index`-th byte is the first byte in a UTF-8 code point /// sequence or the end of the string. /// From 0f21e5b706497678af7db9bf920582d56a02e58e Mon Sep 17 00:00:00 2001 From: may Date: Tue, 4 Feb 2025 00:34:42 +0100 Subject: [PATCH 455/481] specify a prim@slice in docs i am not quite sure how this failure is in any way related to this pr, since i am only touching inherent functions on str? but sure. --- core/src/str/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 17fb43b7830eb..5b258a7c844fe 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -169,7 +169,7 @@ impl str { /// UTF-8, and then does the conversion. /// /// [`&str`]: str - /// [byteslice]: slice + /// [byteslice]: prim@slice /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of From 27a7514ebcd94d812d938e3b8bd510fc2d8e815b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 01:47:15 +0000 Subject: [PATCH 456/481] Update `compiler-builtins` to 0.1.145 This includes [1] which is required for LLVM 20. [1]: https://github.com/rust-lang/compiler-builtins/pull/752 --- Cargo.lock | 4 ++-- alloc/Cargo.toml | 2 +- std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30875482dc06e..8b78908e6d730 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.143" +version = "0.1.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85ba2077e3eab3dd81be4ece6b7fb2ad0887c1fb813e9a45400baf75c6c7c29" +checksum = "da0705f5abaaab7168ccc14f8f340ded61be2bd3ebea86b9834b6acbc8495de8" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index 96caac890a35c..db7eaf52fb227 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.145", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/std/Cargo.toml b/std/Cargo.toml index 944c34385572d..aa391a4b317ac 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.143" } +compiler_builtins = { version = "=0.1.145" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From 487d7ffc5bd6e853e1095e925e545a87e45991de Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 4 Feb 2025 11:09:17 -0800 Subject: [PATCH 457/481] Rename slice::take methods to split_off --- core/src/slice/mod.rs | 53 ++++++++++--------- coretests/tests/slice.rs | 110 +++++++++++++++++++-------------------- 2 files changed, 83 insertions(+), 80 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 1993a7491e108..dd2b2fd15f98a 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -4294,25 +4294,25 @@ impl [T] { /// /// # Examples /// - /// Taking the first three elements of a slice: + /// Splitting off the first three elements of a slice: /// /// ``` /// #![feature(slice_take)] /// /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; - /// let mut first_three = slice.take(..3).unwrap(); + /// let mut first_three = slice.split_off(..3).unwrap(); /// /// assert_eq!(slice, &['d']); /// assert_eq!(first_three, &['a', 'b', 'c']); /// ``` /// - /// Taking the last two elements of a slice: + /// Splitting off the last two elements of a slice: /// /// ``` /// #![feature(slice_take)] /// /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; - /// let mut tail = slice.take(2..).unwrap(); + /// let mut tail = slice.split_off(2..).unwrap(); /// /// assert_eq!(slice, &['a', 'b']); /// assert_eq!(tail, &['c', 'd']); @@ -4325,16 +4325,19 @@ impl [T] { /// /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; /// - /// assert_eq!(None, slice.take(5..)); - /// assert_eq!(None, slice.take(..5)); - /// assert_eq!(None, slice.take(..=4)); + /// assert_eq!(None, slice.split_off(5..)); + /// assert_eq!(None, slice.split_off(..5)); + /// assert_eq!(None, slice.split_off(..=4)); /// let expected: &[char] = &['a', 'b', 'c', 'd']; - /// assert_eq!(Some(expected), slice.take(..4)); + /// assert_eq!(Some(expected), slice.split_off(..4)); /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] #[unstable(feature = "slice_take", issue = "62280")] - pub fn take<'a, R: OneSidedRange>(self: &mut &'a Self, range: R) -> Option<&'a Self> { + pub fn split_off<'a, R: OneSidedRange>( + self: &mut &'a Self, + range: R, + ) -> Option<&'a Self> { let (direction, split_index) = split_point_of(range)?; if split_index > self.len() { return None; @@ -4363,13 +4366,13 @@ impl [T] { /// /// # Examples /// - /// Taking the first three elements of a slice: + /// Splitting off the first three elements of a slice: /// /// ``` /// #![feature(slice_take)] /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; - /// let mut first_three = slice.take_mut(..3).unwrap(); + /// let mut first_three = slice.split_off_mut(..3).unwrap(); /// /// assert_eq!(slice, &mut ['d']); /// assert_eq!(first_three, &mut ['a', 'b', 'c']); @@ -4381,7 +4384,7 @@ impl [T] { /// #![feature(slice_take)] /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; - /// let mut tail = slice.take_mut(2..).unwrap(); + /// let mut tail = slice.split_off_mut(2..).unwrap(); /// /// assert_eq!(slice, &mut ['a', 'b']); /// assert_eq!(tail, &mut ['c', 'd']); @@ -4394,16 +4397,16 @@ impl [T] { /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; /// - /// assert_eq!(None, slice.take_mut(5..)); - /// assert_eq!(None, slice.take_mut(..5)); - /// assert_eq!(None, slice.take_mut(..=4)); + /// assert_eq!(None, slice.split_off_mut(5..)); + /// assert_eq!(None, slice.split_off_mut(..5)); + /// assert_eq!(None, slice.split_off_mut(..=4)); /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; - /// assert_eq!(Some(expected), slice.take_mut(..4)); + /// assert_eq!(Some(expected), slice.split_off_mut(..4)); /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] #[unstable(feature = "slice_take", issue = "62280")] - pub fn take_mut<'a, R: OneSidedRange>( + pub fn split_off_mut<'a, R: OneSidedRange>( self: &mut &'a mut Self, range: R, ) -> Option<&'a mut Self> { @@ -4435,14 +4438,14 @@ impl [T] { /// #![feature(slice_take)] /// /// let mut slice: &[_] = &['a', 'b', 'c']; - /// let first = slice.take_first().unwrap(); + /// let first = slice.split_off_first().unwrap(); /// /// assert_eq!(slice, &['b', 'c']); /// assert_eq!(first, &'a'); /// ``` #[inline] #[unstable(feature = "slice_take", issue = "62280")] - pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + pub fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { let (first, rem) = self.split_first()?; *self = rem; Some(first) @@ -4459,7 +4462,7 @@ impl [T] { /// #![feature(slice_take)] /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; - /// let first = slice.take_first_mut().unwrap(); + /// let first = slice.split_off_first_mut().unwrap(); /// *first = 'd'; /// /// assert_eq!(slice, &['b', 'c']); @@ -4467,7 +4470,7 @@ impl [T] { /// ``` #[inline] #[unstable(feature = "slice_take", issue = "62280")] - pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + pub fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { let (first, rem) = mem::take(self).split_first_mut()?; *self = rem; Some(first) @@ -4484,14 +4487,14 @@ impl [T] { /// #![feature(slice_take)] /// /// let mut slice: &[_] = &['a', 'b', 'c']; - /// let last = slice.take_last().unwrap(); + /// let last = slice.split_off_last().unwrap(); /// /// assert_eq!(slice, &['a', 'b']); /// assert_eq!(last, &'c'); /// ``` #[inline] #[unstable(feature = "slice_take", issue = "62280")] - pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + pub fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { let (last, rem) = self.split_last()?; *self = rem; Some(last) @@ -4508,7 +4511,7 @@ impl [T] { /// #![feature(slice_take)] /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; - /// let last = slice.take_last_mut().unwrap(); + /// let last = slice.split_off_last_mut().unwrap(); /// *last = 'd'; /// /// assert_eq!(slice, &['a', 'b']); @@ -4516,7 +4519,7 @@ impl [T] { /// ``` #[inline] #[unstable(feature = "slice_take", issue = "62280")] - pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + pub fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { let (last, rem) = mem::take(self).split_last_mut()?; *self = rem; Some(last) diff --git a/coretests/tests/slice.rs b/coretests/tests/slice.rs index 510dd4967c961..ea5322da3812d 100644 --- a/coretests/tests/slice.rs +++ b/coretests/tests/slice.rs @@ -2399,18 +2399,18 @@ fn slice_rsplit_once() { assert_eq!(v.rsplit_once(|&x| x == 0), None); } -macro_rules! take_tests { +macro_rules! split_off_tests { (slice: &[], $($tts:tt)*) => { - take_tests!(ty: &[()], slice: &[], $($tts)*); + split_off_tests!(ty: &[()], slice: &[], $($tts)*); }; (slice: &mut [], $($tts:tt)*) => { - take_tests!(ty: &mut [()], slice: &mut [], $($tts)*); + split_off_tests!(ty: &mut [()], slice: &mut [], $($tts)*); }; (slice: &$slice:expr, $($tts:tt)*) => { - take_tests!(ty: &[_], slice: &$slice, $($tts)*); + split_off_tests!(ty: &[_], slice: &$slice, $($tts)*); }; (slice: &mut $slice:expr, $($tts:tt)*) => { - take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*); + split_off_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*); }; (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => { $( @@ -2425,64 +2425,64 @@ macro_rules! take_tests { }; } -take_tests! { - slice: &[0, 1, 2, 3], method: take, - (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]), - (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]), - (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]), - (take_oob_range_to, (..5), None, &[0, 1, 2, 3]), - (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]), - (take_oob_range_from, (5..), None, &[0, 1, 2, 3]), +split_off_tests! { + slice: &[0, 1, 2, 3], method: split_off, + (split_off_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]), + (split_off_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]), + (split_off_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]), + (split_off_oob_range_to, (..5), None, &[0, 1, 2, 3]), + (split_off_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]), + (split_off_oob_range_from, (5..), None, &[0, 1, 2, 3]), } -take_tests! { - slice: &mut [0, 1, 2, 3], method: take_mut, - (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]), - (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]), - (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]), - (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]), - (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]), - (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]), +split_off_tests! { + slice: &mut [0, 1, 2, 3], method: split_off_mut, + (split_off_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]), + (split_off_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]), + (split_off_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]), + (split_off_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]), + (split_off_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]), + (split_off_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]), } -take_tests! { - slice: &[1, 2], method: take_first, - (take_first_nonempty, (), Some(&1), &[2]), +split_off_tests! { + slice: &[1, 2], method: split_off_first, + (split_off_first_nonempty, (), Some(&1), &[2]), } -take_tests! { - slice: &mut [1, 2], method: take_first_mut, - (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]), +split_off_tests! { + slice: &mut [1, 2], method: split_off_first_mut, + (split_off_first_mut_nonempty, (), Some(&mut 1), &mut [2]), } -take_tests! { - slice: &[1, 2], method: take_last, - (take_last_nonempty, (), Some(&2), &[1]), +split_off_tests! { + slice: &[1, 2], method: split_off_last, + (split_off_last_nonempty, (), Some(&2), &[1]), } -take_tests! { - slice: &mut [1, 2], method: take_last_mut, - (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]), +split_off_tests! { + slice: &mut [1, 2], method: split_off_last_mut, + (split_off_last_mut_nonempty, (), Some(&mut 2), &mut [1]), } -take_tests! { - slice: &[], method: take_first, - (take_first_empty, (), None, &[]), +split_off_tests! { + slice: &[], method: split_off_first, + (split_off_first_empty, (), None, &[]), } -take_tests! { - slice: &mut [], method: take_first_mut, - (take_first_mut_empty, (), None, &mut []), +split_off_tests! { + slice: &mut [], method: split_off_first_mut, + (split_off_first_mut_empty, (), None, &mut []), } -take_tests! { - slice: &[], method: take_last, - (take_last_empty, (), None, &[]), +split_off_tests! { + slice: &[], method: split_off_last, + (split_off_last_empty, (), None, &[]), } -take_tests! { - slice: &mut [], method: take_last_mut, - (take_last_mut_empty, (), None, &mut []), +split_off_tests! { + slice: &mut [], method: split_off_last_mut, + (split_off_last_mut_empty, (), None, &mut []), } #[cfg(not(miri))] // unused in Miri @@ -2497,19 +2497,19 @@ macro_rules! empty_max_mut { } #[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) -take_tests! { - slice: &[(); usize::MAX], method: take, - (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), - (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX), - (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), +split_off_tests! { + slice: &[(); usize::MAX], method: split_off, + (split_off_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), + (split_off_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX), + (split_off_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), } #[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) -take_tests! { - slice: &mut [(); usize::MAX], method: take_mut, - (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), - (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), - (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), +split_off_tests! { + slice: &mut [(); usize::MAX], method: split_off_mut, + (split_off_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), + (split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), } #[test] From d34477c0df140c9df531d237d385566dcd9bd33a Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 4 Feb 2025 11:42:29 -0800 Subject: [PATCH 458/481] Add OneSidedRangeBound to eliminate panic in `split_point_of` See discussion in https://github.com/rust-lang/rust/pull/88502/files#r760177240 --- core/src/ops/mod.rs | 4 ++-- core/src/ops/range.rs | 46 +++++++++++++++++++++++++++++++++++++++---- core/src/slice/mod.rs | 16 +++++++-------- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/core/src/ops/mod.rs b/core/src/ops/mod.rs index 40526f9583e64..7b2ced2cc4bdc 100644 --- a/core/src/ops/mod.rs +++ b/core/src/ops/mod.rs @@ -182,10 +182,10 @@ pub use self::function::{Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::index::{Index, IndexMut}; pub(crate) use self::index_range::IndexRange; -#[unstable(feature = "one_sided_range", issue = "69780")] -pub use self::range::OneSidedRange; #[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; +#[unstable(feature = "one_sided_range", issue = "69780")] +pub use self::range::{OneSidedRange, OneSidedRangeBound}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[unstable(feature = "try_trait_v2_residual", issue = "91285")] diff --git a/core/src/ops/range.rs b/core/src/ops/range.rs index 727a22e454d3d..42e07a0e51da4 100644 --- a/core/src/ops/range.rs +++ b/core/src/ops/range.rs @@ -979,6 +979,19 @@ impl RangeBounds for RangeToInclusive<&T> { } } +/// An internal helper for `split_off` functions indicating +/// which end a `OneSidedRange` is bounded on. +#[unstable(feature = "one_sided_range", issue = "69780")] +#[allow(missing_debug_implementations)] +pub enum OneSidedRangeBound { + /// The range is bounded inclusively from below and is unbounded above. + StartInclusive, + /// The range is bounded exclusively from above and is unbounded below. + End, + /// The range is bounded inclusively from above and is unbounded below. + EndInclusive, +} + /// `OneSidedRange` is implemented for built-in range types that are unbounded /// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`, /// but `..`, `d..e`, and `f..=g` do not. @@ -986,13 +999,38 @@ impl RangeBounds for RangeToInclusive<&T> { /// 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); +} #[unstable(feature = "one_sided_range", issue = "69780")] -impl OneSidedRange for RangeTo where Self: RangeBounds {} +impl OneSidedRange for RangeTo +where + Self: RangeBounds, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::End, self.end) + } +} #[unstable(feature = "one_sided_range", issue = "69780")] -impl OneSidedRange for RangeFrom where Self: RangeBounds {} +impl OneSidedRange for RangeFrom +where + Self: RangeBounds, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::StartInclusive, self.start) + } +} #[unstable(feature = "one_sided_range", issue = "69780")] -impl OneSidedRange for RangeToInclusive where Self: RangeBounds {} +impl OneSidedRange for RangeToInclusive +where + Self: RangeBounds, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::EndInclusive, self.end) + } +} diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index dd2b2fd15f98a..fe9d7c10db28c 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, unchecked_sub}; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive}; +use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; use crate::panic::const_panic; use crate::simd::{self, Simd}; use crate::ub_checks::assert_unsafe_precondition; @@ -83,14 +83,12 @@ pub use raw::{from_raw_parts, from_raw_parts_mut}; /// which to split. Returns `None` if the split index would overflow. #[inline] fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { - use Bound::*; - - Some(match (range.start_bound(), range.end_bound()) { - (Unbounded, Excluded(i)) => (Direction::Front, *i), - (Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?), - (Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?), - (Included(i), Unbounded) => (Direction::Back, *i), - _ => unreachable!(), + use OneSidedRangeBound::{End, EndInclusive, StartInclusive}; + + Some(match range.bound() { + (StartInclusive, i) => (Direction::Back, i), + (End, i) => (Direction::Front, i), + (EndInclusive, i) => (Direction::Front, i.checked_add(1)?), }) } From 24100f66c9460adf319b72def3e71f32f8b97515 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Sat, 1 Feb 2025 23:44:52 +0100 Subject: [PATCH 459/481] Use `widening_mul` --- core/src/fmt/num.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/core/src/fmt/num.rs b/core/src/fmt/num.rs index 7166f106b8da2..4467b37bd4510 100644 --- a/core/src/fmt/num.rs +++ b/core/src/fmt/num.rs @@ -733,28 +733,9 @@ fn udiv_1e19(n: u128) -> (u128, u64) { let quot = if n < 1 << 83 { ((n >> 19) as u64 / (DIV >> 19)) as u128 } else { - u128_mulhi(n, FACTOR) >> 62 + n.widening_mul(FACTOR).1 >> 62 }; let rem = (n - quot * DIV as u128) as u64; (quot, rem) } - -/// Multiply unsigned 128 bit integers, return upper 128 bits of the result -#[inline] -fn u128_mulhi(x: u128, y: u128) -> u128 { - let x_lo = x as u64; - let x_hi = (x >> 64) as u64; - let y_lo = y as u64; - let y_hi = (y >> 64) as u64; - - // handle possibility of overflow - let carry = (x_lo as u128 * y_lo as u128) >> 64; - let m = x_lo as u128 * y_hi as u128 + carry; - let high1 = m >> 64; - - let m_lo = m as u64; - let high2 = (x_hi as u128 * y_lo as u128 + m_lo as u128) >> 64; - - x_hi as u128 * y_hi as u128 + high1 + high2 -} From 61eaf91d664aef4cb8f0efe4c5314d4b239edca7 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 5 Feb 2025 08:52:13 +0100 Subject: [PATCH 460/481] Fix link in from_fn.rs --- core/src/iter/sources/from_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/iter/sources/from_fn.rs b/core/src/iter/sources/from_fn.rs index 75cc0ffe3c77c..1c7e1b30a2f88 100644 --- a/core/src/iter/sources/from_fn.rs +++ b/core/src/iter/sources/from_fn.rs @@ -1,7 +1,7 @@ use crate::fmt; /// Creates an iterator with the provided closure -/// `F: FnMut() -> Option` as its `[next](Iterator::next)` method. +/// `F: FnMut() -> Option` as its [`next`](Iterator::next) method. /// /// The iterator will yield the `T`s returned from the closure. /// From f9313430edb2516dd9eeabc8aaaabc89a51fc674 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 4 Feb 2025 23:38:17 -0800 Subject: [PATCH 461/481] Fix unreachable_pub lint for hermit target --- panic_unwind/src/hermit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panic_unwind/src/hermit.rs b/panic_unwind/src/hermit.rs index 8ac827dd9ccbe..7e08ad66577f1 100644 --- a/panic_unwind/src/hermit.rs +++ b/panic_unwind/src/hermit.rs @@ -7,14 +7,14 @@ use core::any::Any; pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { extern "C" { - pub fn __rust_abort() -> !; + fn __rust_abort() -> !; } __rust_abort(); } pub(crate) unsafe fn panic(_data: Box) -> u32 { extern "C" { - pub fn __rust_abort() -> !; + fn __rust_abort() -> !; } __rust_abort(); } From c4187732afe8c77858106fe853f8b89a50c5f805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:59:40 +0800 Subject: [PATCH 462/481] tests(std): don't output to std{out,err} in `test_creation_flags` and `test_proc_thread_attributes` --- std/src/process/tests.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index e8cbfe337bccf..1323aba38b7cc 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -418,8 +418,13 @@ fn test_creation_flags() { const EXIT_PROCESS_DEBUG_EVENT: u32 = 5; const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; - let mut child = - Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap(); + let mut child = Command::new("cmd") + .creation_flags(DEBUG_PROCESS) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .unwrap(); child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); let mut events = 0; let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; @@ -486,9 +491,13 @@ fn test_proc_thread_attributes() { } } - let parent = ProcessDropGuard(Command::new("cmd").spawn().unwrap()); + let mut parent = Command::new("cmd"); + parent.stdout(Stdio::null()).stderr(Stdio::null()); + + let parent = ProcessDropGuard(parent.spawn().unwrap()); let mut child_cmd = Command::new("cmd"); + child_cmd.stdout(Stdio::null()).stderr(Stdio::null()); let parent_process_handle = parent.0.as_raw_handle(); From dcfba8ba9cc1fae99e401e8f2eb3c065cc8f4b37 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 27 Jan 2025 19:28:12 +0100 Subject: [PATCH 463/481] Stabilize `HashMap::get_many_mut` as `HashMap::get_disjoint_mut` as well as `HashMap::get_many_unchecked_mut` to `HashMap::get_disjoint_unchecked_mut`. --- std/src/collections/hash/map.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index d2342d8fd5176..5013826cb9b3b 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -969,7 +969,6 @@ where /// # Examples /// /// ``` - /// #![feature(map_many_mut)] /// use std::collections::HashMap; /// /// let mut libraries = HashMap::new(); @@ -979,13 +978,13 @@ where /// libraries.insert("Library of Congress".to_string(), 1800); /// /// // Get Athenæum and Bodleian Library - /// let [Some(a), Some(b)] = libraries.get_many_mut([ + /// let [Some(a), Some(b)] = libraries.get_disjoint_mut([ /// "Athenæum", /// "Bodleian Library", /// ]) else { panic!() }; /// /// // Assert values of Athenæum and Library of Congress - /// let got = libraries.get_many_mut([ + /// let got = libraries.get_disjoint_mut([ /// "Athenæum", /// "Library of Congress", /// ]); @@ -998,7 +997,7 @@ where /// ); /// /// // Missing keys result in None - /// let got = libraries.get_many_mut([ + /// let got = libraries.get_disjoint_mut([ /// "Athenæum", /// "New York Public Library", /// ]); @@ -1012,21 +1011,24 @@ where /// ``` /// /// ```should_panic - /// #![feature(map_many_mut)] /// use std::collections::HashMap; /// /// let mut libraries = HashMap::new(); /// libraries.insert("Athenæum".to_string(), 1807); /// /// // Duplicate keys panic! - /// let got = libraries.get_many_mut([ + /// let got = libraries.get_disjoint_mut([ /// "Athenæum", /// "Athenæum", /// ]); /// ``` #[inline] - #[unstable(feature = "map_many_mut", issue = "97601")] - pub fn get_many_mut(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N] + #[doc(alias = "get_many_mut")] + #[stable(feature = "map_many_mut", since = "CURRENT_RUSTC_VERSION")] + pub fn get_disjoint_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut V>; N] where K: Borrow, Q: Hash + Eq, @@ -1040,7 +1042,7 @@ where /// Returns an array of length `N` with the results of each query. `None` will be used if /// the key is missing. /// - /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`). + /// For a safe alternative see [`get_disjoint_mut`](`HashMap::get_disjoint_mut`). /// /// # Safety /// @@ -1052,7 +1054,6 @@ where /// # Examples /// /// ``` - /// #![feature(map_many_mut)] /// use std::collections::HashMap; /// /// let mut libraries = HashMap::new(); @@ -1062,13 +1063,13 @@ where /// libraries.insert("Library of Congress".to_string(), 1800); /// /// // SAFETY: The keys do not overlap. - /// let [Some(a), Some(b)] = (unsafe { libraries.get_many_unchecked_mut([ + /// let [Some(a), Some(b)] = (unsafe { libraries.get_disjoint_unchecked_mut([ /// "Athenæum", /// "Bodleian Library", /// ]) }) else { panic!() }; /// /// // SAFETY: The keys do not overlap. - /// let got = unsafe { libraries.get_many_unchecked_mut([ + /// let got = unsafe { libraries.get_disjoint_unchecked_mut([ /// "Athenæum", /// "Library of Congress", /// ]) }; @@ -1081,7 +1082,7 @@ where /// ); /// /// // SAFETY: The keys do not overlap. - /// let got = unsafe { libraries.get_many_unchecked_mut([ + /// let got = unsafe { libraries.get_disjoint_unchecked_mut([ /// "Athenæum", /// "New York Public Library", /// ]) }; @@ -1089,8 +1090,9 @@ where /// assert_eq!(got, [Some(&mut 1807), None]); /// ``` #[inline] - #[unstable(feature = "map_many_mut", issue = "97601")] - pub unsafe fn get_many_unchecked_mut( + #[doc(alias = "get_many_unchecked_mut")] + #[stable(feature = "map_many_mut", since = "CURRENT_RUSTC_VERSION")] + pub unsafe fn get_disjoint_unchecked_mut( &mut self, ks: [&Q; N], ) -> [Option<&'_ mut V>; N] From d736c5f289d057529be0c17440f52d76a910739e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Thu, 6 Feb 2025 11:52:13 +0100 Subject: [PATCH 464/481] Stabilise 'Cursor::{get_mut, set_position}' in 'const' scenarios; --- std/src/io/cursor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/io/cursor.rs b/std/src/io/cursor.rs index b2ffeb0f95d0d..606099c8bc67a 100644 --- a/std/src/io/cursor.rs +++ b/std/src/io/cursor.rs @@ -153,7 +153,7 @@ impl Cursor { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + #[rustc_const_stable(feature = "const_mut_cursor", since = "CURRENT_RUSTC_VERSION")] pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -201,7 +201,7 @@ impl Cursor { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + #[rustc_const_stable(feature = "const_mut_cursor", since = "CURRENT_RUSTC_VERSION")] pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } From 93888a0bfbfbabe9acc6f1261de096b6fb351ae4 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 16 Dec 2024 15:36:59 +0100 Subject: [PATCH 465/481] remove use of `feature(trait_upcasting)` from core tests --- coretests/tests/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index 7fe7286260858..f1bbed3de3017 100644 --- a/coretests/tests/lib.rs +++ b/coretests/tests/lib.rs @@ -81,7 +81,6 @@ #![feature(strict_provenance_atomic_ptr)] #![feature(strict_provenance_lints)] #![feature(test)] -#![feature(trait_upcasting)] #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_blocks)] From 9c8778d293eb66455ca94d2ae1348a539d083398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Jan 2025 18:40:41 +0000 Subject: [PATCH 466/481] Remove some unnecessary parens in `assert!` conditions While working on #122661, some of these started triggering our "unnecessary parens" lints due to a change in the `assert!` desugaring. A cursory search identified a few more. Some of these have been carried from before 1.0, were a bulk rename from the previous name of `assert!` left them in that state. I went and removed as many of these unnecessary parens as possible in order to have fewer annoyances in the future if we make the lint smarter. --- alloc/tests/str.rs | 22 +++++++++++----------- coretests/tests/bool.rs | 8 ++++---- coretests/tests/ptr.rs | 6 +++--- std/tests/istr.rs | 4 ++-- std/tests/seq-compare.rs | 22 +++++++++++----------- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/alloc/tests/str.rs b/alloc/tests/str.rs index 6f930ab08535c..5720d3ffd97b6 100644 --- a/alloc/tests/str.rs +++ b/alloc/tests/str.rs @@ -2297,21 +2297,21 @@ fn utf8_chars() { assert_eq!(schs.len(), 4); assert_eq!(schs.iter().cloned().collect::(), s); - assert!((from_utf8(s.as_bytes()).is_ok())); + assert!(from_utf8(s.as_bytes()).is_ok()); // invalid prefix - assert!((!from_utf8(&[0x80]).is_ok())); + assert!(!from_utf8(&[0x80]).is_ok()); // invalid 2 byte prefix - assert!((!from_utf8(&[0xc0]).is_ok())); - assert!((!from_utf8(&[0xc0, 0x10]).is_ok())); + assert!(!from_utf8(&[0xc0]).is_ok()); + assert!(!from_utf8(&[0xc0, 0x10]).is_ok()); // invalid 3 byte prefix - assert!((!from_utf8(&[0xe0]).is_ok())); - assert!((!from_utf8(&[0xe0, 0x10]).is_ok())); - assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); + assert!(!from_utf8(&[0xe0]).is_ok()); + assert!(!from_utf8(&[0xe0, 0x10]).is_ok()); + assert!(!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()); // invalid 4 byte prefix - assert!((!from_utf8(&[0xf0]).is_ok())); - assert!((!from_utf8(&[0xf0, 0x10]).is_ok())); - assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); - assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); + assert!(!from_utf8(&[0xf0]).is_ok()); + assert!(!from_utf8(&[0xf0, 0x10]).is_ok()); + assert!(!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()); + assert!(!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()); } #[test] diff --git a/coretests/tests/bool.rs b/coretests/tests/bool.rs index 47f6459915b3e..bcd6dc2abac6c 100644 --- a/coretests/tests/bool.rs +++ b/coretests/tests/bool.rs @@ -71,14 +71,14 @@ fn test_bool() { #[test] pub fn test_bool_not() { if !false { - assert!((true)); + assert!(true); } else { - assert!((false)); + assert!(false); } if !true { - assert!((false)); + assert!(false); } else { - assert!((true)); + assert!(true); } } diff --git a/coretests/tests/ptr.rs b/coretests/tests/ptr.rs index 7cefb615d0371..345bec345d128 100644 --- a/coretests/tests/ptr.rs +++ b/coretests/tests/ptr.rs @@ -42,11 +42,11 @@ fn test() { let mut v1 = vec![0u16, 0u16, 0u16]; copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1); - assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); + assert!(v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16); copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16)); + assert!(v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16); copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16)); + assert!(v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16); } } diff --git a/std/tests/istr.rs b/std/tests/istr.rs index 9a127ae803e77..e481872977abf 100644 --- a/std/tests/istr.rs +++ b/std/tests/istr.rs @@ -5,7 +5,7 @@ fn test_stack_assign() { let t: String = "a".to_string(); assert_eq!(s, t); let u: String = "b".to_string(); - assert!((s != u)); + assert!(s != u); } #[test] @@ -19,7 +19,7 @@ fn test_heap_assign() { let t: String = "a big ol' string".to_string(); assert_eq!(s, t); let u: String = "a bad ol' string".to_string(); - assert!((s != u)); + assert!(s != u); } #[test] diff --git a/std/tests/seq-compare.rs b/std/tests/seq-compare.rs index 221f1c7cabde5..ec39c5b603ccc 100644 --- a/std/tests/seq-compare.rs +++ b/std/tests/seq-compare.rs @@ -1,15 +1,15 @@ #[test] fn seq_compare() { - assert!(("hello".to_string() < "hellr".to_string())); - assert!(("hello ".to_string() > "hello".to_string())); - assert!(("hello".to_string() != "there".to_string())); - assert!((vec![1, 2, 3, 4] > vec![1, 2, 3])); - assert!((vec![1, 2, 3] < vec![1, 2, 3, 4])); - assert!((vec![1, 2, 4, 4] > vec![1, 2, 3, 4])); - assert!((vec![1, 2, 3, 4] < vec![1, 2, 4, 4])); - assert!((vec![1, 2, 3] <= vec![1, 2, 3])); - assert!((vec![1, 2, 3] <= vec![1, 2, 3, 3])); - assert!((vec![1, 2, 3, 4] > vec![1, 2, 3])); + assert!("hello".to_string() < "hellr".to_string()); + assert!("hello ".to_string() > "hello".to_string()); + assert!("hello".to_string() != "there".to_string()); + assert!(vec![1, 2, 3, 4] > vec![1, 2, 3]); + assert!(vec![1, 2, 3] < vec![1, 2, 3, 4]); + assert!(vec![1, 2, 4, 4] > vec![1, 2, 3, 4]); + assert!(vec![1, 2, 3, 4] < vec![1, 2, 4, 4]); + assert!(vec![1, 2, 3] <= vec![1, 2, 3]); + assert!(vec![1, 2, 3] <= vec![1, 2, 3, 3]); + assert!(vec![1, 2, 3, 4] > vec![1, 2, 3]); assert_eq!(vec![1, 2, 3], vec![1, 2, 3]); - assert!((vec![1, 2, 3] != vec![1, 1, 3])); + assert!(vec![1, 2, 3] != vec![1, 1, 3]); } From 028267f397b3108c796ca12eaded6843a683e067 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 6 Feb 2025 10:25:40 +0530 Subject: [PATCH 467/481] sys: net: Add UEFI stubs - Just a copy of sys/net/unsupported. - Will make the future net PRs easier to review. Signed-off-by: Ayush Singh --- std/src/sys/net/connection/uefi/mod.rs | 369 +++++++++++++++++++++++++ std/src/sys/net/mod.rs | 5 + 2 files changed, 374 insertions(+) create mode 100644 std/src/sys/net/connection/uefi/mod.rs diff --git a/std/src/sys/net/connection/uefi/mod.rs b/std/src/sys/net/connection/uefi/mod.rs new file mode 100644 index 0000000000000..87e6106468fdb --- /dev/null +++ b/std/src/sys/net/connection/uefi/mod.rs @@ -0,0 +1,369 @@ +use crate::fmt; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::sys::unsupported; +use crate::time::Duration; + +pub struct TcpStream(!); + +impl TcpStream { + pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn read_timeout(&self) -> io::Result> { + self.0 + } + + pub fn write_timeout(&self) -> io::Result> { + self.0 + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn read(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { + self.0 + } + + pub fn is_read_vectored(&self) -> bool { + self.0 + } + + pub fn write(&self, _: &[u8]) -> io::Result { + self.0 + } + + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { + self.0 + } + + pub fn is_write_vectored(&self) -> bool { + self.0 + } + + pub fn peer_addr(&self) -> io::Result { + self.0 + } + + pub fn socket_addr(&self) -> io::Result { + self.0 + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_linger(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn linger(&self) -> io::Result> { + self.0 + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn nodelay(&self) -> io::Result { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result { + self.0 + } + + pub fn take_error(&self) -> io::Result> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct TcpListener(!); + +impl TcpListener { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + self.0 + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result { + self.0 + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn only_v6(&self) -> io::Result { + self.0 + } + + pub fn take_error(&self) -> io::Result> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct UdpSocket(!); + +impl UdpSocket { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result { + self.0 + } + + pub fn socket_addr(&self) -> io::Result { + self.0 + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0 + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0 + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { + self.0 + } + + pub fn duplicate(&self) -> io::Result { + self.0 + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn read_timeout(&self) -> io::Result> { + self.0 + } + + pub fn write_timeout(&self) -> io::Result> { + self.0 + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn broadcast(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn multicast_loop_v4(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn multicast_loop_v6(&self) -> io::Result { + self.0 + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + self.0 + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + self.0 + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + self.0 + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result { + self.0 + } + + pub fn take_error(&self) -> io::Result> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + self.0 + } + + pub fn send(&self, _: &[u8]) -> io::Result { + self.0 + } + + pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct LookupHost(!); + +impl LookupHost { + pub fn port(&self) -> u16 { + self.0 + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + self.0 + } +} + +impl TryFrom<&str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &str) -> io::Result { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result { + unsupported() + } +} + +#[allow(nonstandard_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + #[allow(dead_code)] + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + #[allow(dead_code)] + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } +} diff --git a/std/src/sys/net/mod.rs b/std/src/sys/net/mod.rs index 5aa197fbc0df3..646679a1cc8b9 100644 --- a/std/src/sys/net/mod.rs +++ b/std/src/sys/net/mod.rs @@ -25,6 +25,11 @@ cfg_if::cfg_if! { mod xous; pub use xous::*; } + } else if #[cfg(target_os = "uefi")] { + mod connection { + mod uefi; + pub use uefi::*; + } } else { mod connection { mod unsupported; From 1fdbc7ae8ff8b67ceac6a4ab9f01bd62e3033d5c Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 6 Feb 2025 18:49:53 +0800 Subject: [PATCH 468/481] tests(std/net): remove outdated `base_port` calculation This was never modified since `std::net` was originally introduced, when each CI job was running multiple jobs concurrently which caused issues with fighting over the same ports. This is not the case in the current CI infrastructure, so remove this relic. --- std/src/net/test.rs | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/std/src/net/test.rs b/std/src/net/test.rs index d318d457f3569..a5c3983cd89ec 100644 --- a/std/src/net/test.rs +++ b/std/src/net/test.rs @@ -5,14 +5,15 @@ use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToS use crate::sync::atomic::{AtomicUsize, Ordering}; static PORT: AtomicUsize = AtomicUsize::new(0); +const BASE_PORT: u16 = 19600; pub fn next_test_ip4() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port(); + let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT; SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) } pub fn next_test_ip6() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port(); + let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT; SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0)) } @@ -30,31 +31,3 @@ pub fn tsa(a: A) -> Result, String> { Err(e) => Err(e.to_string()), } } - -// The bots run multiple builds at the same time, and these builds -// all want to use ports. This function figures out which workspace -// it is running in and assigns a port range based on it. -fn base_port() -> u16 { - let cwd = if cfg!(target_env = "sgx") { - String::from("sgx") - } else { - env::current_dir().unwrap().into_os_string().into_string().unwrap() - }; - let dirs = [ - "32-opt", - "32-nopt", - "musl-64-opt", - "cross-opt", - "64-opt", - "64-nopt", - "64-opt-vg", - "64-debug-opt", - "all-opt", - "snap3", - "dist", - "sgx", - ]; - dirs.iter().enumerate().find(|&(_, dir)| cwd.contains(dir)).map(|p| p.0).unwrap_or(0) as u16 - * 1000 - + 19600 -} From 59b645171b4f9e4743cc95ad005c3007c8b54126 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 7 Feb 2025 09:45:19 +0000 Subject: [PATCH 469/481] Move two windows process tests to tests/ui --- std/src/process/tests.rs | 148 --------------------------------------- 1 file changed, 148 deletions(-) diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index 1323aba38b7cc..9b87259abefc1 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -391,154 +391,6 @@ fn test_interior_nul_in_env_value_is_error() { } } -/// Tests that process creation flags work by debugging a process. -/// Other creation flags make it hard or impossible to detect -/// behavioral changes in the process. -#[test] -#[cfg(windows)] -fn test_creation_flags() { - use crate::os::windows::process::CommandExt; - use crate::sys::c::{BOOL, INFINITE}; - #[repr(C)] - struct DEBUG_EVENT { - pub event_code: u32, - pub process_id: u32, - pub thread_id: u32, - // This is a union in the real struct, but we don't - // need this data for the purposes of this test. - pub _junk: [u8; 164], - } - - extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: u32) -> BOOL; - fn ContinueDebugEvent(dwProcessId: u32, dwThreadId: u32, dwContinueStatus: u32) -> BOOL; - } - - const DEBUG_PROCESS: u32 = 1; - const EXIT_PROCESS_DEBUG_EVENT: u32 = 5; - const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; - - let mut child = Command::new("cmd") - .creation_flags(DEBUG_PROCESS) - .stdin(Stdio::piped()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - .unwrap(); - child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); - let mut events = 0; - let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; - loop { - if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { - panic!("WaitForDebugEvent failed!"); - } - events += 1; - - if event.event_code == EXIT_PROCESS_DEBUG_EVENT { - break; - } - - if unsafe { - ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED) - } == 0 - { - panic!("ContinueDebugEvent failed!"); - } - } - assert!(events > 0); -} - -/// Tests proc thread attributes by spawning a process with a custom parent process, -/// then comparing the parent process ID with the expected parent process ID. -#[test] -#[cfg(windows)] -fn test_proc_thread_attributes() { - use crate::mem; - use crate::os::windows::io::AsRawHandle; - use crate::os::windows::process::{CommandExt, ProcThreadAttributeList}; - use crate::sys::c::{BOOL, CloseHandle, HANDLE}; - use crate::sys::cvt; - - #[repr(C)] - #[allow(non_snake_case)] - struct PROCESSENTRY32W { - dwSize: u32, - cntUsage: u32, - th32ProcessID: u32, - th32DefaultHeapID: usize, - th32ModuleID: u32, - cntThreads: u32, - th32ParentProcessID: u32, - pcPriClassBase: i32, - dwFlags: u32, - szExeFile: [u16; 260], - } - - extern "system" { - fn CreateToolhelp32Snapshot(dwflags: u32, th32processid: u32) -> HANDLE; - fn Process32First(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL; - fn Process32Next(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL; - } - - const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; - const TH32CS_SNAPPROCESS: u32 = 0x00000002; - - struct ProcessDropGuard(crate::process::Child); - - impl Drop for ProcessDropGuard { - fn drop(&mut self) { - let _ = self.0.kill(); - } - } - - let mut parent = Command::new("cmd"); - parent.stdout(Stdio::null()).stderr(Stdio::null()); - - let parent = ProcessDropGuard(parent.spawn().unwrap()); - - let mut child_cmd = Command::new("cmd"); - child_cmd.stdout(Stdio::null()).stderr(Stdio::null()); - - let parent_process_handle = parent.0.as_raw_handle(); - - let mut attribute_list = ProcThreadAttributeList::build() - .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle) - .finish() - .unwrap(); - - let child = ProcessDropGuard(child_cmd.spawn_with_attributes(&mut attribute_list).unwrap()); - - let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; - - let mut process_entry = PROCESSENTRY32W { - dwSize: mem::size_of::() as u32, - cntUsage: 0, - th32ProcessID: 0, - th32DefaultHeapID: 0, - th32ModuleID: 0, - cntThreads: 0, - th32ParentProcessID: 0, - pcPriClassBase: 0, - dwFlags: 0, - szExeFile: [0; 260], - }; - - unsafe { cvt(Process32First(h_snapshot, &mut process_entry as *mut _)) }.unwrap(); - - loop { - if child.0.id() == process_entry.th32ProcessID { - break; - } - unsafe { cvt(Process32Next(h_snapshot, &mut process_entry as *mut _)) }.unwrap(); - } - - unsafe { cvt(CloseHandle(h_snapshot)) }.unwrap(); - - assert_eq!(parent.0.id(), process_entry.th32ParentProcessID); - - drop(child) -} - #[test] fn test_command_implements_send_sync() { fn take_send_sync_type(_: T) {} From e01a3d460e12bf1d48f1cb81bc08e21b47ed3784 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 18 Jan 2025 19:10:36 +0100 Subject: [PATCH 470/481] std: move `io` module out of `pal` --- .../hermit/io.rs => io/io_slice/iovec.rs} | 14 +-- .../io.rs => io/io_slice/unsupported.rs} | 4 - .../{pal/wasi/io.rs => io/io_slice/wasi.rs} | 8 -- .../solid/io.rs => io/io_slice/windows.rs} | 38 ++++---- std/src/sys/io/is_terminal/hermit.rs | 6 ++ std/src/sys/io/is_terminal/isatty.rs | 6 ++ std/src/sys/io/is_terminal/unsupported.rs | 3 + .../io.rs => io/is_terminal/windows.rs} | 84 +----------------- std/src/sys/io/mod.rs | 40 +++++++++ std/src/sys/mod.rs | 1 + std/src/sys/pal/hermit/mod.rs | 1 - std/src/sys/pal/sgx/mod.rs | 2 - std/src/sys/pal/solid/mod.rs | 1 - std/src/sys/pal/teeos/mod.rs | 2 - std/src/sys/pal/uefi/mod.rs | 2 - std/src/sys/pal/unix/io.rs | 87 ------------------- std/src/sys/pal/unix/mod.rs | 1 - std/src/sys/pal/unsupported/mod.rs | 1 - std/src/sys/pal/wasi/mod.rs | 1 - std/src/sys/pal/wasip2/mod.rs | 2 - std/src/sys/pal/wasm/mod.rs | 2 - std/src/sys/pal/windows/mod.rs | 1 - std/src/sys/pal/xous/mod.rs | 2 - std/src/sys/pal/zkvm/mod.rs | 2 - 24 files changed, 81 insertions(+), 230 deletions(-) rename std/src/sys/{pal/hermit/io.rs => io/io_slice/iovec.rs} (90%) rename std/src/sys/{pal/unsupported/io.rs => io/io_slice/unsupported.rs} (94%) rename std/src/sys/{pal/wasi/io.rs => io/io_slice/wasi.rs} (90%) rename std/src/sys/{pal/solid/io.rs => io/io_slice/windows.rs} (54%) create mode 100644 std/src/sys/io/is_terminal/hermit.rs create mode 100644 std/src/sys/io/is_terminal/isatty.rs create mode 100644 std/src/sys/io/is_terminal/unsupported.rs rename std/src/sys/{pal/windows/io.rs => io/is_terminal/windows.rs} (55%) create mode 100644 std/src/sys/io/mod.rs delete mode 100644 std/src/sys/pal/unix/io.rs diff --git a/std/src/sys/pal/hermit/io.rs b/std/src/sys/io/io_slice/iovec.rs similarity index 90% rename from std/src/sys/pal/hermit/io.rs rename to std/src/sys/io/io_slice/iovec.rs index 0424a1ac55a29..072191315f7c5 100644 --- a/std/src/sys/pal/hermit/io.rs +++ b/std/src/sys/io/io_slice/iovec.rs @@ -1,8 +1,13 @@ -use hermit_abi::{c_void, iovec}; +#[cfg(target_os = "hermit")] +use hermit_abi::iovec; +#[cfg(target_family = "unix")] +use libc::iovec; +use crate::ffi::c_void; use crate::marker::PhantomData; -use crate::os::hermit::io::{AsFd, AsRawFd}; use crate::slice; +#[cfg(target_os = "solid_asp3")] +use crate::sys::pal::abi::sockets::iovec; #[derive(Copy, Clone)] #[repr(transparent)] @@ -80,8 +85,3 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } } } - -pub fn is_terminal(fd: &impl AsFd) -> bool { - let fd = fd.as_fd(); - hermit_abi::isatty(fd.as_raw_fd()) -} diff --git a/std/src/sys/pal/unsupported/io.rs b/std/src/sys/io/io_slice/unsupported.rs similarity index 94% rename from std/src/sys/pal/unsupported/io.rs rename to std/src/sys/io/io_slice/unsupported.rs index 604735d32d51a..1572cac6cd771 100644 --- a/std/src/sys/pal/unsupported/io.rs +++ b/std/src/sys/io/io_slice/unsupported.rs @@ -50,7 +50,3 @@ impl<'a> IoSliceMut<'a> { self.0 } } - -pub fn is_terminal(_: &T) -> bool { - false -} diff --git a/std/src/sys/pal/wasi/io.rs b/std/src/sys/io/io_slice/wasi.rs similarity index 90% rename from std/src/sys/pal/wasi/io.rs rename to std/src/sys/io/io_slice/wasi.rs index 57f81bc6257cd..87acbbd924e56 100644 --- a/std/src/sys/pal/wasi/io.rs +++ b/std/src/sys/io/io_slice/wasi.rs @@ -1,7 +1,4 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - use crate::marker::PhantomData; -use crate::os::fd::{AsFd, AsRawFd}; use crate::slice; #[derive(Copy, Clone)] @@ -77,8 +74,3 @@ impl<'a> IoSliceMut<'a> { unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) } } } - -pub fn is_terminal(fd: &impl AsFd) -> bool { - let fd = fd.as_fd(); - unsafe { libc::isatty(fd.as_raw_fd()) != 0 } -} diff --git a/std/src/sys/pal/solid/io.rs b/std/src/sys/io/io_slice/windows.rs similarity index 54% rename from std/src/sys/pal/solid/io.rs rename to std/src/sys/io/io_slice/windows.rs index 9ef4b7049b690..c3d8ec87c19e3 100644 --- a/std/src/sys/pal/solid/io.rs +++ b/std/src/sys/io/io_slice/windows.rs @@ -1,86 +1,82 @@ -use libc::c_void; - -use super::abi::sockets::iovec; use crate::marker::PhantomData; use crate::slice; +use crate::sys::c; #[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { - vec: iovec, + vec: c::WSABUF, _p: PhantomData<&'a [u8]>, } impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + assert!(buf.len() <= u32::MAX as usize); IoSlice { - vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, + vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, _p: PhantomData, } } #[inline] pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { + if (self.vec.len as usize) < n { panic!("advancing IoSlice beyond its length"); } unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); + self.vec.len -= n as u32; + self.vec.buf = self.vec.buf.add(n); } } #[inline] pub const fn as_slice(&self) -> &'a [u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } } } #[repr(transparent)] pub struct IoSliceMut<'a> { - vec: iovec, + vec: c::WSABUF, _p: PhantomData<&'a mut [u8]>, } impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + assert!(buf.len() <= u32::MAX as usize); IoSliceMut { - vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, + vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, _p: PhantomData, } } #[inline] pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { + if (self.vec.len as usize) < n { panic!("advancing IoSliceMut beyond its length"); } unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); + self.vec.len -= n as u32; + self.vec.buf = self.vec.buf.add(n); } } #[inline] pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } } #[inline] pub const fn into_slice(self) -> &'a mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } } #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } } } - -pub fn is_terminal(_: &T) -> bool { - false -} diff --git a/std/src/sys/io/is_terminal/hermit.rs b/std/src/sys/io/is_terminal/hermit.rs new file mode 100644 index 0000000000000..61bdb6f0a5440 --- /dev/null +++ b/std/src/sys/io/is_terminal/hermit.rs @@ -0,0 +1,6 @@ +use crate::os::fd::{AsFd, AsRawFd}; + +pub fn is_terminal(fd: &impl AsFd) -> bool { + let fd = fd.as_fd(); + hermit_abi::isatty(fd.as_raw_fd()) +} diff --git a/std/src/sys/io/is_terminal/isatty.rs b/std/src/sys/io/is_terminal/isatty.rs new file mode 100644 index 0000000000000..6e0b46211b907 --- /dev/null +++ b/std/src/sys/io/is_terminal/isatty.rs @@ -0,0 +1,6 @@ +use crate::os::fd::{AsFd, AsRawFd}; + +pub fn is_terminal(fd: &impl AsFd) -> bool { + let fd = fd.as_fd(); + unsafe { libc::isatty(fd.as_raw_fd()) != 0 } +} diff --git a/std/src/sys/io/is_terminal/unsupported.rs b/std/src/sys/io/is_terminal/unsupported.rs new file mode 100644 index 0000000000000..cee4add32fbfc --- /dev/null +++ b/std/src/sys/io/is_terminal/unsupported.rs @@ -0,0 +1,3 @@ +pub fn is_terminal(_: &T) -> bool { + false +} diff --git a/std/src/sys/pal/windows/io.rs b/std/src/sys/io/is_terminal/windows.rs similarity index 55% rename from std/src/sys/pal/windows/io.rs rename to std/src/sys/io/is_terminal/windows.rs index f2865d2ffc168..3ec18fb47b9de 100644 --- a/std/src/sys/pal/windows/io.rs +++ b/std/src/sys/io/is_terminal/windows.rs @@ -1,90 +1,8 @@ -use core::ffi::c_void; - -use crate::marker::PhantomData; +use crate::ffi::c_void; use crate::mem::size_of; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle}; -use crate::slice; use crate::sys::c; -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: c::WSABUF, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= u32::MAX as usize); - IoSlice { - vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if (self.vec.len as usize) < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.len -= n as u32; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub const fn as_slice(&self) -> &'a [u8] { - unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } - } -} - -#[repr(transparent)] -pub struct IoSliceMut<'a> { - vec: c::WSABUF, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= u32::MAX as usize); - IoSliceMut { - vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if (self.vec.len as usize) < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.len -= n as u32; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } - } - - #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } - } -} - pub fn is_terminal(h: &impl AsHandle) -> bool { handle_is_console(h.as_handle()) } diff --git a/std/src/sys/io/mod.rs b/std/src/sys/io/mod.rs new file mode 100644 index 0000000000000..4605b56f8f16c --- /dev/null +++ b/std/src/sys/io/mod.rs @@ -0,0 +1,40 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +mod io_slice { + cfg_if::cfg_if! { + if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3"))] { + mod iovec; + pub use iovec::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else { + mod unsupported; + pub use unsupported::*; + } + } +} + +mod is_terminal { + cfg_if::cfg_if! { + if #[cfg(any(target_family = "unix", target_os = "wasi"))] { + mod isatty; + pub use isatty::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else { + mod unsupported; + pub use unsupported::*; + } + } +} + +pub use io_slice::{IoSlice, IoSliceMut}; +pub use is_terminal::is_terminal; diff --git a/std/src/sys/mod.rs b/std/src/sys/mod.rs index 39a0bc6e337c6..1032fcba5e2e1 100644 --- a/std/src/sys/mod.rs +++ b/std/src/sys/mod.rs @@ -12,6 +12,7 @@ pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; pub mod exit_guard; +pub mod io; pub mod net; pub mod os_str; pub mod path; diff --git a/std/src/sys/pal/hermit/mod.rs b/std/src/sys/pal/hermit/mod.rs index 032007aa4dca5..3d555ad5050c2 100644 --- a/std/src/sys/pal/hermit/mod.rs +++ b/std/src/sys/pal/hermit/mod.rs @@ -23,7 +23,6 @@ pub mod env; pub mod fd; pub mod fs; pub mod futex; -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/sgx/mod.rs b/std/src/sys/pal/sgx/mod.rs index 0f5935d0c7184..9a04fa4b97e19 100644 --- a/std/src/sys/pal/sgx/mod.rs +++ b/std/src/sys/pal/sgx/mod.rs @@ -14,8 +14,6 @@ pub mod env; pub mod fd; #[path = "../unsupported/fs.rs"] pub mod fs; -#[path = "../unsupported/io.rs"] -pub mod io; mod libunwind_integration; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/std/src/sys/pal/solid/mod.rs b/std/src/sys/pal/solid/mod.rs index caf848a4e9b07..06af7bfade059 100644 --- a/std/src/sys/pal/solid/mod.rs +++ b/std/src/sys/pal/solid/mod.rs @@ -23,7 +23,6 @@ pub mod env; // `crate::sys::error` pub(crate) mod error; pub mod fs; -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/teeos/mod.rs b/std/src/sys/pal/teeos/mod.rs index a9904e66664e3..f850fefc8f22f 100644 --- a/std/src/sys/pal/teeos/mod.rs +++ b/std/src/sys/pal/teeos/mod.rs @@ -13,8 +13,6 @@ pub mod env; //pub mod fd; #[path = "../unsupported/fs.rs"] pub mod fs; -#[path = "../unsupported/io.rs"] -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/uefi/mod.rs b/std/src/sys/pal/uefi/mod.rs index 07025a304bfd7..4766e2ef0a95f 100644 --- a/std/src/sys/pal/uefi/mod.rs +++ b/std/src/sys/pal/uefi/mod.rs @@ -17,8 +17,6 @@ pub mod args; pub mod env; pub mod fs; pub mod helpers; -#[path = "../unsupported/io.rs"] -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/unix/io.rs b/std/src/sys/pal/unix/io.rs deleted file mode 100644 index 0d5a152dc0dc6..0000000000000 --- a/std/src/sys/pal/unix/io.rs +++ /dev/null @@ -1,87 +0,0 @@ -use libc::{c_void, iovec}; - -use crate::marker::PhantomData; -use crate::os::fd::{AsFd, AsRawFd}; -use crate::slice; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: iovec, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice { - vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub const fn as_slice(&self) -> &'a [u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} - -#[repr(transparent)] -pub struct IoSliceMut<'a> { - vec: iovec, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut { - vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } - - #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} - -pub fn is_terminal(fd: &impl AsFd) -> bool { - let fd = fd.as_fd(); - unsafe { libc::isatty(fd.as_raw_fd()) != 0 } -} diff --git a/std/src/sys/pal/unix/mod.rs b/std/src/sys/pal/unix/mod.rs index 6862399b9425c..027df6c5691c6 100644 --- a/std/src/sys/pal/unix/mod.rs +++ b/std/src/sys/pal/unix/mod.rs @@ -11,7 +11,6 @@ pub mod env; pub mod fd; pub mod fs; pub mod futex; -pub mod io; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod kernel_copy; #[cfg(target_os = "linux")] diff --git a/std/src/sys/pal/unsupported/mod.rs b/std/src/sys/pal/unsupported/mod.rs index 4941dd4918c86..b1aaeb1b4c814 100644 --- a/std/src/sys/pal/unsupported/mod.rs +++ b/std/src/sys/pal/unsupported/mod.rs @@ -3,7 +3,6 @@ pub mod args; pub mod env; pub mod fs; -pub mod io; pub mod os; pub mod pipe; pub mod process; diff --git a/std/src/sys/pal/wasi/mod.rs b/std/src/sys/pal/wasi/mod.rs index 312ad28ab51c8..f4588a60ea9a4 100644 --- a/std/src/sys/pal/wasi/mod.rs +++ b/std/src/sys/pal/wasi/mod.rs @@ -20,7 +20,6 @@ pub mod fs; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/std/src/sys/pal/wasip2/mod.rs b/std/src/sys/pal/wasip2/mod.rs index 234e946d3b8ca..72c9742b2e549 100644 --- a/std/src/sys/pal/wasip2/mod.rs +++ b/std/src/sys/pal/wasip2/mod.rs @@ -17,8 +17,6 @@ pub mod fs; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; -#[path = "../wasi/io.rs"] -pub mod io; #[path = "../wasi/os.rs"] pub mod os; diff --git a/std/src/sys/pal/wasm/mod.rs b/std/src/sys/pal/wasm/mod.rs index 1280f3532001a..32d59c4d0f7c4 100644 --- a/std/src/sys/pal/wasm/mod.rs +++ b/std/src/sys/pal/wasm/mod.rs @@ -21,8 +21,6 @@ pub mod args; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; -#[path = "../unsupported/io.rs"] -pub mod io; #[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/std/src/sys/pal/windows/mod.rs b/std/src/sys/pal/windows/mod.rs index f9aa049ca9ae6..1eca346b76c2b 100644 --- a/std/src/sys/pal/windows/mod.rs +++ b/std/src/sys/pal/windows/mod.rs @@ -21,7 +21,6 @@ pub mod fs; #[cfg(not(target_vendor = "win7"))] pub mod futex; pub mod handle; -pub mod io; pub mod os; pub mod pipe; pub mod process; diff --git a/std/src/sys/pal/xous/mod.rs b/std/src/sys/pal/xous/mod.rs index 8ba2b6e2f20fd..1bd0e67f37162 100644 --- a/std/src/sys/pal/xous/mod.rs +++ b/std/src/sys/pal/xous/mod.rs @@ -5,8 +5,6 @@ pub mod args; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; -#[path = "../unsupported/io.rs"] -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/std/src/sys/pal/zkvm/mod.rs b/std/src/sys/pal/zkvm/mod.rs index 9e9ae86107033..054c867f90d8e 100644 --- a/std/src/sys/pal/zkvm/mod.rs +++ b/std/src/sys/pal/zkvm/mod.rs @@ -16,8 +16,6 @@ pub mod args; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; -#[path = "../unsupported/io.rs"] -pub mod io; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; From a8c3487514bd58cc37f00d5fa3fa1e1ffca3c28f Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 18 Jan 2025 19:12:14 +0100 Subject: [PATCH 471/481] std: get rid of `sys_common::io` --- std/src/fs/tests.rs | 2 +- std/src/io/mod.rs | 2 +- std/src/lib.rs | 25 +-------- std/src/os/unix/fs/tests.rs | 4 +- std/src/os/unix/net/tests.rs | 2 +- std/src/process/tests.rs | 4 +- std/src/sys/io/mod.rs | 4 ++ std/src/sys/pal/sgx/stdio.rs | 2 +- std/src/sys/pal/unix/kernel_copy/tests.rs | 2 +- std/src/sys/pal/unix/stdio.rs | 2 +- std/src/sys/pal/wasi/stdio.rs | 2 +- std/src/sys/pal/windows/process/tests.rs | 2 +- std/src/sys/pal/zkvm/stdio.rs | 2 +- std/src/sys_common/io.rs | 49 ----------------- std/src/sys_common/mod.rs | 1 - std/src/test_helpers.rs | 65 +++++++++++++++++++++++ std/tests/common/mod.rs | 2 +- 17 files changed, 84 insertions(+), 88 deletions(-) delete mode 100644 std/src/sys_common/io.rs create mode 100644 std/src/test_helpers.rs diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index 28f16da1ed8d2..e3810030dedf7 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -14,7 +14,7 @@ use crate::os::unix::fs::symlink as junction_point; use crate::os::windows::fs::{OpenOptionsExt, junction_point, symlink_dir, symlink_file}; use crate::path::Path; use crate::sync::Arc; -use crate::sys_common::io::test::{TempDir, tmpdir}; +use crate::test_helpers::{TempDir, tmpdir}; use crate::time::{Duration, Instant, SystemTime}; use crate::{env, str, thread}; diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index cfd03b8e3d6d0..0ffad2c27a4d5 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -344,7 +344,7 @@ pub mod prelude; mod stdio; mod util; -const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; +const DEFAULT_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; pub(crate) use stdio::cleanup; diff --git a/std/src/lib.rs b/std/src/lib.rs index 7c18226874cc8..954a4182fbd6c 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -739,27 +739,4 @@ mod sealed { #[cfg(test)] #[allow(dead_code)] // Not used in all configurations. -pub(crate) mod test_helpers { - /// Test-only replacement for `rand::thread_rng()`, which is unusable for - /// us, as we want to allow running stdlib tests on tier-3 targets which may - /// not have `getrandom` support. - /// - /// Does a bit of a song and dance to ensure that the seed is different on - /// each call (as some tests sadly rely on this), but doesn't try that hard. - /// - /// This is duplicated in the `core`, `alloc` test suites (as well as - /// `std`'s integration tests), but figuring out a mechanism to share these - /// seems far more painful than copy-pasting a 7 line function a couple - /// times, given that even under a perma-unstable feature, I don't think we - /// want to expose types from `rand` from `std`. - #[track_caller] - pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { - use core::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = crate::hash::RandomState::new().build_hasher(); - core::panic::Location::caller().hash(&mut hasher); - let hc64 = hasher.finish(); - let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); - let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); - rand::SeedableRng::from_seed(seed) - } -} +pub(crate) mod test_helpers; diff --git a/std/src/os/unix/fs/tests.rs b/std/src/os/unix/fs/tests.rs index 67f607bd46837..db9621c8c205c 100644 --- a/std/src/os/unix/fs/tests.rs +++ b/std/src/os/unix/fs/tests.rs @@ -3,7 +3,7 @@ use super::*; #[test] fn read_vectored_at() { let msg = b"preadv is working!"; - let dir = crate::sys_common::io::test::tmpdir(); + let dir = crate::test_helpers::tmpdir(); let filename = dir.join("preadv.txt"); { @@ -31,7 +31,7 @@ fn read_vectored_at() { #[test] fn write_vectored_at() { let msg = b"pwritev is not working!"; - let dir = crate::sys_common::io::test::tmpdir(); + let dir = crate::test_helpers::tmpdir(); let filename = dir.join("preadv.txt"); { diff --git a/std/src/os/unix/net/tests.rs b/std/src/os/unix/net/tests.rs index 21e2176185d25..0398a535eb54a 100644 --- a/std/src/os/unix/net/tests.rs +++ b/std/src/os/unix/net/tests.rs @@ -7,7 +7,7 @@ use crate::os::android::net::{SocketAddrExt, UnixSocketExt}; use crate::os::linux::net::{SocketAddrExt, UnixSocketExt}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::os::unix::io::AsRawFd; -use crate::sys_common::io::test::tmpdir; +use crate::test_helpers::tmpdir; use crate::thread; use crate::time::Duration; diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index 9b87259abefc1..69273d863ebbd 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -549,7 +549,7 @@ fn debug_print() { #[test] #[cfg(windows)] fn run_bat_script() { - let tempdir = crate::sys_common::io::test::tmpdir(); + let tempdir = crate::test_helpers::tmpdir(); let script_path = tempdir.join("hello.cmd"); crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap(); @@ -568,7 +568,7 @@ fn run_bat_script() { #[test] #[cfg(windows)] fn run_canonical_bat_script() { - let tempdir = crate::sys_common::io::test::tmpdir(); + let tempdir = crate::test_helpers::tmpdir(); let script_path = tempdir.join("hello.cmd"); crate::fs::write(&script_path, "@echo Hello, %~1!").unwrap(); diff --git a/std/src/sys/io/mod.rs b/std/src/sys/io/mod.rs index 4605b56f8f16c..e00b479109f39 100644 --- a/std/src/sys/io/mod.rs +++ b/std/src/sys/io/mod.rs @@ -38,3 +38,7 @@ mod is_terminal { pub use io_slice::{IoSlice, IoSliceMut}; pub use is_terminal::is_terminal; + +// Bare metal platforms usually have very small amounts of RAM +// (in the order of hundreds of KB) +pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; diff --git a/std/src/sys/pal/sgx/stdio.rs b/std/src/sys/pal/sgx/stdio.rs index 2e680e740fde3..e79a3d971c6be 100644 --- a/std/src/sys/pal/sgx/stdio.rs +++ b/std/src/sys/pal/sgx/stdio.rs @@ -62,7 +62,7 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { // FIXME: Rust normally maps Unix EBADF to `Uncategorized` diff --git a/std/src/sys/pal/unix/kernel_copy/tests.rs b/std/src/sys/pal/unix/kernel_copy/tests.rs index 1350d743ff6f3..54d8f8ed2edd4 100644 --- a/std/src/sys/pal/unix/kernel_copy/tests.rs +++ b/std/src/sys/pal/unix/kernel_copy/tests.rs @@ -2,7 +2,7 @@ use crate::fs::OpenOptions; use crate::io; use crate::io::{BufRead, Read, Result, Seek, SeekFrom, Write}; use crate::os::unix::io::AsRawFd; -use crate::sys_common::io::test::tmpdir; +use crate::test_helpers::tmpdir; #[test] fn copy_specialization() -> Result<()> { diff --git a/std/src/sys/pal/unix/stdio.rs b/std/src/sys/pal/unix/stdio.rs index 97e75f1b5b669..8c2f61a40de3b 100644 --- a/std/src/sys/pal/unix/stdio.rs +++ b/std/src/sys/pal/unix/stdio.rs @@ -92,7 +92,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { err.raw_os_error() == Some(libc::EBADF as i32) } -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { Some(Stderr::new()) diff --git a/std/src/sys/pal/wasi/stdio.rs b/std/src/sys/pal/wasi/stdio.rs index ca49f871e1957..d08b772e5fc7d 100644 --- a/std/src/sys/pal/wasi/stdio.rs +++ b/std/src/sys/pal/wasi/stdio.rs @@ -101,7 +101,7 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into()) diff --git a/std/src/sys/pal/windows/process/tests.rs b/std/src/sys/pal/windows/process/tests.rs index 1bcc5fa6b2048..9a1eaf42fd9a8 100644 --- a/std/src/sys/pal/windows/process/tests.rs +++ b/std/src/sys/pal/windows/process/tests.rs @@ -158,7 +158,7 @@ fn windows_exe_resolver() { use super::resolve_exe; use crate::io; use crate::sys::fs::symlink; - use crate::sys_common::io::test::tmpdir; + use crate::test_helpers::tmpdir; let env_paths = || env::var_os("PATH"); diff --git a/std/src/sys/pal/zkvm/stdio.rs b/std/src/sys/pal/zkvm/stdio.rs index dd218c8894ca5..5f1d06dd1d78d 100644 --- a/std/src/sys/pal/zkvm/stdio.rs +++ b/std/src/sys/pal/zkvm/stdio.rs @@ -54,7 +54,7 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(_err: &io::Error) -> bool { true diff --git a/std/src/sys_common/io.rs b/std/src/sys_common/io.rs deleted file mode 100644 index 6f6f282d432d6..0000000000000 --- a/std/src/sys_common/io.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Bare metal platforms usually have very small amounts of RAM -// (in the order of hundreds of KB) -pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; - -#[cfg(test)] -#[allow(dead_code)] // not used on emscripten and wasi -pub mod test { - use rand::RngCore; - - use crate::path::{Path, PathBuf}; - use crate::{env, fs, thread}; - - pub struct TempDir(PathBuf); - - impl TempDir { - pub fn join(&self, path: &str) -> PathBuf { - let TempDir(ref p) = *self; - p.join(path) - } - - pub fn path(&self) -> &Path { - let TempDir(ref p) = *self; - p - } - } - - impl Drop for TempDir { - fn drop(&mut self) { - // Gee, seeing how we're testing the fs module I sure hope that we - // at least implement this correctly! - let TempDir(ref p) = *self; - let result = fs::remove_dir_all(p); - // Avoid panicking while panicking as this causes the process to - // immediately abort, without displaying test results. - if !thread::panicking() { - result.unwrap(); - } - } - } - - #[track_caller] // for `test_rng` - pub fn tmpdir() -> TempDir { - let p = env::temp_dir(); - let mut r = crate::test_helpers::test_rng(); - let ret = p.join(&format!("rust-{}", r.next_u32())); - fs::create_dir(&ret).unwrap(); - TempDir(ret) - } -} diff --git a/std/src/sys_common/mod.rs b/std/src/sys_common/mod.rs index 959fbd4ca0a11..4dc67d26bd8ff 100644 --- a/std/src/sys_common/mod.rs +++ b/std/src/sys_common/mod.rs @@ -21,7 +21,6 @@ mod tests; pub mod fs; -pub mod io; pub mod process; pub mod wstr; pub mod wtf8; diff --git a/std/src/test_helpers.rs b/std/src/test_helpers.rs new file mode 100644 index 0000000000000..7c20f38c863b6 --- /dev/null +++ b/std/src/test_helpers.rs @@ -0,0 +1,65 @@ +use rand::{RngCore, SeedableRng}; + +use crate::hash::{BuildHasher, Hash, Hasher, RandomState}; +use crate::panic::Location; +use crate::path::{Path, PathBuf}; +use crate::{env, fs, thread}; + +/// Test-only replacement for `rand::thread_rng()`, which is unusable for +/// us, as we want to allow running stdlib tests on tier-3 targets which may +/// not have `getrandom` support. +/// +/// Does a bit of a song and dance to ensure that the seed is different on +/// each call (as some tests sadly rely on this), but doesn't try that hard. +/// +/// This is duplicated in the `core`, `alloc` test suites (as well as +/// `std`'s integration tests), but figuring out a mechanism to share these +/// seems far more painful than copy-pasting a 7 line function a couple +/// times, given that even under a perma-unstable feature, I don't think we +/// want to expose types from `rand` from `std`. +#[track_caller] +pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { + let mut hasher = RandomState::new().build_hasher(); + Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + SeedableRng::from_seed(seed) +} + +pub struct TempDir(PathBuf); + +impl TempDir { + pub fn join(&self, path: &str) -> PathBuf { + let TempDir(ref p) = *self; + p.join(path) + } + + pub fn path(&self) -> &Path { + let TempDir(ref p) = *self; + p + } +} + +impl Drop for TempDir { + fn drop(&mut self) { + // Gee, seeing how we're testing the fs module I sure hope that we + // at least implement this correctly! + let TempDir(ref p) = *self; + let result = fs::remove_dir_all(p); + // Avoid panicking while panicking as this causes the process to + // immediately abort, without displaying test results. + if !thread::panicking() { + result.unwrap(); + } + } +} + +#[track_caller] // for `test_rng` +pub fn tmpdir() -> TempDir { + let p = env::temp_dir(); + let mut r = test_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); + fs::create_dir(&ret).unwrap(); + TempDir(ret) +} diff --git a/std/tests/common/mod.rs b/std/tests/common/mod.rs index 7cf70c725e411..1e8e4cced6c03 100644 --- a/std/tests/common/mod.rs +++ b/std/tests/common/mod.rs @@ -18,7 +18,7 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { rand::SeedableRng::from_seed(seed) } -// Copied from std::sys_common::io +// Copied from std::test_helpers pub(crate) struct TempDir(PathBuf); impl TempDir { From c62a207d67f16e7cef2b4321e9c19419ac31759e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Sun, 26 Jan 2025 19:12:54 +0100 Subject: [PATCH 472/481] Optimize `Rc::::default()` implementation This PR lets `impl Default for Rc` re-use the implementation for `Rc::<[u8]>::default()`. The previous version only calculted the memory layout at runtime, even though it should be known at compile time, resulting in an additional function call. The same optimization is done for `Rc`. Generated byte code: . Resolves . --- alloc/src/ffi/c_str.rs | 5 +++-- alloc/src/rc.rs | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index c7d6d8a55c2e3..07c75677d0532 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -965,8 +965,9 @@ impl Default for Rc { /// This may or may not share an allocation with other Rcs on the same thread. #[inline] fn default() -> Self { - let c_str: &CStr = Default::default(); - Rc::from(c_str) + let rc = Rc::<[u8]>::from(*b"\0"); + // `[u8]` has the same layout as `CStr`, and it is `NUL` terminated. + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } } } diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index ae3318b839dd7..05e76ccf685e1 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -2369,7 +2369,9 @@ impl Default for Rc { /// This may or may not share an allocation with other Rcs on the same thread. #[inline] fn default() -> Self { - Rc::from("") + let rc = Rc::<[u8]>::default(); + // `[u8]` has the same layout as `str`. + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } } } From 61d392b5c7b631fd453bee3d18f98defe404dd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Fri, 7 Feb 2025 13:40:04 +0100 Subject: [PATCH 473/481] Clean up 'HashMap' and 'HashSet' docs; --- std/src/collections/hash/map.rs | 12 ++++++------ std/src/collections/hash/set.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 5013826cb9b3b..6a0ff3a29e08f 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -282,7 +282,7 @@ impl HashMap { /// manually using this function can expose a DoS attack vector. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. + /// the `HashMap` to be useful, see its documentation for details. /// /// # Examples /// @@ -314,7 +314,7 @@ impl HashMap { /// manually using this function can expose a DoS attack vector. /// /// The `hasher` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. + /// the `HashMap` to be useful, see its documentation for details. /// /// # Examples /// @@ -1283,7 +1283,7 @@ impl HashMap where S: BuildHasher, { - /// Creates a raw entry builder for the HashMap. + /// Creates a raw entry builder for the `HashMap`. /// /// Raw entries provide the lowest level of control for searching and /// manipulating a map. They must be manually initialized with a hash and @@ -1298,13 +1298,13 @@ where /// * Using custom comparison logic without newtype wrappers /// /// Because raw entries provide much more low-level control, it's much easier - /// to put the HashMap into an inconsistent state which, while memory-safe, + /// to put the `HashMap` into an inconsistent state which, while memory-safe, /// will cause the map to produce seemingly random results. Higher-level and /// more foolproof APIs like `entry` should be preferred when possible. /// /// In particular, the hash used to initialize the raw entry must still be /// consistent with the hash of the key that is ultimately stored in the entry. - /// This is because implementations of HashMap may need to recompute hashes + /// This is because implementations of `HashMap` may need to recompute hashes /// when resizing, at which point only the keys are available. /// /// Raw entries give mutable access to the keys. This must not be used @@ -1320,7 +1320,7 @@ where RawEntryBuilderMut { map: self } } - /// Creates a raw immutable entry builder for the HashMap. + /// Creates a raw immutable entry builder for the `HashMap`. /// /// Raw entries provide the lowest level of control for searching and /// manipulating a map. They must be manually initialized with a hash and diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index bbb6ca2352136..c265d42d06a9f 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -374,7 +374,7 @@ impl HashSet { /// manually using this function can expose a DoS attack vector. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. + /// the `HashSet` to be useful, see its documentation for details. /// /// # Examples /// @@ -406,7 +406,7 @@ impl HashSet { /// manually using this function can expose a DoS attack vector. /// /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. + /// the `HashSet` to be useful, see its documentation for details. /// /// # Examples /// From 1d75f41c43ac94a668782cfd5450a4b09342f790 Mon Sep 17 00:00:00 2001 From: Jaken Herman Date: Fri, 7 Feb 2025 12:45:56 -0600 Subject: [PATCH 474/481] Document `Sum::sum` returns additive identities for `[]` Because the neutral element of `` was changed to `neg_zero`, the documentation needed to be updated, as it was reporting inadequate information about what should be expected from the return. Co-authored-by: Jubilee --- core/src/iter/traits/iterator.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/iter/traits/iterator.rs b/core/src/iter/traits/iterator.rs index 91c3a4b29b539..42886e90f997d 100644 --- a/core/src/iter/traits/iterator.rs +++ b/core/src/iter/traits/iterator.rs @@ -3493,7 +3493,8 @@ pub trait Iterator { /// /// Takes each element, adds them together, and returns the result. /// - /// An empty iterator returns the zero value of the type. + /// An empty iterator returns the *additive identity* ("zero") of the type, + /// which is `0` for integers and `-0.0` for floats. /// /// `sum()` can be used to sum any type implementing [`Sum`][`core::iter::Sum`], /// including [`Option`][`Option::sum`] and [`Result`][`Result::sum`]. @@ -3511,6 +3512,10 @@ pub trait Iterator { /// let sum: i32 = a.iter().sum(); /// /// assert_eq!(sum, 6); + /// + /// let b: Vec = vec![]; + /// let sum: f32 = b.iter().sum(); + /// assert_eq!(sum, -0.0_f32); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] fn sum(self) -> S From 0d224656d4010e83cace2026d8c702a27e92edb2 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sat, 8 Feb 2025 02:45:29 +0100 Subject: [PATCH 475/481] Make `AsyncFnOnce`, `AsyncFnMut`, `AsyncFn` non-`#[fundamental]` --- core/src/ops/async_function.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/ops/async_function.rs b/core/src/ops/async_function.rs index c90ae7babbd93..6be42ca7d32fe 100644 --- a/core/src/ops/async_function.rs +++ b/core/src/ops/async_function.rs @@ -6,7 +6,6 @@ use crate::marker::Tuple; /// All `async fn` and functions returning futures implement this trait. #[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] -#[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] #[lang = "async_fn"] pub trait AsyncFn: AsyncFnMut { @@ -20,7 +19,6 @@ pub trait AsyncFn: AsyncFnMut { /// All `async fn` and functions returning futures implement this trait. #[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] -#[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] #[lang = "async_fn_mut"] pub trait AsyncFnMut: AsyncFnOnce { @@ -41,7 +39,6 @@ pub trait AsyncFnMut: AsyncFnOnce { /// All `async fn` and functions returning futures implement this trait. #[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] -#[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] #[lang = "async_fn_once"] pub trait AsyncFnOnce { From c736a5fa990b9571b529f05cf3c94de284b79e58 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 23 Dec 2024 07:08:00 +0000 Subject: [PATCH 476/481] Windows: remove readonly files --- std/src/fs/tests.rs | 2 +- std/src/sys/pal/windows/fs.rs | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index e3810030dedf7..8e307f57cf9d2 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -1384,7 +1384,7 @@ fn file_try_clone() { } #[test] -#[cfg(not(windows))] +#[cfg(not(target_vendor = "win7"))] fn unlink_readonly() { let tmpdir = tmpdir(); let path = tmpdir.join("file"); diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index f8493c21ad444..750cf7faeaeab 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -296,6 +296,10 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = maybe_verbatim(path)?; + Self::open_native(&path, opts) + } + + fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result { let creation = opts.get_creation_mode()?; let handle = unsafe { c::CreateFileW( @@ -1226,8 +1230,24 @@ pub fn readdir(p: &Path) -> io::Result { pub fn unlink(p: &Path) -> io::Result<()> { let p_u16s = maybe_verbatim(p)?; - cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?; - Ok(()) + if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 { + let err = api::get_last_error(); + // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove + // the file while ignoring the readonly attribute. + // This is accomplished by calling the `posix_delete` function on an open file handle. + if err == WinError::ACCESS_DENIED { + let mut opts = OpenOptions::new(); + opts.access_mode(c::DELETE); + opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); + if File::open_native(&p_u16s, &opts).map(|f| f.posix_delete()).is_ok() { + return Ok(()); + } + } + // return the original error if any of the above fails. + Err(io::Error::from_raw_os_error(err.code as i32)) + } else { + Ok(()) + } } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { From 64cf2557a993dfb0041ab262dd5ebc668f794862 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 26 Dec 2024 10:42:06 +0000 Subject: [PATCH 477/481] Update platform information for remove_file --- std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index a5b0111adfb4a..0871a9e22d386 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -2307,8 +2307,8 @@ impl AsInner for DirEntry { /// /// # Platform-specific behavior /// -/// This function currently corresponds to the `unlink` function on Unix -/// and the `DeleteFile` function on Windows. +/// This function currently corresponds to the `unlink` function on Unix. +/// On Windows, `DeleteFile` is used or `CreateFileW` and `SetInformationByHandle` for readonly files. /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior From cadedd724f55a410846350f5f242c77770611f6a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 26 Jan 2025 06:15:58 +0000 Subject: [PATCH 478/481] Windows: Test that deleting a running binary fails --- std/src/sys/pal/windows/fs.rs | 6 ++++-- std/tests/win_delete_self.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 std/tests/win_delete_self.rs diff --git a/std/src/sys/pal/windows/fs.rs b/std/src/sys/pal/windows/fs.rs index 750cf7faeaeab..bdb55643bb101 100644 --- a/std/src/sys/pal/windows/fs.rs +++ b/std/src/sys/pal/windows/fs.rs @@ -1239,8 +1239,10 @@ pub fn unlink(p: &Path) -> io::Result<()> { let mut opts = OpenOptions::new(); opts.access_mode(c::DELETE); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); - if File::open_native(&p_u16s, &opts).map(|f| f.posix_delete()).is_ok() { - return Ok(()); + if let Ok(f) = File::open_native(&p_u16s, &opts) { + if f.posix_delete().is_ok() { + return Ok(()); + } } } // return the original error if any of the above fails. diff --git a/std/tests/win_delete_self.rs b/std/tests/win_delete_self.rs new file mode 100644 index 0000000000000..1c3ce4d710c38 --- /dev/null +++ b/std/tests/win_delete_self.rs @@ -0,0 +1,8 @@ +#![cfg(windows)] + +/// Attempting to delete a running binary should return an error on Windows. +#[test] +fn win_delete_self() { + let path = std::env::current_exe().unwrap(); + assert!(std::fs::remove_file(path).is_err()); +} From e98bfe644375eded847aad2f0702abf7017c03d7 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 28 Jan 2025 00:25:28 +0000 Subject: [PATCH 479/481] Allow Rust to use a number of libc filesystem calls This allows Rust on Fuchsia to use a number of function calls from libc: * dirfd * fdatasync * flock with LOCK_EX, LOCK_SH, LOCK_NB, LOCK_UN * fstatat --- std/src/sys/pal/unix/fs.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/std/src/sys/pal/unix/fs.rs b/std/src/sys/pal/unix/fs.rs index 6c41781fe850c..00cfa7a7fcfda 100644 --- a/std/src/sys/pal/unix/fs.rs +++ b/std/src/sys/pal/unix/fs.rs @@ -9,9 +9,12 @@ use libc::c_char; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), target_os = "android", + target_os = "fuchsia", target_os = "hurd" ))] use libc::dirfd; +#[cfg(target_os = "fuchsia")] +use libc::fstatat as fstatat64; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::fstatat64; #[cfg(any( @@ -848,7 +851,6 @@ impl Drop for Dir { target_os = "vita", target_os = "hurd", target_os = "espidf", - target_os = "fuchsia", target_os = "horizon", target_os = "vxworks", target_os = "rtems", @@ -880,6 +882,7 @@ impl DirEntry { any( all(target_os = "linux", not(target_env = "musl")), target_os = "android", + target_os = "fuchsia", target_os = "hurd" ), not(miri) // no dirfd on Miri @@ -908,6 +911,7 @@ impl DirEntry { not(any( all(target_os = "linux", not(target_env = "musl")), target_os = "android", + target_os = "fuchsia", target_os = "hurd", )), miri @@ -1211,6 +1215,7 @@ impl File { } #[cfg(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "android", target_os = "netbsd", @@ -1223,6 +1228,7 @@ impl File { } #[cfg(not(any( target_os = "android", + target_os = "fuchsia", target_os = "freebsd", target_os = "linux", target_os = "netbsd", @@ -1238,6 +1244,7 @@ impl File { #[cfg(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1249,6 +1256,7 @@ impl File { #[cfg(not(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1259,6 +1267,7 @@ impl File { #[cfg(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1270,6 +1279,7 @@ impl File { #[cfg(not(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1280,6 +1290,7 @@ impl File { #[cfg(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1297,6 +1308,7 @@ impl File { #[cfg(not(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1307,6 +1319,7 @@ impl File { #[cfg(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1324,6 +1337,7 @@ impl File { #[cfg(not(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1334,6 +1348,7 @@ impl File { #[cfg(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -1345,6 +1360,7 @@ impl File { #[cfg(not(any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", From 5e9cfe0c7b114f227cce325e325d1c4f8c4f6e1b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 8 Feb 2025 22:28:21 +0000 Subject: [PATCH 480/481] occured -> occurred --- core/src/panicking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/panicking.rs b/core/src/panicking.rs index a89de12c02bdc..b97f19e1baa93 100644 --- a/core/src/panicking.rs +++ b/core/src/panicking.rs @@ -302,7 +302,7 @@ fn panic_null_pointer_dereference() -> ! { } panic_nounwind_fmt( - format_args!("null pointer dereference occured"), + format_args!("null pointer dereference occurred"), /* force_no_backtrace */ false, ) } From c99d2c5ef1f3d20d770bc9d402a64733fc586d48 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Feb 2025 22:12:13 +0000 Subject: [PATCH 481/481] Rustfmt --- alloc/src/collections/btree/set/tests.rs | 16 +- alloc/src/collections/linked_list/tests.rs | 28 ++-- alloc/src/collections/vec_deque/tests.rs | 7 +- alloc/src/rc.rs | 9 +- alloc/src/sync.rs | 13 +- alloc/tests/str.rs | 165 ++++++++++--------- alloc/tests/string.rs | 35 ++-- core/src/cell.rs | 17 +- coretests/tests/iter/adapters/map_windows.rs | 9 +- panic_unwind/src/emcc.rs | 13 +- std/src/io/stdio/tests.rs | 7 +- std/src/os/windows/process.rs | 8 +- std/src/os/xous/ffi/definitions.rs | 66 ++++---- std/src/sys/pal/itron/time/tests.rs | 30 ++-- std/src/sys/pal/windows/args/tests.rs | 8 +- std/src/sys_common/wtf8/tests.rs | 111 ++++++------- 16 files changed, 292 insertions(+), 250 deletions(-) diff --git a/alloc/src/collections/btree/set/tests.rs b/alloc/src/collections/btree/set/tests.rs index 990044e069f64..d538ef707eb93 100644 --- a/alloc/src/collections/btree/set/tests.rs +++ b/alloc/src/collections/btree/set/tests.rs @@ -132,9 +132,11 @@ fn test_difference() { check_difference(&[1, 3, 5, 9, 11], &[3, 6, 9], &[1, 5, 11]); check_difference(&[1, 3, 5, 9, 11], &[0, 1], &[3, 5, 9, 11]); check_difference(&[1, 3, 5, 9, 11], &[11, 12], &[1, 3, 5, 9]); - check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[ - 11, 22, 33, 40, 42, - ]); + check_difference( + &[-5, 11, 22, 33, 40, 42], + &[-12, -5, 14, 23, 34, 38, 39, 50], + &[11, 22, 33, 40, 42], + ); if cfg!(miri) { // Miri is too slow @@ -250,9 +252,11 @@ fn test_union() { check_union(&[], &[], &[]); check_union(&[1, 2, 3], &[2], &[1, 2, 3]); check_union(&[2], &[1, 2, 3], &[1, 2, 3]); - check_union(&[1, 3, 5, 9, 11, 16, 19, 24], &[-2, 1, 5, 9, 13, 19], &[ - -2, 1, 3, 5, 9, 11, 13, 16, 19, 24, - ]); + check_union( + &[1, 3, 5, 9, 11, 16, 19, 24], + &[-2, 1, 5, 9, 13, 19], + &[-2, 1, 3, 5, 9, 11, 13, 16, 19, 24], + ); } #[test] diff --git a/alloc/src/collections/linked_list/tests.rs b/alloc/src/collections/linked_list/tests.rs index aa19239f6c55d..812fe229a0fc5 100644 --- a/alloc/src/collections/linked_list/tests.rs +++ b/alloc/src/collections/linked_list/tests.rs @@ -696,9 +696,10 @@ fn test_cursor_mut_insert() { cursor.splice_after(p); cursor.splice_before(q); check_links(&m); - assert_eq!(m.iter().cloned().collect::>(), &[ - 200, 201, 202, 203, 1, 100, 101, 102, 103, 8, 2, 3, 4, 5, 6 - ]); + assert_eq!( + m.iter().cloned().collect::>(), + &[200, 201, 202, 203, 1, 100, 101, 102, 103, 8, 2, 3, 4, 5, 6] + ); let mut cursor = m.cursor_front_mut(); cursor.move_prev(); let tmp = cursor.split_before(); @@ -915,9 +916,10 @@ fn extract_if_complex() { assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); assert_eq!(list.len(), 14); - assert_eq!(list.into_iter().collect::>(), vec![ - 1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39 - ]); + assert_eq!( + list.into_iter().collect::>(), + vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39] + ); } { @@ -932,9 +934,10 @@ fn extract_if_complex() { assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); assert_eq!(list.len(), 13); - assert_eq!(list.into_iter().collect::>(), vec![ - 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39 - ]); + assert_eq!( + list.into_iter().collect::>(), + vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39] + ); } { @@ -949,9 +952,10 @@ fn extract_if_complex() { assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); assert_eq!(list.len(), 11); - assert_eq!(list.into_iter().collect::>(), vec![ - 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35 - ]); + assert_eq!( + list.into_iter().collect::>(), + vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35] + ); } { diff --git a/alloc/src/collections/vec_deque/tests.rs b/alloc/src/collections/vec_deque/tests.rs index 6328b3b4db867..c90679f179775 100644 --- a/alloc/src/collections/vec_deque/tests.rs +++ b/alloc/src/collections/vec_deque/tests.rs @@ -562,9 +562,10 @@ fn make_contiguous_head_to_end() { tester.push_front(i as char); } - assert_eq!(tester, [ - 'P', 'O', 'N', 'M', 'L', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' - ]); + assert_eq!( + tester, + ['P', 'O', 'N', 'M', 'L', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'] + ); // ABCDEFGHIJKPONML let expected_start = 0; diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 05e76ccf685e1..6d82f514aa683 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -2350,11 +2350,10 @@ impl Default for Rc { fn default() -> Rc { unsafe { Self::from_inner( - Box::leak(Box::write(Box::new_uninit(), RcInner { - strong: Cell::new(1), - weak: Cell::new(1), - value: T::default(), - })) + Box::leak(Box::write( + Box::new_uninit(), + RcInner { strong: Cell::new(1), weak: Cell::new(1), value: T::default() }, + )) .into(), ) } diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 431e19e6ef1d7..dba1449347ac0 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -3466,11 +3466,14 @@ impl Default for Arc { fn default() -> Arc { unsafe { Self::from_inner( - Box::leak(Box::write(Box::new_uninit(), ArcInner { - strong: atomic::AtomicUsize::new(1), - weak: atomic::AtomicUsize::new(1), - data: T::default(), - })) + Box::leak(Box::write( + Box::new_uninit(), + ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data: T::default(), + }, + )) .into(), ) } diff --git a/alloc/tests/str.rs b/alloc/tests/str.rs index 5720d3ffd97b6..23a0e5e525643 100644 --- a/alloc/tests/str.rs +++ b/alloc/tests/str.rs @@ -1524,18 +1524,14 @@ fn test_lines() { t("bare\r", &["bare\r"]); t("bare\rcr", &["bare\rcr"]); t("Text\n\r", &["Text", "\r"]); - t("\nMäry häd ä little lämb\n\r\nLittle lämb\n", &[ - "", - "Märy häd ä little lämb", - "", - "Little lämb", - ]); - t("\r\nMäry häd ä little lämb\n\nLittle lämb", &[ - "", - "Märy häd ä little lämb", - "", - "Little lämb", - ]); + t( + "\nMäry häd ä little lämb\n\r\nLittle lämb\n", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); + t( + "\r\nMäry häd ä little lämb\n\nLittle lämb", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); } #[test] @@ -1978,73 +1974,88 @@ mod pattern { assert_eq!(v, right); } - make_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", [ - Reject(0, 1), - Match(1, 3), - Reject(3, 4), - Match(4, 6), - Reject(6, 7), - ]); - make_test!(str_searcher_ascii_haystack_seq, "bb", "abbcbbbbd", [ - Reject(0, 1), - Match(1, 3), - Reject(3, 4), - Match(4, 6), - Match(6, 8), - Reject(8, 9), - ]); - make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [ - Match(0, 0), - Reject(0, 1), - Match(1, 1), - Reject(1, 2), - Match(2, 2), - Reject(2, 3), - Match(3, 3), - Reject(3, 4), - Match(4, 4), - Reject(4, 5), - Match(5, 5), - Reject(5, 6), - Match(6, 6), - Reject(6, 7), - Match(7, 7), - ]); - make_test!(str_searcher_multibyte_haystack, " ", "├──", [ - Reject(0, 3), - Reject(3, 6), - Reject(6, 9), - ]); - make_test!(str_searcher_empty_needle_multibyte_haystack, "", "├──", [ - Match(0, 0), - Reject(0, 3), - Match(3, 3), - Reject(3, 6), - Match(6, 6), - Reject(6, 9), - Match(9, 9), - ]); + make_test!( + str_searcher_ascii_haystack, + "bb", + "abbcbbd", + [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),] + ); + make_test!( + str_searcher_ascii_haystack_seq, + "bb", + "abbcbbbbd", + [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),] + ); + make_test!( + str_searcher_empty_needle_ascii_haystack, + "", + "abbcbbd", + [ + Match(0, 0), + Reject(0, 1), + Match(1, 1), + Reject(1, 2), + Match(2, 2), + Reject(2, 3), + Match(3, 3), + Reject(3, 4), + Match(4, 4), + Reject(4, 5), + Match(5, 5), + Reject(5, 6), + Match(6, 6), + Reject(6, 7), + Match(7, 7), + ] + ); + make_test!( + str_searcher_multibyte_haystack, + " ", + "├──", + [Reject(0, 3), Reject(3, 6), Reject(6, 9),] + ); + make_test!( + str_searcher_empty_needle_multibyte_haystack, + "", + "├──", + [ + Match(0, 0), + Reject(0, 3), + Match(3, 3), + Reject(3, 6), + Match(6, 6), + Reject(6, 9), + Match(9, 9), + ] + ); make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]); make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []); - make_test!(char_searcher_ascii_haystack, 'b', "abbcbbd", [ - Reject(0, 1), - Match(1, 2), - Match(2, 3), - Reject(3, 4), - Match(4, 5), - Match(5, 6), - Reject(6, 7), - ]); - make_test!(char_searcher_multibyte_haystack, ' ', "├──", [ - Reject(0, 3), - Reject(3, 6), - Reject(6, 9), - ]); - make_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", [ - Reject(0, 1), - Reject(1, 2), - Reject(2, 3), - ]); + make_test!( + char_searcher_ascii_haystack, + 'b', + "abbcbbd", + [ + Reject(0, 1), + Match(1, 2), + Match(2, 3), + Reject(3, 4), + Match(4, 5), + Match(5, 6), + Reject(6, 7), + ] + ); + make_test!( + char_searcher_multibyte_haystack, + ' ', + "├──", + [Reject(0, 3), Reject(3, 6), Reject(6, 9),] + ); + make_test!( + char_searcher_short_haystack, + '\u{1F4A9}', + "* \t", + [Reject(0, 1), Reject(1, 2), Reject(2, 3),] + ); // See #85462 #[test] diff --git a/alloc/tests/string.rs b/alloc/tests/string.rs index 1c8bff1564db2..d996c55f94660 100644 --- a/alloc/tests/string.rs +++ b/alloc/tests/string.rs @@ -154,19 +154,28 @@ fn test_fromutf8error_into_lossy() { #[test] fn test_from_utf16() { let pairs = [ - (String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"), vec![ - 0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39, 0xd800, - 0xdf3b, 0xd800, 0xdf30, 0x000a, - ]), - (String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"), vec![ - 0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32, 0xd801, - 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a, - ]), - (String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"), vec![ - 0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11, 0xd800, - 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800, 0xdf04, 0xd800, - 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a, - ]), + ( + String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"), + vec![ + 0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39, + 0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a, + ], + ), + ( + String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"), + vec![ + 0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32, + 0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a, + ], + ), + ( + String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"), + vec![ + 0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11, + 0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800, + 0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a, + ], + ), ( String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"), vec![ diff --git a/core/src/cell.rs b/core/src/cell.rs index 320d8176011fd..cbf00106c5173 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -1590,10 +1590,10 @@ impl<'b, T: ?Sized> Ref<'b, T> { { let (a, b) = f(&*orig); let borrow = orig.borrow.clone(); - (Ref { value: NonNull::from(a), borrow }, Ref { - value: NonNull::from(b), - borrow: orig.borrow, - }) + ( + Ref { value: NonNull::from(a), borrow }, + Ref { value: NonNull::from(b), borrow: orig.borrow }, + ) } /// Converts into a reference to the underlying data. @@ -1758,11 +1758,10 @@ impl<'b, T: ?Sized> RefMut<'b, T> { { let borrow = orig.borrow.clone(); let (a, b) = f(&mut *orig); - (RefMut { value: NonNull::from(a), borrow, marker: PhantomData }, RefMut { - value: NonNull::from(b), - borrow: orig.borrow, - marker: PhantomData, - }) + ( + RefMut { value: NonNull::from(a), borrow, marker: PhantomData }, + RefMut { value: NonNull::from(b), borrow: orig.borrow, marker: PhantomData }, + ) } /// Converts into a mutable reference to the underlying data. diff --git a/coretests/tests/iter/adapters/map_windows.rs b/coretests/tests/iter/adapters/map_windows.rs index b677f1cfd55e7..01cebc9b27fd8 100644 --- a/coretests/tests/iter/adapters/map_windows.rs +++ b/coretests/tests/iter/adapters/map_windows.rs @@ -159,11 +159,10 @@ fn output_n2() { >::new(), ); assert_eq!("ab".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![['a', 'b']]); - assert_eq!("abcd".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![ - ['a', 'b'], - ['b', 'c'], - ['c', 'd'] - ],); + assert_eq!( + "abcd".chars().map_windows(|a: &[_; 2]| *a).collect::>(), + vec![['a', 'b'], ['b', 'c'], ['c', 'd']], + ); } #[test] diff --git a/panic_unwind/src/emcc.rs b/panic_unwind/src/emcc.rs index 9127449edb1a7..86906b46d66ba 100644 --- a/panic_unwind/src/emcc.rs +++ b/panic_unwind/src/emcc.rs @@ -98,11 +98,14 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } - ptr::write(exception, Exception { - canary: &EXCEPTION_TYPE_INFO, - caught: AtomicBool::new(false), - data: Some(data), - }); + ptr::write( + exception, + Exception { + canary: &EXCEPTION_TYPE_INFO, + caught: AtomicBool::new(false), + data: Some(data), + }, + ); __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); } diff --git a/std/src/io/stdio/tests.rs b/std/src/io/stdio/tests.rs index bf8f3a5adfb6f..e68d8c29fbce2 100644 --- a/std/src/io/stdio/tests.rs +++ b/std/src/io/stdio/tests.rs @@ -159,7 +159,8 @@ where assert_eq!(rx2.recv().unwrap(), Release2); // release th2 th2.join().unwrap(); th1.join().unwrap(); - assert_eq!(*log.lock().unwrap(), [ - Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1 - ]); + assert_eq!( + *log.lock().unwrap(), + [Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1] + ); } diff --git a/std/src/os/windows/process.rs b/std/src/os/windows/process.rs index 0277b79b8b69c..201274cf03aec 100644 --- a/std/src/os/windows/process.rs +++ b/std/src/os/windows/process.rs @@ -590,10 +590,10 @@ impl<'a> ProcThreadAttributeListBuilder<'a> { value_ptr: *const T, value_size: usize, ) -> Self { - self.attributes.insert(attribute, ProcThreadAttributeValue { - ptr: value_ptr.cast::(), - size: value_size, - }); + self.attributes.insert( + attribute, + ProcThreadAttributeValue { ptr: value_ptr.cast::(), size: value_size }, + ); self } diff --git a/std/src/os/xous/ffi/definitions.rs b/std/src/os/xous/ffi/definitions.rs index 1b16849af03b0..345005bcc78d7 100644 --- a/std/src/os/xous/ffi/definitions.rs +++ b/std/src/os/xous/ffi/definitions.rs @@ -126,36 +126,42 @@ impl From for Error { #[stable(feature = "rust1", since = "1.0.0")] impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", match self { - Error::NoError => "no error occurred", - Error::BadAlignment => "memory was not properly aligned", - Error::BadAddress => "an invalid address was supplied", - Error::OutOfMemory => "the process or service has run out of memory", - Error::MemoryInUse => "the requested address is in use", - Error::InterruptNotFound => "the requested interrupt does not exist on this platform", - Error::InterruptInUse => "the requested interrupt is currently in use", - Error::InvalidString => "the specified string was not formatted correctly", - Error::ServerExists => "a server with that address already exists", - Error::ServerNotFound => "the requetsed server could not be found", - Error::ProcessNotFound => "the target process does not exist", - Error::ProcessNotChild => "the requested operation can only be done on child processes", - Error::ProcessTerminated => "the target process has crashed", - Error::Timeout => "the requested operation timed out", - Error::InternalError => "an internal error occurred", - Error::ServerQueueFull => "the server has too many pending messages", - Error::ThreadNotAvailable => "the specified thread does not exist", - Error::UnhandledSyscall => "the kernel did not recognize that syscall", - Error::InvalidSyscall => "the syscall had incorrect parameters", - Error::ShareViolation => "an attempt was made to share memory twice", - Error::InvalidThread => "tried to resume a thread that was not ready", - Error::InvalidPid => "kernel attempted to use a pid that was not valid", - Error::AccessDenied => "no permission to perform the requested operation", - Error::UseBeforeInit => "attempt to use a service before initialization finished", - Error::DoubleFree => "the requested resource was freed twice", - Error::DebugInProgress => "kernel attempted to activate a thread being debugged", - Error::InvalidLimit => "process attempted to adjust an invalid limit", - Error::UnknownError => "an unknown error occurred", - }) + write!( + f, + "{}", + match self { + Error::NoError => "no error occurred", + Error::BadAlignment => "memory was not properly aligned", + Error::BadAddress => "an invalid address was supplied", + Error::OutOfMemory => "the process or service has run out of memory", + Error::MemoryInUse => "the requested address is in use", + Error::InterruptNotFound => + "the requested interrupt does not exist on this platform", + Error::InterruptInUse => "the requested interrupt is currently in use", + Error::InvalidString => "the specified string was not formatted correctly", + Error::ServerExists => "a server with that address already exists", + Error::ServerNotFound => "the requetsed server could not be found", + Error::ProcessNotFound => "the target process does not exist", + Error::ProcessNotChild => + "the requested operation can only be done on child processes", + Error::ProcessTerminated => "the target process has crashed", + Error::Timeout => "the requested operation timed out", + Error::InternalError => "an internal error occurred", + Error::ServerQueueFull => "the server has too many pending messages", + Error::ThreadNotAvailable => "the specified thread does not exist", + Error::UnhandledSyscall => "the kernel did not recognize that syscall", + Error::InvalidSyscall => "the syscall had incorrect parameters", + Error::ShareViolation => "an attempt was made to share memory twice", + Error::InvalidThread => "tried to resume a thread that was not ready", + Error::InvalidPid => "kernel attempted to use a pid that was not valid", + Error::AccessDenied => "no permission to perform the requested operation", + Error::UseBeforeInit => "attempt to use a service before initialization finished", + Error::DoubleFree => "the requested resource was freed twice", + Error::DebugInProgress => "kernel attempted to activate a thread being debugged", + Error::InvalidLimit => "process attempted to adjust an invalid limit", + Error::UnknownError => "an unknown error occurred", + } + ) } } diff --git a/std/src/sys/pal/itron/time/tests.rs b/std/src/sys/pal/itron/time/tests.rs index 28db4f8b6799f..d14035d9da49f 100644 --- a/std/src/sys/pal/itron/time/tests.rs +++ b/std/src/sys/pal/itron/time/tests.rs @@ -8,24 +8,26 @@ fn reltim2dur(t: u64) -> Duration { fn test_dur2reltims() { assert_eq!(dur2reltims(reltim2dur(0)).collect::>(), vec![]); assert_eq!(dur2reltims(reltim2dur(42)).collect::>(), vec![42]); - assert_eq!(dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), vec![ - abi::TMAX_RELTIM - ]); - assert_eq!(dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), vec![ - abi::TMAX_RELTIM, - 10000 - ]); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); } #[test] fn test_dur2tmos() { assert_eq!(dur2tmos(reltim2dur(0)).collect::>(), vec![0]); assert_eq!(dur2tmos(reltim2dur(42)).collect::>(), vec![42]); - assert_eq!(dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), vec![ - abi::TMAX_RELTIM - ]); - assert_eq!(dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), vec![ - abi::TMAX_RELTIM, - 10000 - ]); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); } diff --git a/std/src/sys/pal/windows/args/tests.rs b/std/src/sys/pal/windows/args/tests.rs index 6d5c953cbd5c6..484a90ab056df 100644 --- a/std/src/sys/pal/windows/args/tests.rs +++ b/std/src/sys/pal/windows/args/tests.rs @@ -47,10 +47,10 @@ fn whitespace_behavior() { fn genius_quotes() { chk(r#"EXE "" """#, &["EXE", "", ""]); chk(r#"EXE "" """"#, &["EXE", "", r#"""#]); - chk(r#"EXE "this is """all""" in the same argument""#, &[ - "EXE", - r#"this is "all" in the same argument"#, - ]); + chk( + r#"EXE "this is """all""" in the same argument""#, + &["EXE", r#"this is "all" in the same argument"#], + ); chk(r#"EXE "a"""#, &["EXE", r#"a""#]); chk(r#"EXE "a"" a"#, &["EXE", r#"a" a"#]); // quotes cannot be escaped in command names diff --git a/std/src/sys_common/wtf8/tests.rs b/std/src/sys_common/wtf8/tests.rs index bc06eaa2b8fa1..b57c99a8452a1 100644 --- a/std/src/sys_common/wtf8/tests.rs +++ b/std/src/sys_common/wtf8/tests.rs @@ -356,32 +356,32 @@ fn wtf8buf_from_iterator() { fn f(values: &[u32]) -> Wtf8Buf { values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() } - assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]), Wtf8Buf { - bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), - is_known_utf8: true - }); + assert_eq!( + f(&[0x61, 0xE9, 0x20, 0x1F4A9]), + Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } + ); assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]), Wtf8Buf { - bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), - is_known_utf8: false - }); - assert_eq!(f(&[0xD800, 0xDBFF]), Wtf8Buf { - bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), - is_known_utf8: false - }); - assert_eq!(f(&[0xD800, 0xE000]), Wtf8Buf { - bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), - is_known_utf8: false - }); - assert_eq!(f(&[0xD7FF, 0xDC00]), Wtf8Buf { - bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), - is_known_utf8: false - }); - assert_eq!(f(&[0x61, 0xDC00]), Wtf8Buf { - bytes: b"\x61\xED\xB0\x80".to_vec(), - is_known_utf8: false - }); + assert_eq!( + f(&[0xD83D, 0x20, 0xDCA9]), + Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD800, 0xDBFF]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD800, 0xE000]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0xD7FF, 0xDC00]), + Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + f(&[0x61, 0xDC00]), + Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); assert_eq!(f(&[0xDC00]), Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false }); } @@ -396,36 +396,36 @@ fn wtf8buf_extend() { string } - assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), Wtf8Buf { - bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), - is_known_utf8: true - }); + assert_eq!( + e(&[0x61, 0xE9], &[0x20, 0x1F4A9]), + Wtf8Buf { bytes: b"a\xC3\xA9 \xF0\x9F\x92\xA9".to_vec(), is_known_utf8: true } + ); assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]), Wtf8Buf { - bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), - is_known_utf8: false - }); - assert_eq!(e(&[0xD800], &[0xDBFF]), Wtf8Buf { - bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), - is_known_utf8: false - }); - assert_eq!(e(&[0xD800], &[0xE000]), Wtf8Buf { - bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), - is_known_utf8: false - }); - assert_eq!(e(&[0xD7FF], &[0xDC00]), Wtf8Buf { - bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), - is_known_utf8: false - }); - assert_eq!(e(&[0x61], &[0xDC00]), Wtf8Buf { - bytes: b"\x61\xED\xB0\x80".to_vec(), - is_known_utf8: false - }); - assert_eq!(e(&[], &[0xDC00]), Wtf8Buf { - bytes: b"\xED\xB0\x80".to_vec(), - is_known_utf8: false - }); + assert_eq!( + e(&[0xD83D, 0x20], &[0xDCA9]), + Wtf8Buf { bytes: b"\xED\xA0\xBD \xED\xB2\xA9".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD800], &[0xDBFF]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xED\xAF\xBF".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD800], &[0xE000]), + Wtf8Buf { bytes: b"\xED\xA0\x80\xEE\x80\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0xD7FF], &[0xDC00]), + Wtf8Buf { bytes: b"\xED\x9F\xBF\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[0x61], &[0xDC00]), + Wtf8Buf { bytes: b"\x61\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); + assert_eq!( + e(&[], &[0xDC00]), + Wtf8Buf { bytes: b"\xED\xB0\x80".to_vec(), is_known_utf8: false } + ); } #[test] @@ -556,9 +556,10 @@ fn wtf8_encode_wide() { let mut string = Wtf8Buf::from_str("aé "); string.push(CodePoint::from_u32(0xD83D).unwrap()); string.push_char('💩'); - assert_eq!(string.encode_wide().collect::>(), vec![ - 0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9 - ]); + assert_eq!( + string.encode_wide().collect::>(), + vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] + ); } #[test]