From d76cadf7718d809711d4bca9db1ef058c8265192 Mon Sep 17 00:00:00 2001 From: SabrinaJewson Date: Mon, 9 May 2022 17:01:35 +0100 Subject: [PATCH 001/180] Add `task::Waker::noop` --- core/src/task/wake.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index 27af227a1..bf36d3ba2 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -2,6 +2,7 @@ use crate::fmt; use crate::marker::{PhantomData, Unpin}; +use crate::ptr; /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] /// which provides customized wakeup behavior. @@ -277,6 +278,45 @@ impl Waker { Waker { waker } } + /// Creates a new `Waker` that does nothing when `wake` is called. + /// + /// This is mostly useful for writing tests that need a [`Context`] to poll + /// some futures, but are not expecting those futures to wake the waker or + /// do not need to do anything specific if it happens. + /// + /// # Examples + /// + /// ``` + /// #![feature(noop_waker)] + /// + /// use std::future::Future; + /// use std::task; + /// + /// let waker = task::Waker::noop(); + /// let mut cx = task::Context::from_waker(&waker); + /// + /// let mut future = Box::pin(async { 10 }); + /// assert_eq!(future.as_mut().poll(&mut cx), task::Poll::Ready(10)); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "noop_waker", issue = "none")] + pub const fn noop() -> Waker { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| RAW, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); + + Waker { waker: RAW } + } + /// Get a reference to the underlying [`RawWaker`]. #[inline] #[must_use] From 21b233990f27178e4c6f63373dd578dd0147cc3d Mon Sep 17 00:00:00 2001 From: SabrinaJewson Date: Mon, 20 Jun 2022 11:58:10 +0100 Subject: [PATCH 002/180] Add tracking issue for `noop_waker` --- core/src/task/wake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index bf36d3ba2..3543e9655 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -300,7 +300,7 @@ impl Waker { /// ``` #[inline] #[must_use] - #[unstable(feature = "noop_waker", issue = "none")] + #[unstable(feature = "noop_waker", issue = "98286")] pub const fn noop() -> Waker { const VTABLE: RawWakerVTable = RawWakerVTable::new( // Cloning just returns a new no-op raw waker From 1f047c41491a1b6a4ca1fb3c2f318512cdfa9470 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sat, 16 Jul 2022 18:38:03 +0200 Subject: [PATCH 003/180] Parametrize BinaryHeap with Allocator --- alloc/src/collections/binary_heap.rs | 156 +++++++++++++++++++-------- 1 file changed, 111 insertions(+), 45 deletions(-) diff --git a/alloc/src/collections/binary_heap.rs b/alloc/src/collections/binary_heap.rs index 197e7aaac..97f0c1eeb 100644 --- a/alloc/src/collections/binary_heap.rs +++ b/alloc/src/collections/binary_heap.rs @@ -143,12 +143,14 @@ #![allow(missing_docs)] #![stable(feature = "rust1", since = "1.0.0")] +use core::alloc::Allocator; use core::fmt; use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; use core::mem::{self, swap, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr; +use crate::alloc::Global; use crate::collections::TryReserveError; use crate::slice; use crate::vec::{self, AsVecIntoIter, Vec}; @@ -265,8 +267,11 @@ mod tests; /// [peek\_mut]: BinaryHeap::peek_mut #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BinaryHeap")] -pub struct BinaryHeap { - data: Vec, +pub struct BinaryHeap< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + data: Vec, } /// Structure wrapping a mutable reference to the greatest item on a @@ -277,20 +282,24 @@ pub struct BinaryHeap { /// /// [`peek_mut`]: BinaryHeap::peek_mut #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -pub struct PeekMut<'a, T: 'a + Ord> { - heap: &'a mut BinaryHeap, +pub struct PeekMut< + 'a, + T: 'a + Ord, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { + heap: &'a mut BinaryHeap, sift: bool, } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for PeekMut<'_, T> { +impl fmt::Debug for PeekMut<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish() } } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl Drop for PeekMut<'_, T> { +impl Drop for PeekMut<'_, T, A> { fn drop(&mut self) { if self.sift { // SAFETY: PeekMut is only instantiated for non-empty heaps. @@ -300,7 +309,7 @@ impl Drop for PeekMut<'_, T> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl Deref for PeekMut<'_, T> { +impl Deref for PeekMut<'_, T, A> { type Target = T; fn deref(&self) -> &T { debug_assert!(!self.heap.is_empty()); @@ -310,7 +319,7 @@ impl Deref for PeekMut<'_, T> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl DerefMut for PeekMut<'_, T> { +impl DerefMut for PeekMut<'_, T, A> { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); self.sift = true; @@ -330,7 +339,7 @@ impl<'a, T: Ord> PeekMut<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for BinaryHeap { +impl Clone for BinaryHeap { fn clone(&self) -> Self { BinaryHeap { data: self.data.clone() } } @@ -350,13 +359,13 @@ impl Default for BinaryHeap { } #[stable(feature = "binaryheap_debug", since = "1.4.0")] -impl fmt::Debug for BinaryHeap { +impl fmt::Debug for BinaryHeap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } -impl BinaryHeap { +impl BinaryHeap { /// Creates an empty `BinaryHeap` as a max-heap. /// /// # Examples @@ -394,6 +403,52 @@ impl BinaryHeap { pub fn with_capacity(capacity: usize) -> BinaryHeap { BinaryHeap { data: Vec::with_capacity(capacity) } } +} + +impl BinaryHeap { + /// Creates an empty `BinaryHeap` as a max-heap, using `A` as allocator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new_in(System); + /// heap.push(4); + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[must_use] + pub fn new_in(alloc: A) -> BinaryHeap { + BinaryHeap { data: Vec::new_in(alloc) } + } + + /// Creates an empty `BinaryHeap` with at least the specified capacity, using `A` as allocator. + /// + /// 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. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::with_capacity_in(10, System); + /// heap.push(4); + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[must_use] + pub fn with_capacity_in(capacity: usize, alloc: A) -> BinaryHeap { + BinaryHeap { data: Vec::with_capacity_in(capacity, alloc) } + } /// Returns a mutable reference to the greatest item in the binary heap, or /// `None` if it is empty. @@ -425,7 +480,7 @@ impl BinaryHeap { /// If the item is modified then the worst case time complexity is *O*(log(*n*)), /// otherwise it's *O*(1). #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] - pub fn peek_mut(&mut self) -> Option> { + pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) } } @@ -520,7 +575,7 @@ impl BinaryHeap { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] - pub fn into_sorted_vec(mut self) -> Vec { + pub fn into_sorted_vec(mut self) -> Vec { let mut end = self.len(); while end > 1 { end -= 1; @@ -778,7 +833,7 @@ impl BinaryHeap { /// ``` #[inline] #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] - pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> { + pub fn drain_sorted(&mut self) -> DrainSorted<'_, T, A> { DrainSorted { inner: self } } @@ -821,7 +876,7 @@ impl BinaryHeap { } } -impl BinaryHeap { +impl BinaryHeap { /// Returns an iterator visiting all values in the underlying vector, in /// arbitrary order. /// @@ -858,7 +913,7 @@ impl BinaryHeap { /// assert_eq!(heap.into_iter_sorted().take(2).collect::>(), [5, 4]); /// ``` #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] - pub fn into_iter_sorted(self) -> IntoIterSorted { + pub fn into_iter_sorted(self) -> IntoIterSorted { IntoIterSorted { inner: self } } @@ -1124,7 +1179,7 @@ impl BinaryHeap { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] - pub fn into_vec(self) -> Vec { + pub fn into_vec(self) -> Vec { self.into() } @@ -1195,7 +1250,7 @@ impl BinaryHeap { /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain<'_, T> { + pub fn drain(&mut self) -> Drain<'_, T, A> { Drain { iter: self.data.drain(..) } } @@ -1438,12 +1493,15 @@ unsafe impl AsVecIntoIter for IntoIter { #[must_use = "iterators are lazy and do nothing unless consumed"] #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] #[derive(Clone, Debug)] -pub struct IntoIterSorted { - inner: BinaryHeap, +pub struct IntoIterSorted< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: BinaryHeap, } #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] -impl Iterator for IntoIterSorted { +impl Iterator for IntoIterSorted { type Item = T; #[inline] @@ -1459,13 +1517,13 @@ impl Iterator for IntoIterSorted { } #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] -impl ExactSizeIterator for IntoIterSorted {} +impl ExactSizeIterator for IntoIterSorted {} #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] -impl FusedIterator for IntoIterSorted {} +impl FusedIterator for IntoIterSorted {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIterSorted {} +unsafe impl TrustedLen for IntoIterSorted {} /// A draining iterator over the elements of a `BinaryHeap`. /// @@ -1475,12 +1533,16 @@ unsafe impl TrustedLen for IntoIterSorted {} /// [`drain`]: BinaryHeap::drain #[stable(feature = "drain", since = "1.6.0")] #[derive(Debug)] -pub struct Drain<'a, T: 'a> { - iter: vec::Drain<'a, T>, +pub struct Drain< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { + iter: vec::Drain<'a, T, A>, } #[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_, T> { +impl<'a, T, A: Allocator + 'a> Iterator for Drain<'a, T, A> { type Item = T; #[inline] @@ -1495,7 +1557,7 @@ impl Iterator for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_, T> { +impl<'a, T, A: Allocator + 'a> DoubleEndedIterator for Drain<'a, T, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -1503,14 +1565,14 @@ impl DoubleEndedIterator for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, T> { +impl<'a, T, A: Allocator + 'a> ExactSizeIterator for Drain<'a, T, A> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, T> {} +impl<'a, T, A: Allocator + 'a> FusedIterator for Drain<'a, T, A> {} /// A draining iterator over the elements of a `BinaryHeap`. /// @@ -1520,17 +1582,21 @@ impl FusedIterator for Drain<'_, T> {} /// [`drain_sorted`]: BinaryHeap::drain_sorted #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] #[derive(Debug)] -pub struct DrainSorted<'a, T: Ord> { - inner: &'a mut BinaryHeap, +pub struct DrainSorted< + 'a, + T: Ord, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { + inner: &'a mut BinaryHeap, } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl<'a, T: Ord> Drop for DrainSorted<'a, T> { +impl<'a, T: Ord, A: Allocator + 'a> Drop for DrainSorted<'a, T, A> { /// Removes heap elements in heap order. fn drop(&mut self) { - struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>); + struct DropGuard<'r, 'a, T: Ord, A: Allocator + 'a>(&'r mut DrainSorted<'a, T, A>); - impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> { + impl<'r, 'a, T: Ord, A: Allocator + 'a> Drop for DropGuard<'r, 'a, T, A> { fn drop(&mut self) { while self.0.inner.pop().is_some() {} } @@ -1545,7 +1611,7 @@ impl<'a, T: Ord> Drop for DrainSorted<'a, T> { } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl Iterator for DrainSorted<'_, T> { +impl Iterator for DrainSorted<'_, T, A> { type Item = T; #[inline] @@ -1561,20 +1627,20 @@ impl Iterator for DrainSorted<'_, T> { } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl ExactSizeIterator for DrainSorted<'_, T> {} +impl ExactSizeIterator for DrainSorted<'_, T, A> {} #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl FusedIterator for DrainSorted<'_, T> {} +impl FusedIterator for DrainSorted<'_, T, A> {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for DrainSorted<'_, T> {} +unsafe impl TrustedLen for DrainSorted<'_, T, A> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] -impl From> for BinaryHeap { +impl From> for BinaryHeap { /// Converts a `Vec` into a `BinaryHeap`. /// /// This conversion happens in-place, and has *O*(*n*) time complexity. - fn from(vec: Vec) -> BinaryHeap { + fn from(vec: Vec) -> BinaryHeap { let mut heap = BinaryHeap { data: vec }; heap.rebuild(); heap @@ -1598,12 +1664,12 @@ impl From<[T; N]> for BinaryHeap { } #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] -impl From> for Vec { +impl From> for Vec { /// Converts a `BinaryHeap` into a `Vec`. /// /// This conversion requires no data movement or allocation, and has /// constant time complexity. - fn from(heap: BinaryHeap) -> Vec { + fn from(heap: BinaryHeap) -> Vec { heap.data } } @@ -1644,7 +1710,7 @@ impl IntoIterator for BinaryHeap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a BinaryHeap { +impl<'a, T, A: Allocator + 'a> IntoIterator for &'a BinaryHeap { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1691,7 +1757,7 @@ impl SpecExtend> for BinaryHeap { } } -impl BinaryHeap { +impl BinaryHeap { fn extend_desugared>(&mut self, iter: I) { let iterator = iter.into_iter(); let (lower, _) = iterator.size_hint(); From ae6b449818a94cc282a882ed0333ce427b83c5ee Mon Sep 17 00:00:00 2001 From: yanchith Date: Sat, 16 Jul 2022 18:51:15 +0200 Subject: [PATCH 004/180] Mark lifetimes explicitly --- alloc/src/collections/binary_heap.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/alloc/src/collections/binary_heap.rs b/alloc/src/collections/binary_heap.rs index 97f0c1eeb..b166c526c 100644 --- a/alloc/src/collections/binary_heap.rs +++ b/alloc/src/collections/binary_heap.rs @@ -292,14 +292,14 @@ pub struct PeekMut< } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for PeekMut<'_, T, A> { +impl<'a, T: Ord + fmt::Debug, A: Allocator + 'a> fmt::Debug for PeekMut<'a, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish() } } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl Drop for PeekMut<'_, T, A> { +impl<'a, T: Ord, A: Allocator + 'a> Drop for PeekMut<'a, T, A> { fn drop(&mut self) { if self.sift { // SAFETY: PeekMut is only instantiated for non-empty heaps. @@ -309,7 +309,7 @@ impl Drop for PeekMut<'_, T, A> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl Deref for PeekMut<'_, T, A> { +impl<'a, T: Ord, A: Allocator + 'a> Deref for PeekMut<'a, T, A> { type Target = T; fn deref(&self) -> &T { debug_assert!(!self.heap.is_empty()); @@ -319,7 +319,7 @@ impl Deref for PeekMut<'_, T, A> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl DerefMut for PeekMut<'_, T, A> { +impl<'a, T: Ord, A: Allocator + 'a> DerefMut for PeekMut<'a, T, A> { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); self.sift = true; @@ -328,10 +328,10 @@ impl DerefMut for PeekMut<'_, T, A> { } } -impl<'a, T: Ord> PeekMut<'a, T> { +impl<'a, T: Ord, A: Allocator + 'a> PeekMut<'a, T, A> { /// Removes the peeked value from the heap and returns it. #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")] - pub fn pop(mut this: PeekMut<'a, T>) -> T { + pub fn pop(mut this: PeekMut<'a, T, A>) -> T { let value = this.heap.pop().unwrap(); this.sift = false; value @@ -1611,7 +1611,7 @@ impl<'a, T: Ord, A: Allocator + 'a> Drop for DrainSorted<'a, T, A> { } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl Iterator for DrainSorted<'_, T, A> { +impl<'a, T: Ord, A: Allocator + 'a> Iterator for DrainSorted<'a, T, A> { type Item = T; #[inline] @@ -1627,13 +1627,13 @@ impl Iterator for DrainSorted<'_, T, A> { } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl ExactSizeIterator for DrainSorted<'_, T, A> {} +impl<'a, T: Ord, A: Allocator + 'a> ExactSizeIterator for DrainSorted<'a, T, A> {} #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl FusedIterator for DrainSorted<'_, T, A> {} +impl<'a, T: Ord, A: Allocator + 'a> FusedIterator for DrainSorted<'a, T, A> {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for DrainSorted<'_, T, A> {} +unsafe impl<'a, T: Ord, A: Allocator + 'a> TrustedLen for DrainSorted<'a, T, A> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for BinaryHeap { From 12d0d10dac93556f665a0bcb224e7004bc0610b0 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sat, 16 Jul 2022 19:25:50 +0200 Subject: [PATCH 005/180] Parametrize a few more things --- alloc/src/collections/binary_heap.rs | 35 +++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/alloc/src/collections/binary_heap.rs b/alloc/src/collections/binary_heap.rs index b166c526c..c9f0e0864 100644 --- a/alloc/src/collections/binary_heap.rs +++ b/alloc/src/collections/binary_heap.rs @@ -1421,19 +1421,22 @@ impl FusedIterator for Iter<'_, T> {} /// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct IntoIter { - iter: vec::IntoIter, +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: vec::IntoIter, } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter").field(&self.iter.as_slice()).finish() } } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; #[inline] @@ -1448,7 +1451,7 @@ impl Iterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -1456,21 +1459,21 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} // In addition to the SAFETY invariants of the following three unsafe traits // also refer to the vec::in_place_collect module documentation to get an overview #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] -unsafe impl SourceIter for IntoIter { - type Source = IntoIter; +unsafe impl SourceIter for IntoIter { + type Source = IntoIter; #[inline] unsafe fn as_inner(&mut self) -> &mut Self::Source { @@ -1480,9 +1483,9 @@ unsafe impl SourceIter for IntoIter { #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] -unsafe impl InPlaceIterable for IntoIter {} +unsafe impl InPlaceIterable for IntoIter {} -unsafe impl AsVecIntoIter for IntoIter { +unsafe impl AsVecIntoIter for IntoIter { type Item = I; fn as_into_iter(&mut self) -> &mut vec::IntoIter { @@ -1682,9 +1685,9 @@ impl FromIterator for BinaryHeap { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for BinaryHeap { +impl IntoIterator for BinaryHeap { type Item = T; - type IntoIter = IntoIter; + type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each value out of /// the binary heap in arbitrary order. The binary heap cannot be used @@ -1704,7 +1707,7 @@ impl IntoIterator for BinaryHeap { /// println!("{x}"); /// } /// ``` - fn into_iter(self) -> IntoIter { + fn into_iter(self) -> IntoIter { IntoIter { iter: self.data.into_iter() } } } @@ -1720,7 +1723,7 @@ impl<'a, T, A: Allocator + 'a> IntoIterator for &'a BinaryHeap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for BinaryHeap { +impl Extend for BinaryHeap { #[inline] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter); @@ -1737,7 +1740,7 @@ impl Extend for BinaryHeap { } } -impl> SpecExtend for BinaryHeap { +impl> SpecExtend for BinaryHeap { default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter.into_iter()); } From 86e4dfe1a4341f469008910099e7cb30925ed92c Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 21 Jul 2022 22:49:08 -0400 Subject: [PATCH 006/180] document memory orderings of `thread::{park, unpark}` --- std/src/thread/mod.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index d28c7b58b..32453b4d4 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -845,7 +845,7 @@ pub fn sleep(dur: Duration) { /// A call to `park` does not guarantee that the thread will remain parked /// forever, and callers should be prepared for this possibility. /// -/// # park and unpark +/// # `park` and `unpark` /// /// Every thread is equipped with some basic low-level blocking support, via the /// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] @@ -866,14 +866,6 @@ pub fn sleep(dur: Duration) { /// if it wasn't already. Because the token is initially absent, [`unpark`] /// followed by [`park`] will result in the second call returning immediately. /// -/// In other words, each [`Thread`] acts a bit like a spinlock that can be -/// locked and unlocked using `park` and `unpark`. -/// -/// Notice that being unblocked does not imply any synchronization with someone -/// that unparked this thread, it could also be spurious. -/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and -/// [`unpark`] return immediately without doing anything. -/// /// The API is typically used by acquiring a handle to the current thread, /// placing that handle in a shared data structure so that other threads can /// find it, and then `park`ing in a loop. When some desired condition is met, another @@ -887,6 +879,23 @@ pub fn sleep(dur: Duration) { /// /// * It can be implemented very efficiently on many platforms. /// +/// # Memory Orderings +/// +/// Calls to `park` _synchronize-with_ calls to `unpark`, 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. +/// +/// In atomic ordering terms, `unpark` performs a `Release` operation and `park` +/// performs the corresponding `Acquire` operation. Calls to `unpark` for the same +/// thread form a [release sequence]. +/// +/// Notice that being unblocked does not imply any synchronization with someone that +/// unparked this thread, it could also be spurious. For example, it would be a valid, +/// but inefficient, implementation to make both park and unpark return immediately +/// without doing anything. +/// /// # Examples /// /// ``` @@ -926,6 +935,7 @@ pub fn sleep(dur: Duration) { /// /// [`unpark`]: Thread::unpark /// [`thread::park_timeout`]: park_timeout +/// [release sequence]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release_sequence #[stable(feature = "rust1", since = "1.0.0")] pub fn park() { // SAFETY: park_timeout is called on the parker owned by this thread. From ff83dddb5404f5b24b196a864f9c22ef5612ac11 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Wed, 5 Oct 2022 16:33:04 -0400 Subject: [PATCH 007/180] tidy Co-authored-by: yvt --- std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 32453b4d4..afa4e2fb1 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -880,7 +880,7 @@ pub fn sleep(dur: Duration) { /// * It can be implemented very efficiently on many platforms. /// /// # Memory Orderings -/// +/// /// Calls to `park` _synchronize-with_ calls to `unpark`, 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` @@ -890,7 +890,7 @@ pub fn sleep(dur: Duration) { /// In atomic ordering terms, `unpark` performs a `Release` operation and `park` /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same /// thread form a [release sequence]. -/// +/// /// Notice that being unblocked does not imply any synchronization with someone that /// unparked this thread, it could also be spurious. For example, it would be a valid, /// but inefficient, implementation to make both park and unpark return immediately From 4193bd76143549069a72a77157d2394b9e95ab56 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sun, 1 Jan 2023 14:34:22 -0500 Subject: [PATCH 008/180] improve wording of `thread::park` docs --- std/src/thread/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index afa4e2fb1..07662e90c 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -891,10 +891,9 @@ pub fn sleep(dur: Duration) { /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same /// thread form a [release sequence]. /// -/// Notice that being unblocked does not imply any synchronization with someone that -/// unparked this thread, it could also be spurious. For example, it would be a valid, -/// but inefficient, implementation to make both park and unpark return immediately -/// without doing anything. +/// Note that being unblocked does not imply synchronization with a call to `unpark`, +/// the wakeup could also be spurious. For example, a valid, but inefficient, +/// implementation could have `park` and `unpark` return immediately without doing anything. /// /// # Examples /// From 3fa93b1d43872c3f1654725c2868a6016888fe85 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 22 Jan 2023 15:46:53 +0100 Subject: [PATCH 009/180] =?UTF-8?q?io:=20soften=20=E2=80=98at=20most=20one?= =?UTF-8?q?=20write=20attempt=E2=80=99=20requirement=20in=20io::Write::wri?= =?UTF-8?q?te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, documentation of std::io::Write::write indicates that call to it ‘represents at most one attempt to write to any wrapped object’. It seems that such wording was put there to contrast it with pre-1.0 interface which attempted to write all the data (it has since been changed in [RFC 517]). However, the requirement puts unnecessary constraints and may complicate adaptors which perform non-trivial transformations on the data. For example, they may maintain an internal buffer which needs to be written out before the write method accepts more data. It might be natural to code the method such that it flushes the buffer and then grabs another chunk of user data. With the current wording in the documentation, the adaptor would be forced to return Ok(0). This commit softens the wording such that implementations can choose code structure which makes most sense for their particular use case. While at it, elaborate on the meaning of `Ok(0)` return pointing out that the write_all methods interprets it as an error. [RFC 517]: https://rust-lang.github.io/rfcs/0517-io-os-reform.html --- std/src/io/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index de528e853..aa34d4be1 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1385,17 +1385,18 @@ pub trait Write { /// /// This function will attempt to write the entire contents of `buf`, but /// the entire write might not succeed, or the write may also generate an - /// error. A call to `write` represents *at most one* attempt to write to + /// error. Typically, a call to `write` represents one attempt to write to /// any wrapped object. /// /// Calls to `write` are not guaranteed to block waiting for data to be /// written, and a write which would otherwise block can be indicated through /// an [`Err`] variant. /// - /// If the return value is [`Ok(n)`] then it must be guaranteed that - /// `n <= buf.len()`. A return value of `0` typically means that the - /// underlying object is no longer able to accept bytes and will likely not - /// be able to in the future as well, or that the buffer provided is empty. + /// If the return value is [`Ok(n)`] then it must be guaranteed that `n <= + /// buf.len()`. Unless `input` is empty, this function shouldn’t return `0` + /// since caller may interpret that as an error (the default implementation + /// of [`Write::write_all`] does exactly that). To indicate lack of space + /// function should return [`ErrorKind::StorageFull`] error instead. /// /// # Errors /// From dc8923548a10c68514000741f33f45c557a3a9cf Mon Sep 17 00:00:00 2001 From: Stiopa Koltsov Date: Fri, 3 Feb 2023 00:13:50 +0000 Subject: [PATCH 010/180] Specify behavior of HashSet::insert `HashSet::insert` does not replace the value with equal value. Fixes #107581. --- std/src/collections/hash/set.rs | 4 +++- std/src/collections/hash/set/tests.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index b59f89d32..ac7acf999 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -875,7 +875,9 @@ where /// Returns whether the value was newly inserted. That is: /// /// - If the set did not previously contain this value, `true` is returned. - /// - If the set already contained this value, `false` is returned. + /// - If the set already contained this value, `false` is returned, + /// and the set is not modified: original value is not replaced, + /// and the value passed as argument is dropped. /// /// # Examples /// diff --git a/std/src/collections/hash/set/tests.rs b/std/src/collections/hash/set/tests.rs index 941a0450c..022ca68ff 100644 --- a/std/src/collections/hash/set/tests.rs +++ b/std/src/collections/hash/set/tests.rs @@ -3,6 +3,7 @@ use super::HashSet; use crate::panic::{catch_unwind, AssertUnwindSafe}; use crate::sync::atomic::{AtomicU32, Ordering}; +use crate::sync::Arc; #[test] fn test_zero_capacities() { @@ -502,3 +503,22 @@ fn const_with_hasher() { const X: HashSet<(), ()> = HashSet::with_hasher(()); assert_eq!(X.len(), 0); } + +#[test] +fn test_insert_does_not_overwrite_the_value() { + let first_value = Arc::new(17); + let second_value = Arc::new(17); + + let mut set = HashSet::new(); + let inserted = set.insert(first_value.clone()); + assert!(inserted); + + let inserted = set.insert(second_value); + assert!(!inserted); + + assert!( + Arc::ptr_eq(set.iter().next().unwrap(), &first_value), + "Insert must not overwrite the value, so the contained value pointer \ + must be the same as first value pointer we inserted" + ); +} From bee1b0aea111cfbaea825ff04424b72d5015ecb2 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 3 Feb 2023 18:38:51 +0100 Subject: [PATCH 011/180] Update library/std/src/io/mod.rs --- std/src/io/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index aa34d4be1..d4f8c3123 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1392,10 +1392,10 @@ pub trait Write { /// written, and a write which would otherwise block can be indicated through /// an [`Err`] variant. /// - /// If the return value is [`Ok(n)`] then it must be guaranteed that `n <= - /// buf.len()`. Unless `input` is empty, this function shouldn’t return `0` - /// since caller may interpret that as an error (the default implementation - /// of [`Write::write_all`] does exactly that). To indicate lack of space + /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. + /// If the return value is `Ok(n)` it must hold than `n <= buf.len()`. + /// Unless `input` is empty, this function shouldn’t return `Ok(0)` since + /// caller may interpret that as an error. To indicate lack of space /// function should return [`ErrorKind::StorageFull`] error instead. /// /// # Errors From b2d307cfc842ccdb125e10c4c7aff79f15e60f4f Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Wed, 1 Mar 2023 00:48:22 +0100 Subject: [PATCH 012/180] Update library/std/src/io/mod.rs Co-authored-by: Andrew Gallant --- std/src/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index d4f8c3123..8e8fa147c 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1394,9 +1394,9 @@ pub trait Write { /// /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. /// If the return value is `Ok(n)` it must hold than `n <= buf.len()`. - /// Unless `input` is empty, this function shouldn’t return `Ok(0)` since - /// caller may interpret that as an error. To indicate lack of space - /// function should return [`ErrorKind::StorageFull`] error instead. + /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the + /// caller may interpret that as an error. To indicate lack of space, + /// implementors should return [`ErrorKind::StorageFull`] error instead. /// /// # Errors /// From 02d39781c5b424be08249fdc0d63d013c99da141 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 3 Mar 2023 03:16:56 +0100 Subject: [PATCH 013/180] Update library/std/src/io/mod.rs Co-authored-by: Jacob Lifshay --- std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 8e8fa147c..b2fcb9660 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1393,7 +1393,7 @@ pub trait Write { /// an [`Err`] variant. /// /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. - /// If the return value is `Ok(n)` it must hold than `n <= buf.len()`. + /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the /// caller may interpret that as an error. To indicate lack of space, /// implementors should return [`ErrorKind::StorageFull`] error instead. From ef5cd79cb475950fc39d4c8534c6c3766d995533 Mon Sep 17 00:00:00 2001 From: Dante Broggi <34220985+Dante-Broggi@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:52:32 -0400 Subject: [PATCH 014/180] add `#[doc(alias="flatmap")]` to `Option::and_then` I keep forgetting that rust calls this `and_then` and trying to search for `flatmap`. `and_then`'s docs even mention "Some languages call this operation flatmap", but it doesn't show up as a result in the search at `https://doc.rust-lang.org/std/?search=flatmap` --- core/src/option.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/option.rs b/core/src/option.rs index 0f2475a8b..b5ea89162 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -1464,6 +1464,7 @@ impl Option { /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0)); /// assert_eq!(item_2_0, None); /// ``` + #[doc(alias = "flatmap")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] From 814423ff9299b11b5403614233dc6af225b1d228 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Mar 2023 21:22:36 -0500 Subject: [PATCH 015/180] Allow access to `OsStr` bytes `OsStr` has historically kept its implementation details private out of concern for locking us into a specific encoding on Windows. This is an alternative to #95290 which proposed specifying the encoding on Windows. Instead, this only specifies that for cross-platform code, `OsStr`'s encoding is a superset of UTF-8 and defines rules for safely interacting with it At minimum, this can greatly simplify the `os_str_bytes` crate and every arg parser that interacts with `OsStr` directly (which is most of those that support invalid UTF-8). --- std/src/ffi/mod.rs | 8 +++++ std/src/ffi/os_str.rs | 56 +++++++++++++++++++++++++++++++- std/src/sys/unix/os_str.rs | 9 +++-- std/src/sys/unix/os_str/tests.rs | 9 +++-- std/src/sys/windows/os_str.rs | 10 ++++++ std/src/sys_common/wtf8.rs | 8 ++++- 6 files changed, 91 insertions(+), 9 deletions(-) diff --git a/std/src/ffi/mod.rs b/std/src/ffi/mod.rs index d987bf69b..3ddb87487 100644 --- a/std/src/ffi/mod.rs +++ b/std/src/ffi/mod.rs @@ -127,6 +127,14 @@ //! trait, which provides a [`from_wide`] method to convert a native Windows //! string (without the terminating nul character) to an [`OsString`]. //! +//! ## On all platforms +//! +//! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of +//! UTF-8; see [`OsString`] for more details on its encoding on different platforms. +//! +//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_os_str_bytes`] and +//! [`OsStr::from_os_str_bytes_unchecked`]. +//! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point //! [`env::set_var()`]: crate::env::set_var "env::set_var" diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 5c0541d3c..25ab21966 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -667,6 +667,45 @@ impl OsStr { s.as_ref() } + /// Converts a slice of bytes to an OS string slice without checking that the string contains + /// valid `OsStr`-encoded data. + /// + /// See the [module's toplevel documentation about conversions][conversions] for safe, + /// cross-platform [conversions] from/to native representations. + /// + /// # Safety + /// + /// `OsStr`'s encoding is an unspecified superset of UTF-8 and callers must + /// pass in bytes that originated as a mixture of validated UTF-8 and bytes from + /// [`OsStr::as_os_str_bytes`] from within the same rust version built for the same target + /// platform. The bytes from `OsStr::as_os_str_bytes` may be split either + /// immediately before or immediately after some valid non-empty UTF-8 substring + /// + /// # Example + /// + /// ``` + /// #![feature(os_str_bytes)] + /// + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("Mary had a little lamb"); + /// let bytes = os_str.as_os_str_bytes(); + /// let words = bytes.split(|b| *b == b' '); + /// let words: Vec<&OsStr> = words.map(|word| { + /// // SAFETY: + /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes` + /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring + /// unsafe { OsStr::from_os_str_bytes_unchecked(word) } + /// }).collect(); + /// ``` + /// + /// [conversions]: super#conversions + #[inline] + #[unstable(feature = "os_str_bytes", issue = "111544")] + pub fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { + Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes)) + } + #[inline] fn from_inner(inner: &Slice) -> &OsStr { // SAFETY: OsStr is just a wrapper of Slice, @@ -837,13 +876,28 @@ impl OsStr { OsString { inner: Buf::from_box(boxed) } } + /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS + /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function. + /// + /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should + /// be treated as opaque and only comparable within the same rust version built for the same + /// target platform. See [`OsString`] for more encoding details and [`std::ffi`] for + /// platform-specific, specified conversions. + /// + /// [`std::ffi`]: crate::ffi + #[inline] + #[unstable(feature = "os_str_bytes", issue = "111544")] + pub fn as_os_str_bytes(&self) -> &[u8] { + self.inner.as_os_str_bytes() + } + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is not externally public, to avoid /// revealing the internal, platform-specific encodings. #[inline] pub(crate) fn bytes(&self) -> &[u8] { - unsafe { &*(&self.inner as *const _ as *const [u8]) } + self.as_os_str_bytes() } /// Converts this string to its ASCII lower case equivalent in-place. diff --git a/std/src/sys/unix/os_str.rs b/std/src/sys/unix/os_str.rs index 488217f39..142fcb9ed 100644 --- a/std/src/sys/unix/os_str.rs +++ b/std/src/sys/unix/os_str.rs @@ -193,13 +193,18 @@ impl Buf { impl Slice { #[inline] - fn from_u8_slice(s: &[u8]) -> &Slice { + pub fn as_os_str_bytes(&self) -> &[u8] { + &self.inner + } + + #[inline] + pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { unsafe { mem::transmute(s) } } #[inline] pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) + unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) } } pub fn to_str(&self) -> Option<&str> { diff --git a/std/src/sys/unix/os_str/tests.rs b/std/src/sys/unix/os_str/tests.rs index 22ba0c923..91bc0e61a 100644 --- a/std/src/sys/unix/os_str/tests.rs +++ b/std/src/sys/unix/os_str/tests.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn slice_debug_output() { - let input = Slice::from_u8_slice(b"\xF0hello,\tworld"); + let input = unsafe { Slice::from_os_str_bytes_unchecked(b"\xF0hello,\tworld") }; let expected = r#""\xF0hello,\tworld""#; let output = format!("{input:?}"); @@ -11,8 +11,7 @@ fn slice_debug_output() { #[test] fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(), - ); + assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe { + Slice::from_os_str_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + },); } diff --git a/std/src/sys/windows/os_str.rs b/std/src/sys/windows/os_str.rs index 2f2b0e56e..611f0d040 100644 --- a/std/src/sys/windows/os_str.rs +++ b/std/src/sys/windows/os_str.rs @@ -151,6 +151,16 @@ impl Buf { } impl Slice { + #[inline] + pub fn as_os_str_bytes(&self) -> &[u8] { + self.inner.as_bytes() + } + + #[inline] + pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { + mem::transmute(Wtf8::from_bytes_unchecked(s)) + } + #[inline] pub fn from_str(s: &str) -> &Slice { unsafe { mem::transmute(Wtf8::from_str(s)) } diff --git a/std/src/sys_common/wtf8.rs b/std/src/sys_common/wtf8.rs index ff96c35fb..31bb0ad25 100644 --- a/std/src/sys_common/wtf8.rs +++ b/std/src/sys_common/wtf8.rs @@ -570,7 +570,7 @@ impl Wtf8 { /// Since the byte slice is not checked for valid WTF-8, this functions is /// marked unsafe. #[inline] - unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { mem::transmute(value) } @@ -614,6 +614,12 @@ impl Wtf8 { Wtf8CodePoints { bytes: self.bytes.iter() } } + /// Access raw bytes of WTF-8 data + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + /// Tries to convert the string to UTF-8 and return a `&str` slice. /// /// Returns `None` if the string contains surrogates. From b997221881b98a5704d5b608281f7cc96355cff6 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 11 Apr 2023 13:20:41 -0400 Subject: [PATCH 016/180] clarify wording around spurious wakeups from `thread::park` --- std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 07662e90c..0f8b9c766 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -891,8 +891,8 @@ pub fn sleep(dur: Duration) { /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same /// thread form a [release sequence]. /// -/// Note that being unblocked does not imply synchronization with a call to `unpark`, -/// the wakeup could also be spurious. For example, a valid, but inefficient, +/// Note that being unblocked does not imply a call was made to `unpark`, because +/// wakeups can also be spurious. For example, a valid, but inefficient, /// implementation could have `park` and `unpark` return immediately without doing anything. /// /// # Examples From a00a89f74720c6d1d907cc96ca6f1608d5f3a752 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Wed, 4 Jan 2023 14:16:55 +0100 Subject: [PATCH 017/180] Make `{Arc,Rc,Weak}::ptr_eq` ignore pointer metadata --- alloc/src/rc.rs | 10 +++++----- alloc/src/sync.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index cf93a4049..3bfa1526a 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -1169,7 +1169,7 @@ impl Rc { #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. /// /// # Examples /// @@ -1184,7 +1184,7 @@ impl Rc { /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.as_ptr() as *const () == other.ptr.as_ptr() as *const () } } @@ -2468,8 +2468,8 @@ impl Weak { } /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). See [that - /// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. /// /// # Notes /// @@ -2510,7 +2510,7 @@ impl Weak { #[must_use] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + ptr::eq(self.ptr.as_ptr() as *const (), other.ptr.as_ptr() as *const ()) } } diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index 5bfe537bc..ef2148e9e 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -1263,7 +1263,7 @@ impl Arc { } /// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. /// /// # Examples /// @@ -1283,7 +1283,7 @@ impl Arc { #[must_use] #[stable(feature = "ptr_eq", since = "1.17.0")] pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.as_ptr() as *const () == other.ptr.as_ptr() as *const () } } @@ -2243,8 +2243,8 @@ impl Weak { } /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). See [that - /// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. /// /// # Notes /// @@ -2287,7 +2287,7 @@ impl Weak { #[must_use] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + ptr::eq(self.ptr.as_ptr() as *const (), other.ptr.as_ptr() as *const ()) } } From 1368974bd5bfafd889121a117e41b7dfbfac6d3f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 1 May 2023 17:17:05 +0000 Subject: [PATCH 018/180] Relax implicit `R: Sized` bound on `BufReader` --- std/src/io/buffered/bufreader.rs | 27 +++++++++++++++------------ std/src/io/mod.rs | 2 +- std/src/sys/unix/kernel_copy.rs | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/std/src/io/buffered/bufreader.rs b/std/src/io/buffered/bufreader.rs index 4f339a18a..3edf9d747 100644 --- a/std/src/io/buffered/bufreader.rs +++ b/std/src/io/buffered/bufreader.rs @@ -47,9 +47,9 @@ use buffer::Buffer; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufReader { - inner: R, +pub struct BufReader { buf: Buffer, + inner: R, } impl BufReader { @@ -95,7 +95,7 @@ impl BufReader { } } -impl BufReader { +impl BufReader { /// Gets a reference to the underlying reader. /// /// It is inadvisable to directly read from the underlying reader. @@ -213,7 +213,10 @@ impl BufReader { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> R { + pub fn into_inner(self) -> R + where + R: Sized, + { self.inner } @@ -226,13 +229,13 @@ impl BufReader { // This is only used by a test which asserts that the initialization-tracking is correct. #[cfg(test)] -impl BufReader { +impl BufReader { pub fn initialized(&self) -> usize { self.buf.initialized() } } -impl BufReader { +impl BufReader { /// Seeks relative to the current position. If the new position lies within the buffer, /// the buffer will not be flushed, allowing for more efficient seeks. /// This method does not return the location of the underlying reader, so the caller @@ -257,7 +260,7 @@ impl BufReader { } #[stable(feature = "rust1", since = "1.0.0")] -impl Read for BufReader { +impl Read for BufReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer @@ -371,7 +374,7 @@ impl Read for BufReader { } #[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for BufReader { +impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { self.buf.fill_buf(&mut self.inner) } @@ -384,11 +387,11 @@ impl BufRead for BufReader { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for BufReader where - R: fmt::Debug, + R: ?Sized + fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BufReader") - .field("reader", &self.inner) + .field("reader", &&self.inner) .field( "buffer", &format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()), @@ -398,7 +401,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufReader { +impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// /// The position used for seeking with [SeekFrom::Current]\(_) is the @@ -491,7 +494,7 @@ impl Seek for BufReader { } } -impl SizeHint for BufReader { +impl SizeHint for BufReader { #[inline] fn lower_bound(&self) -> usize { SizeHint::lower_bound(self.get_ref()) + self.buffer().len() diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 9e09ce337..bb329dc24 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -2753,7 +2753,7 @@ trait SizeHint { } } -impl SizeHint for T { +impl SizeHint for T { #[inline] default fn lower_bound(&self) -> usize { 0 diff --git a/std/src/sys/unix/kernel_copy.rs b/std/src/sys/unix/kernel_copy.rs index 16c8e0c0e..81b081e00 100644 --- a/std/src/sys/unix/kernel_copy.rs +++ b/std/src/sys/unix/kernel_copy.rs @@ -466,7 +466,7 @@ impl CopyRead for Take { } } -impl CopyRead for BufReader { +impl CopyRead for BufReader { fn drain_to(&mut self, writer: &mut W, outer_limit: u64) -> Result { let buf = self.buffer(); let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))]; From afa75997ae0812b7dc5b2eaa28738290c420ea5c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 1 May 2023 17:52:28 +0000 Subject: [PATCH 019/180] Relax implicit `W: Sized` bound on `BufWriter` --- std/src/io/buffered/bufwriter.rs | 138 ++++++++++++++++--------------- std/src/io/copy.rs | 2 +- std/src/sys/unix/kernel_copy.rs | 2 +- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/std/src/io/buffered/bufwriter.rs b/std/src/io/buffered/bufwriter.rs index 14c455d4f..0e2450655 100644 --- a/std/src/io/buffered/bufwriter.rs +++ b/std/src/io/buffered/bufwriter.rs @@ -67,8 +67,7 @@ use crate::ptr; /// [`TcpStream`]: crate::net::TcpStream /// [`flush`]: BufWriter::flush #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter { - inner: W, +pub struct BufWriter { // The buffer. Avoid using this like a normal `Vec` in common code paths. // That is, don't use `buf.push`, `buf.extend_from_slice`, or any other // methods that require bounds checking or the like. This makes an enormous @@ -78,6 +77,7 @@ pub struct BufWriter { // write the buffered data a second time in BufWriter's destructor. This // flag tells the Drop impl if it should skip the flush. panicked: bool, + inner: W, } impl BufWriter { @@ -115,6 +115,69 @@ impl BufWriter { BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false } } + /// Unwraps this `BufWriter`, returning the underlying writer. + /// + /// The buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(mut self) -> Result>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError::new(self, e)), + Ok(()) => Ok(self.into_parts().0), + } + } + + /// Disassembles this `BufWriter`, returning the underlying writer, and any buffered but + /// unwritten data. + /// + /// If the underlying writer panicked, it is not known what portion of the data was written. + /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer + /// contents can still be recovered). + /// + /// `into_parts` makes no attempt to flush data and cannot fail. + /// + /// # Examples + /// + /// ``` + /// use std::io::{BufWriter, Write}; + /// + /// let mut buffer = [0u8; 10]; + /// let mut stream = BufWriter::new(buffer.as_mut()); + /// write!(stream, "too much data").unwrap(); + /// stream.flush().expect_err("it doesn't fit"); + /// let (recovered_writer, buffered_data) = stream.into_parts(); + /// assert_eq!(recovered_writer.len(), 0); + /// assert_eq!(&buffered_data.unwrap(), b"ata"); + /// ``` + #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] + pub fn into_parts(mut self) -> (W, Result, WriterPanicked>) { + let buf = mem::take(&mut self.buf); + let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; + + // SAFETY: forget(self) prevents double dropping inner + let inner = unsafe { ptr::read(&self.inner) }; + mem::forget(self); + + (inner, buf) + } +} + +impl BufWriter { /// Send data in our local buffer into the inner writer, looping as /// necessary until either it's all been sent or an error occurs. /// @@ -284,67 +347,6 @@ impl BufWriter { self.buf.capacity() } - /// Unwraps this `BufWriter`, returning the underlying writer. - /// - /// The buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // unwrap the TcpStream and flush the buffer - /// let stream = buffer.into_inner().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(mut self) -> Result>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError::new(self, e)), - Ok(()) => Ok(self.into_parts().0), - } - } - - /// Disassembles this `BufWriter`, returning the underlying writer, and any buffered but - /// unwritten data. - /// - /// If the underlying writer panicked, it is not known what portion of the data was written. - /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer - /// contents can still be recovered). - /// - /// `into_parts` makes no attempt to flush data and cannot fail. - /// - /// # Examples - /// - /// ``` - /// use std::io::{BufWriter, Write}; - /// - /// let mut buffer = [0u8; 10]; - /// let mut stream = BufWriter::new(buffer.as_mut()); - /// write!(stream, "too much data").unwrap(); - /// stream.flush().expect_err("it doesn't fit"); - /// let (recovered_writer, buffered_data) = stream.into_parts(); - /// assert_eq!(recovered_writer.len(), 0); - /// assert_eq!(&buffered_data.unwrap(), b"ata"); - /// ``` - #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] - pub fn into_parts(mut self) -> (W, Result, WriterPanicked>) { - let buf = mem::take(&mut self.buf); - let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; - - // SAFETY: forget(self) prevents double dropping inner - let inner = unsafe { ptr::read(&self.inner) }; - mem::forget(self); - - (inner, buf) - } - // Ensure this function does not get inlined into `write`, so that it // remains inlineable and its common path remains as short as possible. // If this function ends up being called frequently relative to `write`, @@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked { } #[stable(feature = "rust1", since = "1.0.0")] -impl Write for BufWriter { +impl Write for BufWriter { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { // Use < instead of <= to avoid a needless trip through the buffer in some cases. @@ -640,20 +642,20 @@ impl Write for BufWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufWriter +impl fmt::Debug for BufWriter where W: fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BufWriter") - .field("writer", &self.inner) + .field("writer", &&self.inner) .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) .finish() } } #[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufWriter { +impl Seek for BufWriter { /// Seek to the offset, in bytes, in the underlying writer. /// /// Seeking always writes out the internal buffer before seeking. @@ -664,7 +666,7 @@ impl Seek for BufWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for BufWriter { +impl Drop for BufWriter { fn drop(&mut self) { if !self.panicked { // dtors should not panic, so we ignore a failed flush diff --git a/std/src/io/copy.rs b/std/src/io/copy.rs index 38b98afff..7c2a77277 100644 --- a/std/src/io/copy.rs +++ b/std/src/io/copy.rs @@ -86,7 +86,7 @@ impl BufferedCopySpec for W { } } -impl BufferedCopySpec for BufWriter { +impl BufferedCopySpec for BufWriter { fn copy_to(reader: &mut R, writer: &mut Self) -> Result { if writer.capacity() < DEFAULT_BUF_SIZE { return stack_buffer_copy(reader, writer); diff --git a/std/src/sys/unix/kernel_copy.rs b/std/src/sys/unix/kernel_copy.rs index 81b081e00..7d49bbdcb 100644 --- a/std/src/sys/unix/kernel_copy.rs +++ b/std/src/sys/unix/kernel_copy.rs @@ -495,7 +495,7 @@ impl CopyRead for BufReader { } } -impl CopyWrite for BufWriter { +impl CopyWrite for BufWriter { fn properties(&self) -> CopyParams { self.get_ref().properties() } From f0c9fbc0f51198448c2bb1845e7cc7210c88ad8c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 1 May 2023 18:01:04 +0000 Subject: [PATCH 020/180] Relax implicit `W: Sized` bound on `LineWriter` --- std/src/io/buffered/linewriter.rs | 50 ++++++++++++++------------- std/src/io/buffered/linewritershim.rs | 6 ++-- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/std/src/io/buffered/linewriter.rs b/std/src/io/buffered/linewriter.rs index a26a4ab33..3d4ae7041 100644 --- a/std/src/io/buffered/linewriter.rs +++ b/std/src/io/buffered/linewriter.rs @@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter { +pub struct LineWriter { inner: BufWriter, } @@ -109,27 +109,6 @@ impl LineWriter { LineWriter { inner: BufWriter::with_capacity(capacity, inner) } } - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// - /// let reference = file.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.get_ref() - } - /// Gets a mutable reference to the underlying writer. /// /// Caution must be taken when calling methods on the mutable reference @@ -184,8 +163,31 @@ impl LineWriter { } } +impl LineWriter { + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } +} + #[stable(feature = "rust1", since = "1.0.0")] -impl Write for LineWriter { +impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { LineWriterShim::new(&mut self.inner).write(buf) } @@ -216,7 +218,7 @@ impl Write for LineWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineWriter +impl fmt::Debug for LineWriter where W: fmt::Debug, { diff --git a/std/src/io/buffered/linewritershim.rs b/std/src/io/buffered/linewritershim.rs index 0175d2693..f2a55da05 100644 --- a/std/src/io/buffered/linewritershim.rs +++ b/std/src/io/buffered/linewritershim.rs @@ -11,11 +11,11 @@ use crate::sys_common::memchr; /// `BufWriters` to be temporarily given line-buffering logic; this is what /// enables Stdout to be alternately in line-buffered or block-buffered mode. #[derive(Debug)] -pub struct LineWriterShim<'a, W: Write> { +pub struct LineWriterShim<'a, W: ?Sized + Write> { buffer: &'a mut BufWriter, } -impl<'a, W: Write> LineWriterShim<'a, W> { +impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { pub fn new(buffer: &'a mut BufWriter) -> Self { Self { buffer } } @@ -49,7 +49,7 @@ impl<'a, W: Write> LineWriterShim<'a, W> { } } -impl<'a, W: Write> Write for LineWriterShim<'a, W> { +impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { /// Write some data into this BufReader with line buffering. This means /// that, if any newlines are present in the data, the data up to the last /// newline is sent directly to the underlying writer, and data after it From 0c3c7527652f0892365f7ea64a14790e9f223810 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Sat, 13 May 2023 18:47:14 +0200 Subject: [PATCH 021/180] refactor: Remove redundant, private OsStr::bytes --- std/src/ffi/os_str.rs | 27 ++++++++-------------- std/src/path.rs | 16 ++++++------- std/src/sys/common/small_c_string.rs | 2 +- std/src/sys/common/tests.rs | 4 ++-- std/src/sys/unix/path.rs | 2 +- std/src/sys/unix/process/process_common.rs | 4 ++-- std/src/sys/windows/args.rs | 6 +++-- std/src/sys/windows/path.rs | 24 +++++++++---------- std/src/sys/windows/process.rs | 4 ++-- 9 files changed, 41 insertions(+), 48 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 25ab21966..90cbd57a9 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -702,7 +702,7 @@ impl OsStr { /// [conversions]: super#conversions #[inline] #[unstable(feature = "os_str_bytes", issue = "111544")] - pub fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { + pub unsafe fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes)) } @@ -891,15 +891,6 @@ impl OsStr { self.inner.as_os_str_bytes() } - /// Gets the underlying byte representation. - /// - /// Note: it is *crucial* that this API is not externally public, to avoid - /// revealing the internal, platform-specific encodings. - #[inline] - pub(crate) fn bytes(&self) -> &[u8] { - self.as_os_str_bytes() - } - /// Converts this string to its ASCII lower case equivalent in-place. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', @@ -1185,7 +1176,7 @@ impl Default for &OsStr { impl PartialEq for OsStr { #[inline] fn eq(&self, other: &OsStr) -> bool { - self.bytes().eq(other.bytes()) + self.as_os_str_bytes().eq(other.as_os_str_bytes()) } } @@ -1212,23 +1203,23 @@ impl Eq for OsStr {} impl PartialOrd for OsStr { #[inline] fn partial_cmp(&self, other: &OsStr) -> Option { - self.bytes().partial_cmp(other.bytes()) + self.as_os_str_bytes().partial_cmp(other.as_os_str_bytes()) } #[inline] fn lt(&self, other: &OsStr) -> bool { - self.bytes().lt(other.bytes()) + self.as_os_str_bytes().lt(other.as_os_str_bytes()) } #[inline] fn le(&self, other: &OsStr) -> bool { - self.bytes().le(other.bytes()) + self.as_os_str_bytes().le(other.as_os_str_bytes()) } #[inline] fn gt(&self, other: &OsStr) -> bool { - self.bytes().gt(other.bytes()) + self.as_os_str_bytes().gt(other.as_os_str_bytes()) } #[inline] fn ge(&self, other: &OsStr) -> bool { - self.bytes().ge(other.bytes()) + self.as_os_str_bytes().ge(other.as_os_str_bytes()) } } @@ -1247,7 +1238,7 @@ impl PartialOrd for OsStr { impl Ord for OsStr { #[inline] fn cmp(&self, other: &OsStr) -> cmp::Ordering { - self.bytes().cmp(other.bytes()) + self.as_os_str_bytes().cmp(other.as_os_str_bytes()) } } @@ -1297,7 +1288,7 @@ impl_cmp!(Cow<'a, OsStr>, OsString); impl Hash for OsStr { #[inline] fn hash(&self, state: &mut H) { - self.bytes().hash(state) + self.as_os_str_bytes().hash(state) } } diff --git a/std/src/path.rs b/std/src/path.rs index febdeb514..6f770d4c9 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -193,7 +193,7 @@ impl<'a> Prefix<'a> { fn len(&self) -> usize { use self::Prefix::*; fn os_str_len(s: &OsStr) -> usize { - s.bytes().len() + s.as_os_str_bytes().len() } match *self { Verbatim(x) => 4 + os_str_len(x), @@ -330,7 +330,7 @@ fn has_physical_root(s: &[u8], prefix: Option>) -> bool { // basic workhorse for splitting stem and extension fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - if file.bytes() == b".." { + if file.as_os_str_bytes() == b".." { return (Some(file), None); } @@ -338,7 +338,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { // and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = file.bytes().rsplitn(2, |b| *b == b'.'); + let mut iter = file.as_os_str_bytes().rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") { @@ -349,7 +349,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { } fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { - let slice = file.bytes(); + let slice = file.as_os_str_bytes(); if slice == b".." { return (file, None); } @@ -1481,17 +1481,17 @@ impl PathBuf { fn _set_extension(&mut self, extension: &OsStr) -> bool { let file_stem = match self.file_stem() { None => return false, - Some(f) => f.bytes(), + Some(f) => f.as_os_str_bytes(), }; // truncate until right after the file stem let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr(); - let start = self.inner.bytes().as_ptr().addr(); + let start = self.inner.as_os_str_bytes().as_ptr().addr(); let v = self.as_mut_vec(); v.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension.bytes(); + let new = extension.as_os_str_bytes(); if !new.is_empty() { v.reserve_exact(new.len() + 1); v.push(b'.'); @@ -2015,7 +2015,7 @@ impl Path { } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { - self.inner.bytes() + self.inner.as_os_str_bytes() } /// Directly wraps a string slice as a `Path` slice. diff --git a/std/src/sys/common/small_c_string.rs b/std/src/sys/common/small_c_string.rs index 01acd5191..963d17a47 100644 --- a/std/src/sys/common/small_c_string.rs +++ b/std/src/sys/common/small_c_string.rs @@ -19,7 +19,7 @@ pub fn run_path_with_cstr(path: &Path, f: F) -> io::Result where F: FnOnce(&CStr) -> io::Result, { - run_with_cstr(path.as_os_str().bytes(), f) + run_with_cstr(path.as_os_str().as_os_str_bytes(), f) } #[inline] diff --git a/std/src/sys/common/tests.rs b/std/src/sys/common/tests.rs index fb6f5d6af..0a1cbcbe8 100644 --- a/std/src/sys/common/tests.rs +++ b/std/src/sys/common/tests.rs @@ -8,7 +8,7 @@ use core::iter::repeat; fn stack_allocation_works() { let path = Path::new("abc"); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); @@ -25,7 +25,7 @@ fn heap_allocation_works() { let path = repeat("a").take(384).collect::(); let path = Path::new(&path); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); diff --git a/std/src/sys/unix/path.rs b/std/src/sys/unix/path.rs index a98a69e2d..935245f63 100644 --- a/std/src/sys/unix/path.rs +++ b/std/src/sys/unix/path.rs @@ -30,7 +30,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { // Get the components, skipping the redundant leading "." component if it exists. let mut components = path.strip_prefix(".").unwrap_or(path).components(); - let path_os = path.as_os_str().bytes(); + let path_os = path.as_os_str().as_os_str_bytes(); let mut normalized = if path.is_absolute() { // "If a pathname begins with two successive characters, the diff --git a/std/src/sys/unix/process/process_common.rs b/std/src/sys/unix/process/process_common.rs index afd03d79c..640648e87 100644 --- a/std/src/sys/unix/process/process_common.rs +++ b/std/src/sys/unix/process/process_common.rs @@ -164,9 +164,9 @@ pub enum ProgramKind { impl ProgramKind { fn new(program: &OsStr) -> Self { - if program.bytes().starts_with(b"/") { + if program.as_os_str_bytes().starts_with(b"/") { Self::Absolute - } else if program.bytes().contains(&b'/') { + } else if program.as_os_str_bytes().contains(&b'/') { // If the program has more than one component in it, it is a relative path. Self::Relative } else { diff --git a/std/src/sys/windows/args.rs b/std/src/sys/windows/args.rs index 5bfd8b52e..6b597f499 100644 --- a/std/src/sys/windows/args.rs +++ b/std/src/sys/windows/args.rs @@ -226,7 +226,7 @@ pub(crate) fn append_arg(cmd: &mut Vec, arg: &Arg, force_quotes: bool) -> i // that it actually gets passed through on the command line or otherwise // it will be dropped entirely when parsed on the other end. ensure_no_nuls(arg)?; - let arg_bytes = arg.bytes(); + let arg_bytes = arg.as_os_str_bytes(); let (quote, escape) = match quote { Quote::Always => (true, true), Quote::Auto => { @@ -297,7 +297,9 @@ pub(crate) fn make_bat_command_line( // * `|<>` pipe/redirect characters. const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>"; let force_quotes = match arg { - Arg::Regular(arg) if !force_quotes => arg.bytes().iter().any(|c| SPECIAL.contains(c)), + Arg::Regular(arg) if !force_quotes => { + arg.as_os_str_bytes().iter().any(|c| SPECIAL.contains(c)) + } _ => force_quotes, }; append_arg(&mut cmd, arg, force_quotes)?; diff --git a/std/src/sys/windows/path.rs b/std/src/sys/windows/path.rs index c3573d14c..7a65d901a 100644 --- a/std/src/sys/windows/path.rs +++ b/std/src/sys/windows/path.rs @@ -33,12 +33,12 @@ pub fn is_verbatim_sep(b: u8) -> bool { /// Returns true if `path` looks like a lone filename. pub(crate) fn is_file_name(path: &OsStr) -> bool { - !path.bytes().iter().copied().any(is_sep_byte) + !path.as_os_str_bytes().iter().copied().any(is_sep_byte) } pub(crate) fn has_trailing_slash(path: &OsStr) -> bool { - let is_verbatim = path.bytes().starts_with(br"\\?\"); + let is_verbatim = path.as_os_str_bytes().starts_with(br"\\?\"); let is_separator = if is_verbatim { is_verbatim_sep } else { is_sep_byte }; - if let Some(&c) = path.bytes().last() { is_separator(c) } else { false } + if let Some(&c) = path.as_os_str_bytes().last() { is_separator(c) } else { false } } /// Appends a suffix to a path. @@ -60,7 +60,7 @@ impl<'a, const LEN: usize> PrefixParser<'a, LEN> { fn get_prefix(path: &OsStr) -> [u8; LEN] { let mut prefix = [0; LEN]; // SAFETY: Only ASCII characters are modified. - for (i, &ch) in path.bytes().iter().take(LEN).enumerate() { + for (i, &ch) in path.as_os_str_bytes().iter().take(LEN).enumerate() { prefix[i] = if ch == b'/' { b'\\' } else { ch }; } prefix @@ -93,7 +93,7 @@ impl<'a> PrefixParserSlice<'a, '_> { } fn prefix_bytes(&self) -> &'a [u8] { - &self.path.bytes()[..self.index] + &self.path.as_os_str_bytes()[..self.index] } fn finish(self) -> &'a OsStr { @@ -101,7 +101,7 @@ impl<'a> PrefixParserSlice<'a, '_> { // &[u8] and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced only // from ASCII-bounded slices of existing &OsStr values. - unsafe { bytes_as_os_str(&self.path.bytes()[self.index..]) } + unsafe { bytes_as_os_str(&self.path.as_os_str_bytes()[self.index..]) } } } @@ -173,7 +173,7 @@ fn parse_drive(path: &OsStr) -> Option { drive.is_ascii_alphabetic() } - match path.bytes() { + match path.as_os_str_bytes() { [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), _ => None, } @@ -182,7 +182,7 @@ fn parse_drive(path: &OsStr) -> Option { // Parses a drive prefix exactly, e.g. "C:" fn parse_drive_exact(path: &OsStr) -> Option { // only parse two bytes: the drive letter and the drive separator - if path.bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { + if path.as_os_str_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { parse_drive(path) } else { None @@ -196,15 +196,15 @@ fn parse_drive_exact(path: &OsStr) -> Option { fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; - match path.bytes().iter().position(|&x| separator(x)) { + match path.as_os_str_bytes().iter().position(|&x| separator(x)) { Some(separator_start) => { let separator_end = separator_start + 1; - let component = &path.bytes()[..separator_start]; + let component = &path.as_os_str_bytes()[..separator_start]; // Panic safe // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. - let path = &path.bytes()[separator_end..]; + let path = &path.as_os_str_bytes()[separator_end..]; // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') // is encoded in a single byte, therefore `bytes[separator_start]` and @@ -329,7 +329,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { // Verbatim paths should not be modified. if prefix.map(|x| x.is_verbatim()).unwrap_or(false) { // NULs in verbatim paths are rejected for consistency. - if path.bytes().contains(&0) { + if path.as_os_str_bytes().contains(&0) { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", diff --git a/std/src/sys/windows/process.rs b/std/src/sys/windows/process.rs index df3667c0f..a573a05c3 100644 --- a/std/src/sys/windows/process.rs +++ b/std/src/sys/windows/process.rs @@ -395,7 +395,7 @@ fn resolve_exe<'a>( // Test if the file name has the `exe` extension. // This does a case-insensitive `ends_with`. let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() { - exe_path.bytes()[exe_path.len() - EXE_SUFFIX.len()..] + exe_path.as_os_str_bytes()[exe_path.len() - EXE_SUFFIX.len()..] .eq_ignore_ascii_case(EXE_SUFFIX.as_bytes()) } else { false @@ -425,7 +425,7 @@ fn resolve_exe<'a>( // From the `CreateProcessW` docs: // > If the file name does not contain an extension, .exe is appended. // Note that this rule only applies when searching paths. - let has_extension = exe_path.bytes().contains(&b'.'); + let has_extension = exe_path.as_os_str_bytes().contains(&b'.'); // Search the directories given by `search_paths`. let result = search_paths(parent_paths, child_paths, |mut path| { From e3999897efbe1b54c387b8ed50653871d5eabed3 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Sat, 13 May 2023 19:09:00 +0200 Subject: [PATCH 022/180] refactor: Remove bespoke from_os_str_bytes_unchecked --- std/src/path.rs | 36 ++++++++++++++++-------------------- std/src/sys/windows/path.rs | 20 +++++++------------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/std/src/path.rs b/std/src/path.rs index 6f770d4c9..28cd3c4e4 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -299,20 +299,6 @@ where } } -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - // SAFETY: See note at the top of this module to understand why this and - // `OsStr::bytes` are used: - // - // This casts are safe as OsStr is internally a wrapper around [u8] on all - // platforms. - // - // Note that currently this relies on the special knowledge that std has; - // these types are single-element structs but are not marked - // repr(transparent) or repr(C) which would make these casts not allowable - // outside std. - unsafe { &*(s as *const [u8] as *const OsStr) } -} - // Detect scheme on Redox fn has_redox_scheme(s: &[u8]) -> bool { cfg!(target_os = "redox") && s.contains(&b':') @@ -344,7 +330,12 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { if before == Some(b"") { (Some(file), None) } else { - unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) } + unsafe { + ( + before.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + after.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + ) + } } } @@ -364,7 +355,12 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { }; let before = &slice[..i]; let after = &slice[i + 1..]; - unsafe { (u8_slice_as_os_str(before), Some(u8_slice_as_os_str(after))) } + unsafe { + ( + OsStr::from_os_str_bytes_unchecked(before), + Some(OsStr::from_os_str_bytes_unchecked(after)), + ) + } } //////////////////////////////////////////////////////////////////////////////// @@ -743,7 +739,7 @@ impl<'a> Components<'a> { // separately via `include_cur_dir` b".." => Some(Component::ParentDir), b"" => None, - _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })), + _ => Some(Component::Normal(unsafe { OsStr::from_os_str_bytes_unchecked(comp) })), } } @@ -900,7 +896,7 @@ impl<'a> Iterator for Components<'a> { let raw = &self.path[..self.prefix_len()]; self.path = &self.path[self.prefix_len()..]; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(raw) }, + raw: unsafe { OsStr::from_os_str_bytes_unchecked(raw) }, parsed: self.prefix.unwrap(), })); } @@ -972,7 +968,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(self.path) }, + raw: unsafe { OsStr::from_os_str_bytes_unchecked(self.path) }, parsed: self.prefix.unwrap(), })); } @@ -2011,7 +2007,7 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - unsafe { Path::new(u8_slice_as_os_str(s)) } + unsafe { Path::new(OsStr::from_os_str_bytes_unchecked(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { diff --git a/std/src/sys/windows/path.rs b/std/src/sys/windows/path.rs index 7a65d901a..c9c2d10e6 100644 --- a/std/src/sys/windows/path.rs +++ b/std/src/sys/windows/path.rs @@ -1,7 +1,6 @@ use super::{c, fill_utf16_buf, to_u16s}; use crate::ffi::{OsStr, OsString}; use crate::io; -use crate::mem; use crate::path::{Path, PathBuf, Prefix}; use crate::ptr; @@ -11,16 +10,6 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; -/// # Safety -/// -/// `bytes` must be a valid wtf8 encoded slice -#[inline] -unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr { - // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8, - // which is compatible with &[u8]. - mem::transmute(bytes) -} - #[inline] pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' @@ -101,7 +90,7 @@ impl<'a> PrefixParserSlice<'a, '_> { // &[u8] and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced only // from ASCII-bounded slices of existing &OsStr values. - unsafe { bytes_as_os_str(&self.path.as_os_str_bytes()[self.index..]) } + unsafe { OsStr::from_os_str_bytes_unchecked(&self.path.as_os_str_bytes()[self.index..]) } } } @@ -210,7 +199,12 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { // is encoded in a single byte, therefore `bytes[separator_start]` and // `bytes[separator_end]` must be code point boundaries and thus // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. - unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) } + unsafe { + ( + OsStr::from_os_str_bytes_unchecked(component), + OsStr::from_os_str_bytes_unchecked(path), + ) + } } None => (path, OsStr::new("")), } From 8fb25812d3ba78506dabc9c15b011ecb476a2c65 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 16 May 2023 21:03:29 -0500 Subject: [PATCH 023/180] docs: Add examples of OsStr safety violation --- std/src/ffi/os_str.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index 90cbd57a9..d40c6d317 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -678,8 +678,10 @@ impl OsStr { /// `OsStr`'s encoding is an unspecified superset of UTF-8 and callers must /// pass in bytes that originated as a mixture of validated UTF-8 and bytes from /// [`OsStr::as_os_str_bytes`] from within the same rust version built for the same target - /// platform. The bytes from `OsStr::as_os_str_bytes` may be split either - /// immediately before or immediately after some valid non-empty UTF-8 substring + /// platform. For example, reconstructing an `OsStr` from bytes sent over the network or stored + /// in a file will likely violate these safety rules. The bytes from `OsStr::as_os_str_bytes` + /// may be split either immediately before or immediately after some valid non-empty UTF-8 + /// substring /// /// # Example /// @@ -881,8 +883,9 @@ impl OsStr { /// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should /// be treated as opaque and only comparable within the same rust version built for the same - /// target platform. See [`OsString`] for more encoding details and [`std::ffi`] for - /// platform-specific, specified conversions. + /// target platform. For example, sending the slice over the network or storing it in a file + /// will likely result in incompatible byte slices See [`OsString`] for more encoding details + /// and [`std::ffi`] for platform-specific, specified conversions. /// /// [`std::ffi`]: crate::ffi #[inline] From 99f72621faa0e7e045dc3162b6b9fe66df607203 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 17 May 2023 09:34:25 -0500 Subject: [PATCH 024/180] docs: Clarify OsStr is self-synchronizing --- std/src/ffi/os_str.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index d40c6d317..dd92b9cf7 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -670,18 +670,22 @@ impl OsStr { /// Converts a slice of bytes to an OS string slice without checking that the string contains /// valid `OsStr`-encoded data. /// + /// 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 + /// ASCII. + /// /// See the [module's toplevel documentation about conversions][conversions] for safe, /// cross-platform [conversions] from/to native representations. /// /// # Safety /// - /// `OsStr`'s encoding is an unspecified superset of UTF-8 and callers must - /// pass in bytes that originated as a mixture of validated UTF-8 and bytes from - /// [`OsStr::as_os_str_bytes`] from within the same rust version built for the same target - /// platform. For example, reconstructing an `OsStr` from bytes sent over the network or stored - /// in a file will likely violate these safety rules. The bytes from `OsStr::as_os_str_bytes` - /// may be split either immediately before or immediately after some valid non-empty UTF-8 - /// substring + /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of + /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version + /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent + /// over the network or stored in a file will likely violate these safety rules. + /// + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be + /// split either immediately before or immediately after any valid non-empty UTF-8 substring. /// /// # Example /// @@ -881,6 +885,10 @@ impl OsStr { /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS /// string slice, use the [`OsStr::from_os_str_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 + /// ASCII. + /// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should /// be treated as opaque and only comparable within the same rust version built for the same /// target platform. For example, sending the slice over the network or storing it in a file From 3717cf67dd7b34c26aa72ded93ea6554047e679d Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 17 May 2023 17:29:02 -0400 Subject: [PATCH 025/180] Option::map_or_else: Show an example of integrating with Result Moving this from https://github.com/rust-lang/libs-team/issues/59 where an API addition was rejected. But I think it's valuable to add this example to the documentation at least. --- core/src/option.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/core/src/option.rs b/core/src/option.rs index ec1ef3cf4..b93b40e30 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -1138,7 +1138,7 @@ impl Option { /// Computes a default function result (if none), or /// applies a different function to the contained value (if any). /// - /// # Examples + /// # Basic examples /// /// ``` /// let k = 21; @@ -1149,6 +1149,25 @@ impl Option { /// let x: Option<&str> = None; /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); /// ``` + /// + /// # Handling a Result-based fallback + /// + /// A somewhat common occurrence when dealing with optional values + /// in combination with [`Result`] is the case where one wants to invoke + /// a fallible fallback if the option is not present. This example + /// parses a command line argument (if present), or the contents of a file to + /// an integer. However, unlike accessing the command line argument, reading + /// the file is fallible, so it must be wrapped with `Ok`. + /// + /// ```no_run + /// # fn main() -> Result<(), Box> { + /// let v: u64 = std::env::args() + /// .nth(1) + /// .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)? + /// .parse()?; + /// # Ok(()) + /// # } + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn map_or_else(self, default: D, f: F) -> U From adfcaf812a5263f001f1938b8a94b48a4b6b7ca9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 May 2023 19:41:41 -0500 Subject: [PATCH 026/180] docs: Add missing period --- std/src/ffi/os_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index dd92b9cf7..bb577acf7 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -892,7 +892,7 @@ impl OsStr { /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should /// be treated as opaque and only comparable within the same rust version built for the same /// target platform. For example, sending the slice over the network or storing it in a file - /// will likely result in incompatible byte slices See [`OsString`] for more encoding details + /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details /// and [`std::ffi`] for platform-specific, specified conversions. /// /// [`std::ffi`]: crate::ffi From c83487da610b05a31f4c7974bf58739e4273d063 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:49:36 -0700 Subject: [PATCH 027/180] Safe Transmute: Enable handling references, including recursive types This patch enables support for references in Safe Transmute, by generating nested obligations during trait selection. Specifically, when we call `confirm_transmutability_candidate(...)`, we now recursively traverse the `rustc_transmute::Answer` tree and create obligations for all the `Answer` variants, some of which include multiple nested `Answer`s. Also, to handle recursive types, enable support for coinduction for the Safe Transmute trait (`BikeshedIntrinsicFrom`) by adding the `#[rustc_coinduction]` annotation. Also fix some small logic issues when reducing the `or` and `and` combinations in `rustc_transmute`, so that we don't end up with additional redundant `Answer`s in the tree. Co-authored-by: Jack Wrenn --- core/src/mem/transmutability.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/mem/transmutability.rs b/core/src/mem/transmutability.rs index 87ae30619..d0c30e715 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -5,6 +5,7 @@ /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] +#[rustc_coinductive] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, From 4e1f97036dff0674c98fa31377b832d6e0a8106f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 1 May 2023 10:05:44 -0700 Subject: [PATCH 028/180] bootstrap: enable Cargo `public-dependency` feature for `libstd` --- std/Cargo.toml | 10 ++++++---- std/tests/common/mod.rs | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 824abc72a..4765bb5d2 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["public-dependency"] + [package] name = "std" version = "0.0.0" @@ -10,12 +12,12 @@ edition = "2021" crate-type = ["dylib", "rlib"] [dependencies] -alloc = { path = "../alloc" } +alloc = { path = "../alloc", public = true } 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" } -libc = { version = "0.2.143", default-features = false, features = ['rustc-dep-of-std'] } +core = { path = "../core", public = true } +libc = { version = "0.2.143", default-features = false, features = ['rustc-dep-of-std'], public = true } compiler_builtins = { version = "0.1.92" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } @@ -25,7 +27,7 @@ std_detect = { path = "../stdarch/crates/std_detect", default-features = false, # Dependencies of the `backtrace` crate addr2line = { version = "0.19.0", optional = true, default-features = false } rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } -miniz_oxide = { version = "0.6.0", optional = true, default-features = false } +miniz_oxide = { version = "0.6.0", optional = true, default-features = false, public = false } [dependencies.object] version = "0.30.0" optional = true diff --git a/std/tests/common/mod.rs b/std/tests/common/mod.rs index fce220223..37336e1c0 100644 --- a/std/tests/common/mod.rs +++ b/std/tests/common/mod.rs @@ -1,5 +1,7 @@ #![allow(unused)] +#![allow(exported_private_dependencies)] + use std::env; use std::fs; use std::path::{Path, PathBuf}; From 94313d26b4609ac7b5c64e813e12a6461056d477 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 8 May 2023 14:51:07 -0700 Subject: [PATCH 029/180] std: mark common functions in test crate `pub(crate)` This is not a library, so there's no reason for them to be `pub`. Without doing this, compiling the test crates causes private dep lint errors: error: type `PathBuf` from private dependency 'std' in public interface --> library/std/tests/common/mod.rs:26:5 | 26 | pub fn join(&self, path: &str) -> PathBuf { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D exported-private-dependencies` implied by `-D warnings` error: type `Path` from private dependency 'std' in public interface --> library/std/tests/common/mod.rs:31:5 | 31 | pub fn path(&self) -> &Path { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: could not compile `std` (test "create_dir_all_bare") due to 2 previous errors This happens because Cargo passes `--extern 'priv:std=...` when compiling the test crate. I'm not sure if these warnings are desirable or not. They seem correct in a very pedantic way (the dependency on `std` is not marked public, since it's implicit), but also pointless (the test crate is not an API, so who cares what it does). --- std/tests/common/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/std/tests/common/mod.rs b/std/tests/common/mod.rs index 37336e1c0..358c2c3f9 100644 --- a/std/tests/common/mod.rs +++ b/std/tests/common/mod.rs @@ -1,7 +1,5 @@ #![allow(unused)] -#![allow(exported_private_dependencies)] - use std::env; use std::fs; use std::path::{Path, PathBuf}; @@ -22,15 +20,15 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { } // Copied from std::sys_common::io -pub struct TempDir(PathBuf); +pub(crate) struct TempDir(PathBuf); impl TempDir { - pub fn join(&self, path: &str) -> PathBuf { + pub(crate) fn join(&self, path: &str) -> PathBuf { let TempDir(ref p) = *self; p.join(path) } - pub fn path(&self) -> &Path { + pub(crate) fn path(&self) -> &Path { let TempDir(ref p) = *self; p } @@ -51,7 +49,7 @@ impl Drop for TempDir { } #[track_caller] // for `test_rng` -pub fn tmpdir() -> TempDir { +pub(crate) fn tmpdir() -> TempDir { let p = env::temp_dir(); let mut r = test_rng(); let ret = p.join(&format!("rust-{}", r.next_u32())); From 5f95694dd4445da4cab249c2df77ff9d929d109f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 May 2023 20:30:55 -0700 Subject: [PATCH 030/180] std: make internal-only items `pub(crate)` This works around a weird problem that looks like a bug in the `exported_private_dependencies` lint. --- std/src/sys/wasi/fd.rs | 6 +++--- std/src/sys/wasi/fs.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/std/src/sys/wasi/fd.rs b/std/src/sys/wasi/fd.rs index 9a8b2a0be..1b50c2ea6 100644 --- a/std/src/sys/wasi/fd.rs +++ b/std/src/sys/wasi/fd.rs @@ -96,7 +96,7 @@ impl WasiFd { unsafe { wasi::fd_sync(self.as_raw_fd() as wasi::Fd).map_err(err2io) } } - pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { + pub(crate) fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { unsafe { wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io) } @@ -179,7 +179,7 @@ impl WasiFd { } } - pub fn filestat_get(&self) -> io::Result { + pub(crate) fn filestat_get(&self) -> io::Result { unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) } } @@ -199,7 +199,7 @@ impl WasiFd { unsafe { wasi::fd_filestat_set_size(self.as_raw_fd() as wasi::Fd, size).map_err(err2io) } } - pub fn path_filestat_get( + pub(crate) fn path_filestat_get( &self, flags: wasi::Lookupflags, path: &str, diff --git a/std/src/sys/wasi/fs.rs b/std/src/sys/wasi/fs.rs index 8d1dbf591..437aae3ae 100644 --- a/std/src/sys/wasi/fs.rs +++ b/std/src/sys/wasi/fs.rs @@ -104,7 +104,7 @@ impl FileAttr { Ok(SystemTime::from_wasi_timestamp(self.meta.ctim)) } - pub fn as_wasi(&self) -> &wasi::Filestat { + pub(crate) fn as_wasi(&self) -> &wasi::Filestat { &self.meta } } @@ -142,7 +142,7 @@ impl FileType { self.bits == wasi::FILETYPE_SYMBOLIC_LINK } - pub fn bits(&self) -> wasi::Filetype { + pub(crate) fn bits(&self) -> wasi::Filetype { self.bits } } From ff38db02bad8c45422dc00fcdcf7007b2b66ddee Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 20 May 2023 20:14:38 -0700 Subject: [PATCH 031/180] std: make `fortanix-sgx-abi` a public depedenceny It's exported publicly, so it should not be linted. --- std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 4765bb5d2..72d910bf9 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -42,7 +42,7 @@ rand_xorshift = "0.3.0" dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] -fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] } +fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true } [target.'cfg(target_os = "hermit")'.dependencies] hermit-abi = { version = "0.3.0", features = ['rustc-dep-of-std'] } From a47eabe454bbab872019f4ce19960991a5338ece Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 14:49:38 +0200 Subject: [PATCH 032/180] refactor executing tests to centralize actually invoking tests Before this commit, tests were invoked in multiple places, especially due to `-Z panic-abort-tests`, and adding a new test kind meant having to chase down and update all these places. This commit creates a new Runnable enum, and its children RunnableTest and RunnableBench. The rest of the harness will now pass around the enum rather than constructing and passing around boxed functions. The enum has two children enums because invoking tests and invoking benchmarks requires different parameters. --- test/src/lib.rs | 69 +++++++++++++++++++---------------------------- test/src/types.rs | 62 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/test/src/lib.rs b/test/src/lib.rs index e76d6716b..ca8000e99 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -178,11 +178,17 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { .next() .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{name}'")); let TestDescAndFn { desc, testfn } = test; - let testfn = match testfn { - StaticTestFn(f) => f, - _ => panic!("only static tests are supported"), - }; - run_test_in_spawned_subprocess(desc, Box::new(testfn)); + match testfn.into_runnable() { + Runnable::Test(runnable_test) => { + if runnable_test.is_dynamic() { + panic!("only static tests are supported"); + } + run_test_in_spawned_subprocess(desc, runnable_test); + } + Runnable::Bench(_) => { + panic!("benchmarks should not be executed into child processes") + } + } } let args = env::args().collect::>(); @@ -563,7 +569,7 @@ pub fn run_test( id: TestId, desc: TestDesc, monitor_ch: Sender, - testfn: Box Result<(), String> + Send>, + runnable_test: RunnableTest, opts: TestRunOpts, ) -> Option> { let name = desc.name.clone(); @@ -574,7 +580,7 @@ pub fn run_test( desc, opts.nocapture, opts.time.is_some(), - testfn, + runnable_test, monitor_ch, opts.time, ), @@ -615,37 +621,21 @@ pub fn run_test( let test_run_opts = TestRunOpts { strategy, nocapture: opts.nocapture, time: opts.time_options }; - match testfn { - DynBenchFn(benchfn) => { - // Benchmarks aren't expected to panic, so we run them all in-process. - crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn); - None + match testfn.into_runnable() { + Runnable::Test(runnable_test) => { + if runnable_test.is_dynamic() { + match strategy { + RunStrategy::InProcess => (), + _ => panic!("Cannot run dynamic test fn out-of-process"), + }; + } + run_test_inner(id, desc, monitor_ch, runnable_test, test_run_opts) } - StaticBenchFn(benchfn) => { + Runnable::Bench(runnable_bench) => { // Benchmarks aren't expected to panic, so we run them all in-process. - crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn); + runnable_bench.run(id, &desc, &monitor_ch, opts.nocapture); None } - DynTestFn(f) => { - match strategy { - RunStrategy::InProcess => (), - _ => panic!("Cannot run dynamic test fn out-of-process"), - }; - run_test_inner( - id, - desc, - monitor_ch, - Box::new(move || __rust_begin_short_backtrace(f)), - test_run_opts, - ) - } - StaticTestFn(f) => run_test_inner( - id, - desc, - monitor_ch, - Box::new(move || __rust_begin_short_backtrace(f)), - test_run_opts, - ), } } @@ -663,7 +653,7 @@ fn run_test_in_process( desc: TestDesc, nocapture: bool, report_time: bool, - testfn: Box Result<(), String> + Send>, + runnable_test: RunnableTest, monitor_ch: Sender, time_opts: Option, ) { @@ -675,7 +665,7 @@ fn run_test_in_process( } let start = report_time.then(Instant::now); - let result = fold_err(catch_unwind(AssertUnwindSafe(testfn))); + let result = fold_err(catch_unwind(AssertUnwindSafe(|| runnable_test.run()))); let exec_time = start.map(|start| { let duration = start.elapsed(); TestExecTime(duration) @@ -760,10 +750,7 @@ fn spawn_test_subprocess( monitor_ch.send(message).unwrap(); } -fn run_test_in_spawned_subprocess( - desc: TestDesc, - testfn: Box Result<(), String> + Send>, -) -> ! { +fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! { let builtin_panic_hook = panic::take_hook(); let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| { let test_result = match panic_info { @@ -789,7 +776,7 @@ fn run_test_in_spawned_subprocess( }); let record_result2 = record_result.clone(); panic::set_hook(Box::new(move |info| record_result2(Some(info)))); - if let Err(message) = testfn() { + if let Err(message) = runnable_test.run() { panic!("{}", message); } record_result(None); diff --git a/test/src/types.rs b/test/src/types.rs index e79914dbf..b67880a98 100644 --- a/test/src/types.rs +++ b/test/src/types.rs @@ -2,8 +2,11 @@ use std::borrow::Cow; use std::fmt; +use std::sync::mpsc::Sender; +use super::__rust_begin_short_backtrace; use super::bench::Bencher; +use super::event::CompletedTest; use super::options; pub use NamePadding::*; @@ -95,6 +98,15 @@ impl TestFn { DynBenchFn(..) => PadOnRight, } } + + pub(crate) fn into_runnable(self) -> Runnable { + match self { + StaticTestFn(f) => Runnable::Test(RunnableTest::Static(f)), + StaticBenchFn(f) => Runnable::Bench(RunnableBench::Static(f)), + DynTestFn(f) => Runnable::Test(RunnableTest::Dynamic(f)), + DynBenchFn(f) => Runnable::Bench(RunnableBench::Dynamic(f)), + } + } } impl fmt::Debug for TestFn { @@ -108,6 +120,56 @@ impl fmt::Debug for TestFn { } } +pub(crate) enum Runnable { + Test(RunnableTest), + Bench(RunnableBench), +} + +pub(crate) enum RunnableTest { + Static(fn() -> Result<(), String>), + Dynamic(Box Result<(), String> + Send>), +} + +impl RunnableTest { + pub(crate) fn run(self) -> Result<(), String> { + match self { + RunnableTest::Static(f) => __rust_begin_short_backtrace(f), + RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f), + } + } + + pub(crate) fn is_dynamic(&self) -> bool { + match self { + RunnableTest::Static(_) => false, + RunnableTest::Dynamic(_) => true, + } + } +} + +pub(crate) enum RunnableBench { + Static(fn(&mut Bencher) -> Result<(), String>), + Dynamic(Box Result<(), String> + Send>), +} + +impl RunnableBench { + pub(crate) fn run( + self, + id: TestId, + desc: &TestDesc, + monitor_ch: &Sender, + nocapture: bool, + ) { + match self { + RunnableBench::Static(f) => { + crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f) + } + RunnableBench::Dynamic(f) => { + crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f) + } + } + } +} + // A unique integer associated with each test. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct TestId(pub usize); From 03a11644e01201df33b58a1f27cd82b8977efe45 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 14:56:59 +0200 Subject: [PATCH 033/180] remove nested function from run_test The inner function is not needed anymore as it's only called once after the previous commit's refactoring. --- test/src/lib.rs | 110 +++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 63 deletions(-) diff --git a/test/src/lib.rs b/test/src/lib.rs index ca8000e99..c2725a432 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -559,68 +559,6 @@ pub fn run_test( return None; } - struct TestRunOpts { - pub strategy: RunStrategy, - pub nocapture: bool, - pub time: Option, - } - - fn run_test_inner( - id: TestId, - desc: TestDesc, - monitor_ch: Sender, - runnable_test: RunnableTest, - opts: TestRunOpts, - ) -> Option> { - let name = desc.name.clone(); - - let runtest = move || match opts.strategy { - RunStrategy::InProcess => run_test_in_process( - id, - desc, - opts.nocapture, - opts.time.is_some(), - runnable_test, - monitor_ch, - opts.time, - ), - RunStrategy::SpawnPrimary => spawn_test_subprocess( - id, - desc, - opts.nocapture, - opts.time.is_some(), - monitor_ch, - opts.time, - ), - }; - - // If the platform is single-threaded we're just going to run - // the test synchronously, regardless of the concurrency - // level. - let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm"); - if supports_threads { - let cfg = thread::Builder::new().name(name.as_slice().to_owned()); - let mut runtest = Arc::new(Mutex::new(Some(runtest))); - let runtest2 = runtest.clone(); - match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) { - Ok(handle) => Some(handle), - Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - // `ErrorKind::WouldBlock` means hitting the thread limit on some - // platforms, so run the test synchronously here instead. - Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()(); - None - } - Err(e) => panic!("failed to spawn thread to run test: {e}"), - } - } else { - runtest(); - None - } - } - - let test_run_opts = - TestRunOpts { strategy, nocapture: opts.nocapture, time: opts.time_options }; - match testfn.into_runnable() { Runnable::Test(runnable_test) => { if runnable_test.is_dynamic() { @@ -629,7 +567,53 @@ pub fn run_test( _ => panic!("Cannot run dynamic test fn out-of-process"), }; } - run_test_inner(id, desc, monitor_ch, runnable_test, test_run_opts) + + let name = desc.name.clone(); + let nocapture = opts.nocapture; + let time_options = opts.time_options; + + let runtest = move || match strategy { + RunStrategy::InProcess => run_test_in_process( + id, + desc, + nocapture, + time_options.is_some(), + runnable_test, + monitor_ch, + time_options, + ), + RunStrategy::SpawnPrimary => spawn_test_subprocess( + id, + desc, + nocapture, + time_options.is_some(), + monitor_ch, + time_options, + ), + }; + + // If the platform is single-threaded we're just going to run + // the test synchronously, regardless of the concurrency + // level. + let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm"); + if supports_threads { + let cfg = thread::Builder::new().name(name.as_slice().to_owned()); + let mut runtest = Arc::new(Mutex::new(Some(runtest))); + let runtest2 = runtest.clone(); + match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) { + Ok(handle) => Some(handle), + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // `ErrorKind::WouldBlock` means hitting the thread limit on some + // platforms, so run the test synchronously here instead. + Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()(); + None + } + Err(e) => panic!("failed to spawn thread to run test: {e}"), + } + } else { + runtest(); + None + } } Runnable::Bench(runnable_bench) => { // Benchmarks aren't expected to panic, so we run them all in-process. From 231ce1365bf5f0751258df600f5255067245c53f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 12:46:54 +0200 Subject: [PATCH 034/180] add StaticBenchAsTestFn and DynBenchAsTestFn to convert benches to tests Before this commit, both static and dynamic benches were converted to a DynTestFn, with a boxed closure that ran the benchmarks exactly once. While this worked, it conflicted with -Z panic-abort-tests as the flag does not support dynamic tests. With this change, a StaticBenchFn is converted to a StaticBenchAsTestFn, avoiding any dynamic test creation. DynBenchFn is also converted to DynBenchAsTestFn for completeness. --- test/src/console.rs | 2 +- test/src/lib.rs | 22 ++++------------------ test/src/types.rs | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/test/src/console.rs b/test/src/console.rs index 7eee4ca23..bbeb944e8 100644 --- a/test/src/console.rs +++ b/test/src/console.rs @@ -199,7 +199,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Res let TestDescAndFn { desc, testfn } = test; let fntype = match testfn { - StaticTestFn(..) | DynTestFn(..) => { + StaticTestFn(..) | DynTestFn(..) | StaticBenchAsTestFn(..) | DynBenchAsTestFn(..) => { st.tests += 1; "test" } diff --git a/test/src/lib.rs b/test/src/lib.rs index c2725a432..786439e0a 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -240,16 +240,6 @@ impl FilteredTests { self.tests.push((TestId(self.next_id), test)); self.next_id += 1; } - fn add_bench_as_test( - &mut self, - desc: TestDesc, - benchfn: impl Fn(&mut Bencher) -> Result<(), String> + Send + 'static, - ) { - let testfn = DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) - })); - self.add_test(desc, testfn); - } fn total_len(&self) -> usize { self.tests.len() + self.benches.len() } @@ -307,14 +297,14 @@ where if opts.bench_benchmarks { filtered.add_bench(desc, DynBenchFn(benchfn)); } else { - filtered.add_bench_as_test(desc, benchfn); + filtered.add_test(desc, DynBenchAsTestFn(benchfn)); } } StaticBenchFn(benchfn) => { if opts.bench_benchmarks { filtered.add_bench(desc, StaticBenchFn(benchfn)); } else { - filtered.add_bench_as_test(desc, benchfn); + filtered.add_test(desc, StaticBenchAsTestFn(benchfn)); } } testfn => { @@ -525,12 +515,8 @@ pub fn convert_benchmarks_to_tests(tests: Vec) -> Vec DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) - })), - StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) - })), + DynBenchFn(benchfn) => DynBenchAsTestFn(benchfn), + StaticBenchFn(benchfn) => StaticBenchAsTestFn(benchfn), f => f, }; TestDescAndFn { desc: x.desc, testfn } diff --git a/test/src/types.rs b/test/src/types.rs index b67880a98..504ceee7f 100644 --- a/test/src/types.rs +++ b/test/src/types.rs @@ -85,8 +85,10 @@ impl fmt::Display for TestName { pub enum TestFn { StaticTestFn(fn() -> Result<(), String>), StaticBenchFn(fn(&mut Bencher) -> Result<(), String>), + StaticBenchAsTestFn(fn(&mut Bencher) -> Result<(), String>), DynTestFn(Box Result<(), String> + Send>), DynBenchFn(Box Result<(), String> + Send>), + DynBenchAsTestFn(Box Result<(), String> + Send>), } impl TestFn { @@ -94,8 +96,10 @@ impl TestFn { match *self { StaticTestFn(..) => PadNone, StaticBenchFn(..) => PadOnRight, + StaticBenchAsTestFn(..) => PadNone, DynTestFn(..) => PadNone, DynBenchFn(..) => PadOnRight, + DynBenchAsTestFn(..) => PadNone, } } @@ -103,8 +107,10 @@ impl TestFn { match self { StaticTestFn(f) => Runnable::Test(RunnableTest::Static(f)), StaticBenchFn(f) => Runnable::Bench(RunnableBench::Static(f)), + StaticBenchAsTestFn(f) => Runnable::Test(RunnableTest::StaticBenchAsTest(f)), DynTestFn(f) => Runnable::Test(RunnableTest::Dynamic(f)), DynBenchFn(f) => Runnable::Bench(RunnableBench::Dynamic(f)), + DynBenchAsTestFn(f) => Runnable::Test(RunnableTest::DynamicBenchAsTest(f)), } } } @@ -114,8 +120,10 @@ impl fmt::Debug for TestFn { f.write_str(match *self { StaticTestFn(..) => "StaticTestFn(..)", StaticBenchFn(..) => "StaticBenchFn(..)", + StaticBenchAsTestFn(..) => "StaticBenchAsTestFn(..)", DynTestFn(..) => "DynTestFn(..)", DynBenchFn(..) => "DynBenchFn(..)", + DynBenchAsTestFn(..) => "DynBenchAsTestFn(..)", }) } } @@ -128,6 +136,8 @@ pub(crate) enum Runnable { pub(crate) enum RunnableTest { Static(fn() -> Result<(), String>), Dynamic(Box Result<(), String> + Send>), + StaticBenchAsTest(fn(&mut Bencher) -> Result<(), String>), + DynamicBenchAsTest(Box Result<(), String> + Send>), } impl RunnableTest { @@ -135,13 +145,21 @@ impl RunnableTest { match self { RunnableTest::Static(f) => __rust_begin_short_backtrace(f), RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f), + RunnableTest::StaticBenchAsTest(f) => { + crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b))) + } + RunnableTest::DynamicBenchAsTest(f) => { + crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b))) + } } } pub(crate) fn is_dynamic(&self) -> bool { match self { RunnableTest::Static(_) => false, + RunnableTest::StaticBenchAsTest(_) => false, RunnableTest::Dynamic(_) => true, + RunnableTest::DynamicBenchAsTest(_) => true, } } } From 88db75429e5093e2b8541827b5a5d8c728c80e86 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 12:56:16 +0200 Subject: [PATCH 035/180] convert benches to tests in subprocess if we're not benchmarking --- test/src/lib.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/test/src/lib.rs b/test/src/lib.rs index 786439e0a..b40b6009e 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -92,6 +92,7 @@ use time::TestExecTime; const ERROR_EXIT_CODE: i32 = 101; const SECONDARY_TEST_INVOKER_VAR: &str = "__RUST_TEST_INVOKE"; +const SECONDARY_TEST_BENCH_BENCHMARKS_VAR: &str = "__RUST_TEST_BENCH_BENCHMARKS"; // The default console test runner. It accepts the command line // arguments and a vector of test_descs. @@ -171,10 +172,18 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { // will then exit the process. if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) { env::remove_var(SECONDARY_TEST_INVOKER_VAR); + + // Convert benchmarks to tests if we're not benchmarking. + let mut tests = tests.iter().map(make_owned_test).collect::>(); + if env::var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR).is_ok() { + env::remove_var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR); + } else { + tests = convert_benchmarks_to_tests(tests); + }; + let test = tests - .iter() + .into_iter() .filter(|test| test.desc.name.as_slice() == name) - .map(make_owned_test) .next() .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{name}'")); let TestDescAndFn { desc, testfn } = test; @@ -557,6 +566,7 @@ pub fn run_test( let name = desc.name.clone(); let nocapture = opts.nocapture; let time_options = opts.time_options; + let bench_benchmarks = opts.bench_benchmarks; let runtest = move || match strategy { RunStrategy::InProcess => run_test_in_process( @@ -575,6 +585,7 @@ pub fn run_test( time_options.is_some(), monitor_ch, time_options, + bench_benchmarks, ), }; @@ -672,6 +683,7 @@ fn spawn_test_subprocess( report_time: bool, monitor_ch: Sender, time_opts: Option, + bench_benchmarks: bool, ) { let (result, test_output, exec_time) = (|| { let args = env::args().collect::>(); @@ -679,6 +691,9 @@ fn spawn_test_subprocess( let mut command = Command::new(current_exe); command.env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice()); + if bench_benchmarks { + command.env(SECONDARY_TEST_BENCH_BENCHMARKS_VAR, "1"); + } if nocapture { command.stdout(process::Stdio::inherit()); command.stderr(process::Stdio::inherit()); From 8b39f6d4c74f814ae7206e291823ac3f57fa6efc Mon Sep 17 00:00:00 2001 From: Kathryn R Date: Fri, 26 May 2023 13:39:10 -0700 Subject: [PATCH 036/180] Fix incorrect documented default bufsize in bufreader/writer --- std/src/io/buffered/bufreader.rs | 2 +- std/src/io/buffered/bufwriter.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/io/buffered/bufreader.rs b/std/src/io/buffered/bufreader.rs index 4f339a18a..0cc63dcb4 100644 --- a/std/src/io/buffered/bufreader.rs +++ b/std/src/io/buffered/bufreader.rs @@ -53,7 +53,7 @@ pub struct BufReader { } impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KiB, /// but may change in the future. /// /// # Examples diff --git a/std/src/io/buffered/bufwriter.rs b/std/src/io/buffered/bufwriter.rs index 14c455d4f..aac52ec35 100644 --- a/std/src/io/buffered/bufwriter.rs +++ b/std/src/io/buffered/bufwriter.rs @@ -81,7 +81,7 @@ pub struct BufWriter { } impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KiB, /// but may change in the future. /// /// # Examples From b5b6607a25d7cde52c1c4259532dbd50e194f222 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 17:12:45 +0200 Subject: [PATCH 037/180] Uplift clippy::invalid_utf8_in_unchecked as invalid_from_utf8_unchecked --- core/src/str/converts.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/str/converts.rs b/core/src/str/converts.rs index 5f8748206..12fac0567 100644 --- a/core/src/str/converts.rs +++ b/core/src/str/converts.rs @@ -167,6 +167,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -194,6 +195,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. From 27cfafef38510b4edff99991f36ef57a930c4f1d Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 18:33:19 +0200 Subject: [PATCH 038/180] Add invalid_from_utf8 analogous to invalid_from_utf8_unchecked --- core/src/str/converts.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/str/converts.rs b/core/src/str/converts.rs index 12fac0567..0f23cf7ae 100644 --- a/core/src/str/converts.rs +++ b/core/src/str/converts.rs @@ -84,6 +84,7 @@ use super::Utf8Error; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[rustc_allow_const_fn_unstable(str_internals)] +#[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -127,6 +128,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { From d38bebbb09b787e9d8869a1a8a02fea4da760cca Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 21:49:58 +0200 Subject: [PATCH 039/180] Allow newly uplifted invalid_from_utf8 lint --- alloc/tests/str.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alloc/tests/str.rs b/alloc/tests/str.rs index c1dbbde08..0ba5d088f 100644 --- a/alloc/tests/str.rs +++ b/alloc/tests/str.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), allow(invalid_from_utf8))] + use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; From e33dacb0e82abe54feacdf1dc2883af12e439972 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 31 Mar 2023 13:39:27 +0200 Subject: [PATCH 040/180] Stabilize String::leak --- alloc/src/string.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index c524d4c03..0e5a4eea6 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -1853,26 +1853,27 @@ impl String { /// Consumes and leaks the `String`, returning a mutable reference to the contents, /// `&'a mut str`. /// - /// This is mainly useful for data that lives for the remainder of - /// the program's life. Dropping the returned reference will cause a memory - /// leak. + /// The caller has free choice over the returned lifetime, including `'static`. Indeed, + /// this function is ideally used for data that lives for the remainder of the program's life, + /// as dropping the returned reference will cause a memory leak. /// /// It does not reallocate or shrink the `String`, /// so the leaked allocation may include unused capacity that is not part - /// of the returned slice. + /// of the returned slice. If you don't want that, call [`into_boxed_str`], + /// and then [`Box::leak`]. + /// + /// [`into_boxed_str`]: Self::into_boxed_str /// /// # Examples /// /// Simple usage: /// /// ``` - /// #![feature(string_leak)] - /// /// let x = String::from("bucket"); /// let static_ref: &'static mut str = x.leak(); /// assert_eq!(static_ref, "bucket"); /// ``` - #[unstable(feature = "string_leak", issue = "102929")] + #[stable(feature = "string_leak", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn leak<'a>(self) -> &'a mut str { let slice = self.vec.leak(); From aff348a22f7bdfdedaedce341493d28d13a544d9 Mon Sep 17 00:00:00 2001 From: Markus Everling Date: Fri, 26 May 2023 01:33:50 +0000 Subject: [PATCH 041/180] Update runtime guarantee for `select_nth_unstable` --- core/src/slice/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index bd1b16e8d..5b86540fd 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -2995,7 +2995,7 @@ impl [T] { /// 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 *O*(*n*) on average. The worst-case performance is *O*(*n* log *n*). + /// (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 reordered slice: @@ -3044,9 +3044,8 @@ impl [T] { /// 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 *O*(*n*) on average. - /// The worst-case performance is *O*(*n* log *n*). This function is also known as - /// "kth element" in other libraries. + /// 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. /// /// It returns a triplet of the following from /// the slice reordered according to the provided comparator function: the subslice prior to @@ -3099,8 +3098,7 @@ impl [T] { /// 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 *O*(*n*) on average. - /// The worst-case performance is *O*(*n* log *n*). + /// 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. /// /// It returns a triplet of the following from From 7cd2f42637df9a625c0aafa982fece74e2a090ab Mon Sep 17 00:00:00 2001 From: Markus Everling Date: Sun, 28 May 2023 16:12:48 +0000 Subject: [PATCH 042/180] Update current impl comment for `select_nth_unstable_by_key` --- core/src/slice/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 1f1955552..62003ddf5 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -3113,8 +3113,9 @@ impl [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// From 7f2aeea70272af2776aed5953d1b361469aac53f Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 29 May 2023 12:29:36 -0700 Subject: [PATCH 043/180] Make `TrustedStep` require `Copy` All the implementations of the trait already are `Copy`, and this seems to be enough to simplify the implementations enough to make the MIR inliner willing to inline basics like `Range::next`. --- core/src/iter/range.rs | 25 +++++++++++++------------ core/src/iter/traits/marker.rs | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/core/src/iter/range.rs b/core/src/iter/range.rs index 0171d8981..462f7170a 100644 --- a/core/src/iter/range.rs +++ b/core/src/iter/range.rs @@ -619,9 +619,10 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_next(&mut self) -> Option { if self.start < self.end { + let old = self.start; // SAFETY: just checked precondition - let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; - Some(mem::replace(&mut self.start, n)) + self.start = unsafe { Step::forward_unchecked(old, 1) }; + Some(old) } else { None } @@ -629,15 +630,15 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_nth(&mut self, n: usize) -> Option { - if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if let Some(plus_n) = Step::forward_checked(self.start, n) { if plus_n < self.end { // SAFETY: just checked precondition - self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) }; + self.start = unsafe { Step::forward_unchecked(plus_n, 1) }; return Some(plus_n); } } - self.start = self.end.clone(); + self.start = self.end; None } @@ -655,7 +656,7 @@ impl RangeIteratorImpl for ops::Range { // then steps_between either returns a bound to which we clamp or returns None which // together with the initial inequality implies more than usize::MAX steps. // Otherwise 0 is returned which always safe to use. - self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; + self.start = unsafe { Step::forward_unchecked(self.start, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } @@ -664,8 +665,8 @@ impl RangeIteratorImpl for ops::Range { fn spec_next_back(&mut self) -> Option { if self.start < self.end { // SAFETY: just checked precondition - self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - Some(self.end.clone()) + self.end = unsafe { Step::backward_unchecked(self.end, 1) }; + Some(self.end) } else { None } @@ -673,15 +674,15 @@ impl RangeIteratorImpl for ops::Range { #[inline] fn spec_nth_back(&mut self, n: usize) -> Option { - if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if let Some(minus_n) = Step::backward_checked(self.end, n) { if minus_n > self.start { // SAFETY: just checked precondition self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; - return Some(self.end.clone()); + return Some(self.end); } } - self.end = self.start.clone(); + self.end = self.start; None } @@ -696,7 +697,7 @@ impl RangeIteratorImpl for ops::Range { let taken = available.min(n); // SAFETY: same as the spec_advance_by() implementation - self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; + self.end = unsafe { Step::backward_unchecked(self.end, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } diff --git a/core/src/iter/traits/marker.rs b/core/src/iter/traits/marker.rs index af0284823..c21a2aac1 100644 --- a/core/src/iter/traits/marker.rs +++ b/core/src/iter/traits/marker.rs @@ -86,4 +86,4 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +pub unsafe trait TrustedStep: Step + Copy {} From 7cee3098351c7e98d1861042e4930ef22c7ccfc7 Mon Sep 17 00:00:00 2001 From: reez12g Date: Tue, 30 May 2023 13:56:57 +0900 Subject: [PATCH 044/180] fix comment on Allocator trait --- core/src/alloc/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/alloc/mod.rs b/core/src/alloc/mod.rs index ff390322d..452bc482c 100644 --- a/core/src/alloc/mod.rs +++ b/core/src/alloc/mod.rs @@ -94,8 +94,9 @@ impl fmt::Display for AllocError { /// /// # Safety /// -/// * Memory blocks returned from an allocator must point to valid memory and retain their validity -/// until the instance and all of its copies and clones are dropped, +/// * 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 at +/// least one of the instance and all of its clones has not been 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 From ffe677ffe1114f17a9b22eca0c96a1a7b6bb2afd Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 30 May 2023 00:34:50 -0700 Subject: [PATCH 045/180] Remove array_zip `[T; N]::zip` is "eager" but most zips are mapped. This causes poor optimization in generated code. This is a fundamental design issue and "zip" is "prime real estate" in terms of function names, so let's free it up again. --- core/src/array/mod.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index fec92320a..76b3589b9 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -538,29 +538,6 @@ impl [T; N] { drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f))) } - /// 'Zips up' two arrays into a single array of pairs. - /// - /// `zip()` returns a new array where every element is a tuple where the - /// first element comes from the first array, and the second element comes - /// from the second array. In other words, it zips two arrays together, - /// into a single one. - /// - /// # Examples - /// - /// ``` - /// #![feature(array_zip)] - /// let x = [1, 2, 3]; - /// let y = [4, 5, 6]; - /// let z = x.zip(y); - /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); - /// ``` - #[unstable(feature = "array_zip", issue = "80094")] - pub fn zip(self, rhs: [U; N]) -> [(T, U); N] { - drain_array_with(self, |lhs| { - drain_array_with(rhs, |rhs| from_trusted_iterator(crate::iter::zip(lhs, rhs))) - }) - } - /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")] From 725eb6650336f014dd8dd8d7bd602928a673e6dd Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 29 May 2023 10:33:37 -0400 Subject: [PATCH 046/180] Swap out CURRENT_RUSTC_VERSION to 1.71.0 --- alloc/src/string.rs | 2 +- core/src/ffi/c_str.rs | 4 ++-- core/src/hash/mod.rs | 2 +- core/src/intrinsics.rs | 2 +- core/src/num/nonzero.rs | 28 ++++++++++++++-------------- core/src/ptr/const_ptr.rs | 4 ++-- core/src/ptr/mod.rs | 4 ++-- core/src/ptr/mut_ptr.rs | 4 ++-- core/src/slice/mod.rs | 2 +- core/src/tuple.rs | 4 ++-- std/src/os/windows/io/handle.rs | 6 +++--- std/src/os/windows/io/socket.rs | 6 +++--- 12 files changed, 34 insertions(+), 34 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index c524d4c03..59e3f887b 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -2624,7 +2624,7 @@ impl ToString for String { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "fmt_arguments_to_string_specialization", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "fmt_arguments_to_string_specialization", since = "1.71.0")] impl ToString for fmt::Arguments<'_> { #[inline] fn to_string(&self) -> String { diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 201bacb28..e1e1a9b40 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -531,8 +531,8 @@ impl CStr { /// # } /// ``` #[inline] - #[stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "cstr_is_empty", since = "1.71.0")] + #[rustc_const_stable(feature = "cstr_is_empty", since = "1.71.0")] pub const fn is_empty(&self) -> bool { // SAFETY: We know there is at least one byte; for empty strings it // is the NUL terminator. diff --git a/core/src/hash/mod.rs b/core/src/hash/mod.rs index ca7c0772d..794a57f09 100644 --- a/core/src/hash/mod.rs +++ b/core/src/hash/mod.rs @@ -695,7 +695,7 @@ pub trait BuildHasher { /// bh.hash_one(&OrderAmbivalentPair(2, 10)) /// ); /// ``` - #[stable(feature = "build_hasher_simple_hash_one", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "build_hasher_simple_hash_one", since = "1.71.0")] fn hash_one(&self, x: T) -> u64 where Self: Sized, diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs index 23ded42fa..f5c5dd29f 100644 --- a/core/src/intrinsics.rs +++ b/core/src/intrinsics.rs @@ -2260,7 +2260,7 @@ extern "rust-intrinsic" { /// 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. - #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[rustc_nounwind] pub fn read_via_copy(ptr: *const T) -> T; diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 38a1c42d9..7f06e170a 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -769,8 +769,8 @@ macro_rules! nonzero_signed_operations { /// ``` #[must_use] #[inline] - #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] pub const fn is_positive(self) -> bool { self.get().is_positive() } @@ -794,8 +794,8 @@ macro_rules! nonzero_signed_operations { /// ``` #[must_use] #[inline] - #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] pub const fn is_negative(self) -> bool { self.get().is_negative() } @@ -819,8 +819,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] pub const fn checked_neg(self) -> Option<$Ty> { if let Some(result) = self.get().checked_neg() { // SAFETY: negation of nonzero cannot yield zero values. @@ -851,8 +851,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] pub const fn overflowing_neg(self) -> ($Ty, bool) { let (result, overflow) = self.get().overflowing_neg(); // SAFETY: negation of nonzero cannot yield zero values. @@ -884,8 +884,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] pub const fn saturating_neg(self) -> $Ty { if let Some(result) = self.checked_neg() { return result; @@ -916,8 +916,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "nonzero_negation_ops", since = "1.71.0")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "1.71.0")] pub const fn wrapping_neg(self) -> $Ty { let result = self.get().wrapping_neg(); // SAFETY: negation of nonzero cannot yield zero values. @@ -925,7 +925,7 @@ macro_rules! nonzero_signed_operations { } } - #[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] impl Neg for $Ty { type Output = $Ty; @@ -937,7 +937,7 @@ macro_rules! nonzero_signed_operations { } forward_ref_unop! { impl Neg, neg for $Ty, - #[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] } )+ } } diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 5ee1b5e4a..6e1e862d3 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -1195,7 +1195,7 @@ impl *const T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(self) -> T @@ -1236,7 +1236,7 @@ impl *const T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(self) -> T diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index ff9fa48f3..d0cb2f715 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -1139,7 +1139,7 @@ pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { /// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(src: *const T) -> T { @@ -1256,7 +1256,7 @@ pub const unsafe fn read(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -#[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[rustc_allow_const_fn_unstable(const_mut_refs, const_maybe_uninit_as_mut_ptr)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(src: *const T) -> T { diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 5edd291fb..2fe5164c3 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -1305,7 +1305,7 @@ impl *mut T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read(self) -> T @@ -1346,7 +1346,7 @@ impl *mut T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_ptr_read", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn read_unaligned(self) -> T diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 62003ddf5..c87af35fb 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -1854,7 +1854,7 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)] #[inline] #[track_caller] diff --git a/core/src/tuple.rs b/core/src/tuple.rs index 172e5fccb..a1388dfee 100644 --- a/core/src/tuple.rs +++ b/core/src/tuple.rs @@ -100,7 +100,7 @@ macro_rules! tuple_impls { } } - #[stable(feature = "array_tuple_conv", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "array_tuple_conv", since = "1.71.0")] impl From<[T; ${count(T)}]> for ($(${ignore(T)} T,)+) { #[inline] #[allow(non_snake_case)] @@ -110,7 +110,7 @@ macro_rules! tuple_impls { } } - #[stable(feature = "array_tuple_conv", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "array_tuple_conv", since = "1.71.0")] impl From<($(${ignore(T)} T,)+)> for [T; ${count(T)}] { #[inline] #[allow(non_snake_case)] diff --git a/std/src/os/windows/io/handle.rs b/std/src/os/windows/io/handle.rs index cbf8209a5..274af08a3 100644 --- a/std/src/os/windows/io/handle.rs +++ b/std/src/os/windows/io/handle.rs @@ -437,7 +437,7 @@ impl AsHandle for &mut T { } } -#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "as_windows_ptrs", since = "1.71.0")] /// This impl allows implementing traits that require `AsHandle` on Arc. /// ``` /// # #[cfg(windows)] mod group_cfg { @@ -457,7 +457,7 @@ impl AsHandle for crate::sync::Arc { } } -#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsHandle for crate::rc::Rc { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { @@ -465,7 +465,7 @@ impl AsHandle for crate::rc::Rc { } } -#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsHandle for Box { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { diff --git a/std/src/os/windows/io/socket.rs b/std/src/os/windows/io/socket.rs index 0c90d55c0..6359835ca 100644 --- a/std/src/os/windows/io/socket.rs +++ b/std/src/os/windows/io/socket.rs @@ -254,7 +254,7 @@ impl AsSocket for &mut T { } } -#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "as_windows_ptrs", since = "1.71.0")] /// This impl allows implementing traits that require `AsSocket` on Arc. /// ``` /// # #[cfg(windows)] mod group_cfg { @@ -274,7 +274,7 @@ impl AsSocket for crate::sync::Arc { } } -#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsSocket for crate::rc::Rc { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { @@ -282,7 +282,7 @@ impl AsSocket for crate::rc::Rc { } } -#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsSocket for Box { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { From 91157c56cb5959515f5fada3058a5fcec9fc8bbe Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 30 May 2023 08:00:10 -0400 Subject: [PATCH 047/180] Bump to latest beta compiler --- alloc/src/alloc.rs | 2 -- core/src/ffi/c_str.rs | 2 +- core/src/ffi/mod.rs | 2 +- core/src/intrinsics.rs | 31 ------------------------------- core/src/marker.rs | 3 +-- core/src/mem/mod.rs | 3 +-- core/src/ptr/const_ptr.rs | 10 +--------- core/src/ptr/mut_ptr.rs | 22 ++-------------------- core/tests/clone.rs | 2 +- core/tests/lib.rs | 2 +- core/tests/mem.rs | 11 +---------- 11 files changed, 10 insertions(+), 80 deletions(-) diff --git a/alloc/src/alloc.rs b/alloc/src/alloc.rs index 01d1fdc9b..8c4f6a73d 100644 --- a/alloc/src/alloc.rs +++ b/alloc/src/alloc.rs @@ -38,7 +38,6 @@ extern "Rust" { #[rustc_nounwind] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; - #[cfg(not(bootstrap))] static __rust_no_alloc_shim_is_unstable: u8; } @@ -96,7 +95,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - #[cfg(not(bootstrap))] core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); __rust_alloc(layout.size(), layout.align()) diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index e1e1a9b40..50c7516b7 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -81,7 +81,7 @@ use crate::str; #[derive(Hash)] #[stable(feature = "core_c_str", since = "1.64.0")] #[rustc_has_incoherent_inherent_impls] -#[cfg_attr(not(bootstrap), lang = "CStr")] +#[lang = "CStr"] // FIXME: // `fn from` in `impl From<&CStr> for Box` current implementation relies // on `CStr` being layout-compatible with `[u8]`. diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index b73abbbac..86ea154a8 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -202,7 +202,7 @@ mod c_long_definition { // would be uninhabited and at least dereferencing such pointers would // be UB. #[doc = include_str!("c_void.md")] -#[cfg_attr(not(bootstrap), lang = "c_void")] +#[lang = "c_void"] #[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435 #[stable(feature = "core_c_void", since = "1.30.0")] pub enum c_void { diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs index f5c5dd29f..6dca1fe1e 100644 --- a/core/src/intrinsics.rs +++ b/core/src/intrinsics.rs @@ -1385,7 +1385,6 @@ extern "rust-intrinsic" { /// /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. - #[cfg(not(bootstrap))] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_nounwind] pub fn transmute_unchecked(src: Src) -> Dst; @@ -1425,19 +1424,11 @@ extern "rust-intrinsic" { /// returned value will result in undefined behavior. /// /// The stabilized version of this intrinsic is [`pointer::offset`]. - #[cfg(not(bootstrap))] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_nounwind] pub fn offset(dst: Ptr, offset: Delta) -> Ptr; - /// The bootstrap version of this is more restricted. - #[cfg(bootstrap)] - #[must_use = "returns a new pointer rather than modifying its argument"] - #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] - #[rustc_nounwind] - pub fn offset(dst: *const T, offset: isize) -> *const T; - /// Calculates the offset from a pointer, potentially wrapping. /// /// This is implemented as an intrinsic to avoid converting to and from an @@ -2270,7 +2261,6 @@ extern "rust-intrinsic" { /// 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(not(bootstrap))] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[rustc_nounwind] pub fn write_via_move(ptr: *mut T, value: T); @@ -2832,24 +2822,3 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { write_bytes(dst, val, count) } } - -/// Polyfill for bootstrap -#[cfg(bootstrap)] -pub const unsafe fn transmute_unchecked(src: Src) -> Dst { - use crate::mem::*; - // SAFETY: It's a transmute -- the caller promised it's fine. - unsafe { transmute_copy(&ManuallyDrop::new(src)) } -} - -/// Polyfill for bootstrap -#[cfg(bootstrap)] -pub const unsafe fn write_via_move(ptr: *mut T, value: T) { - use crate::mem::*; - // SAFETY: the caller must guarantee that `dst` is valid for writes. - // `dst` cannot overlap `src` because the caller has mutable access - // to `dst` while `src` is owned by this function. - unsafe { - copy_nonoverlapping::(&value, ptr, 1); - forget(value); - } -} diff --git a/core/src/marker.rs b/core/src/marker.rs index 8dab8d1a6..2d2d5d491 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -971,7 +971,7 @@ pub trait Tuple {} pub trait PointerLike {} /// A marker for types which can be used as types of `const` generic parameters. -#[cfg_attr(not(bootstrap), lang = "const_param_ty")] +#[lang = "const_param_ty"] #[unstable(feature = "adt_const_params", issue = "95174")] #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy: StructuralEq {} @@ -979,7 +979,6 @@ pub trait ConstParamTy: StructuralEq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] #[unstable(feature = "adt_const_params", issue = "95174")] -#[cfg(not(bootstrap))] pub macro ConstParamTy($item:item) { /* compiler built-in */ } diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index afbfd6d36..39c9a04ee 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -968,7 +968,7 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// Integers and other types implementing [`Copy`] are unaffected by `drop`. /// /// ``` -/// # #![cfg_attr(not(bootstrap), allow(dropping_copy_types))] +/// # #![allow(dropping_copy_types)] /// #[derive(Copy, Clone)] /// struct Foo(u8); /// @@ -1316,7 +1316,6 @@ impl SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` -#[cfg(not(bootstrap))] #[unstable(feature = "offset_of", issue = "106655")] #[allow_internal_unstable(builtin_syntax)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 6e1e862d3..c579c3672 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -916,16 +916,8 @@ impl *const T { where T: Sized, { - #[cfg(bootstrap)] // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - self.offset(count as isize) - } - #[cfg(not(bootstrap))] - // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - intrinsics::offset(self, count) - } + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 2fe5164c3..c6f438578 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -473,20 +473,10 @@ impl *mut T { where T: Sized, { - #[cfg(bootstrap)] // SAFETY: the caller must uphold the safety contract for `offset`. // The obtained pointer is valid for writes since the caller must // guarantee that it points to the same allocated object as `self`. - unsafe { - intrinsics::offset(self, count) as *mut T - } - #[cfg(not(bootstrap))] - // SAFETY: the caller must uphold the safety contract for `offset`. - // The obtained pointer is valid for writes since the caller must - // guarantee that it points to the same allocated object as `self`. - unsafe { - intrinsics::offset(self, count) - } + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer in bytes. @@ -1026,16 +1016,8 @@ impl *mut T { where T: Sized, { - #[cfg(bootstrap)] - // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - self.offset(count as isize) - } - #[cfg(not(bootstrap))] // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - intrinsics::offset(self, count) - } + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). diff --git a/core/tests/clone.rs b/core/tests/clone.rs index aafe5ced2..64193e115 100644 --- a/core/tests/clone.rs +++ b/core/tests/clone.rs @@ -1,5 +1,5 @@ #[test] -#[cfg_attr(not(bootstrap), allow(suspicious_double_ref_op))] +#[allow(suspicious_double_ref_op)] fn test_borrowed_clone() { let x = 5; let y: &i32 = &x; diff --git a/core/tests/lib.rs b/core/tests/lib.rs index 3933e3289..3e6d31fcd 100644 --- a/core/tests/lib.rs +++ b/core/tests/lib.rs @@ -109,7 +109,7 @@ #![feature(utf8_chunks)] #![feature(is_ascii_octdigit)] #![feature(get_many_mut)] -#![cfg_attr(not(bootstrap), feature(offset_of))] +#![feature(offset_of)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] diff --git a/core/tests/mem.rs b/core/tests/mem.rs index aee9c89b5..5c2e18745 100644 --- a/core/tests/mem.rs +++ b/core/tests/mem.rs @@ -366,7 +366,6 @@ fn const_maybe_uninit() { } #[test] -#[cfg(not(bootstrap))] fn offset_of() { #[repr(C)] struct Foo { @@ -391,7 +390,7 @@ fn offset_of() { struct Generic { x: u8, y: u32, - z: T + z: T, } trait Trait {} @@ -409,7 +408,6 @@ fn offset_of() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_union() { #[repr(C)] union Foo { @@ -429,7 +427,6 @@ fn offset_of_union() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_dst() { #[repr(C)] struct Alpha { @@ -469,7 +466,6 @@ fn offset_of_dst() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_packed() { #[repr(C, packed)] struct Foo { @@ -482,7 +478,6 @@ fn offset_of_packed() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_projection() { #[repr(C)] struct Foo { @@ -503,7 +498,6 @@ fn offset_of_projection() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_alias() { #[repr(C)] struct Foo { @@ -518,7 +512,6 @@ fn offset_of_alias() { } #[test] -#[cfg(not(bootstrap))] fn const_offset_of() { #[repr(C)] struct Foo { @@ -534,7 +527,6 @@ fn const_offset_of() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_without_const_promotion() { #[repr(C)] struct Foo { @@ -555,7 +547,6 @@ fn offset_of_without_const_promotion() { } #[test] -#[cfg(not(bootstrap))] fn offset_of_addr() { #[repr(C)] struct Foo { From 6f8cb2e43b84fb26d8dbe46e5c260d8bab6691eb Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 30 May 2023 23:58:20 +0100 Subject: [PATCH 048/180] Explicit set `workspace.resolver = "1"` rust-lang/cargo#10910 starts emitting warning if resolver is not set for 2021 edition package. We want to surpress the warning for now. --- portable-simd/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portable-simd/Cargo.toml b/portable-simd/Cargo.toml index 9802386e4..d1732aaec 100644 --- a/portable-simd/Cargo.toml +++ b/portable-simd/Cargo.toml @@ -1,5 +1,5 @@ [workspace] - +resolver = "1" members = [ "crates/core_simd", "crates/std_float", From 601399c7f6712c2f39f3a334a699294db59761d4 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 17 May 2023 14:54:56 +0200 Subject: [PATCH 049/180] Add diagnostic items for `ptr::cast_mut` and `ptr::from_ref` --- core/src/ptr/const_ptr.rs | 1 + core/src/ptr/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 5ee1b5e4a..5b4fecb15 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -104,6 +104,7 @@ impl *const T { /// refactored. #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_diagnostic_item = "ptr_cast_mut"] #[inline(always)] pub const fn cast_mut(self) -> *mut T { self as _ diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index ff9fa48f3..76a5249ab 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -698,6 +698,7 @@ where #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] +#[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref(r: &T) -> *const T { r } From 39aa19ef3e5d013c6bdbbf9ea29952741d4660f5 Mon Sep 17 00:00:00 2001 From: anna-singleton Date: Wed, 31 May 2023 15:51:28 +0100 Subject: [PATCH 050/180] remove reference to Into in ? operator core/std docs, fix 111655 --- core/src/convert/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/convert/mod.rs b/core/src/convert/mod.rs index 38a6d1ccd..799085e9a 100644 --- a/core/src/convert/mod.rs +++ b/core/src/convert/mod.rs @@ -495,8 +495,7 @@ pub trait Into: Sized { /// By converting underlying error types to our own custom error type that encapsulates the /// underlying error type, we can return a single error type without losing information on the /// underlying cause. The '?' operator automatically converts the underlying error type to our -/// custom error type by calling `Into::into` which is automatically provided when -/// implementing `From`. The compiler then infers which implementation of `Into` should be used. +/// custom error type with `From::from`. /// /// ``` /// use std::fs; From 0fcf54630b1c694e36d3fb05ebf5de5d238d7d21 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 16 May 2023 19:37:26 +0300 Subject: [PATCH 051/180] use c literals in library --- std/src/lib.rs | 1 + std/src/sys/unix/args.rs | 12 ++++++------ std/src/sys/unix/fs.rs | 2 +- std/src/sys/unix/mod.rs | 7 +++---- std/src/sys/unix/process/process_common.rs | 9 ++++----- std/src/sys/unix/thread.rs | 3 +-- std/src/sys/windows/c.rs | 4 ++-- std/src/sys/windows/compat.rs | 6 +++--- std/src/sys/windows/mod.rs | 4 ++-- 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/std/src/lib.rs b/std/src/lib.rs index 318a46d1b..d53f1a2b2 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -240,6 +240,7 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] +#![feature(c_str_literals)] #![feature(c_unwind)] #![feature(cfg_target_thread_local)] #![feature(concat_idents)] diff --git a/std/src/sys/unix/args.rs b/std/src/sys/unix/args.rs index 9ed4d9c1e..1e4c24452 100644 --- a/std/src/sys/unix/args.rs +++ b/std/src/sys/unix/args.rs @@ -242,13 +242,13 @@ mod imp { let mut res = Vec::new(); unsafe { - let process_info_sel = sel_registerName("processInfo\0".as_ptr()); - let arguments_sel = sel_registerName("arguments\0".as_ptr()); - let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); - let count_sel = sel_registerName("count\0".as_ptr()); - let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); + let process_info_sel = sel_registerName(c"processInfo".as_ptr()); + let arguments_sel = sel_registerName(c"arguments".as_ptr()); + let utf8_sel = sel_registerName(c"UTF8String".as_ptr()); + let count_sel = sel_registerName(c"count".as_ptr()); + let object_at_sel = sel_registerName(c"objectAtIndex:".as_ptr()); - let klass = objc_getClass("NSProcessInfo\0".as_ptr()); + let klass = objc_getClass(c"NSProcessInfo".as_ptr()); let info = objc_msgSend(klass, process_info_sel); let args = objc_msgSend(info, arguments_sel); diff --git a/std/src/sys/unix/fs.rs b/std/src/sys/unix/fs.rs index 09e9ae272..0e5691d40 100644 --- a/std/src/sys/unix/fs.rs +++ b/std/src/sys/unix/fs.rs @@ -1063,7 +1063,7 @@ impl File { cfg_has_statx! { if let Some(ret) = unsafe { try_statx( fd, - b"\0" as *const _ as *const c_char, + c"".as_ptr() as *const c_char, libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, libc::STATX_ALL, ) } { diff --git a/std/src/sys/unix/mod.rs b/std/src/sys/unix/mod.rs index bb9e65e68..54e2f20b3 100644 --- a/std/src/sys/unix/mod.rs +++ b/std/src/sys/unix/mod.rs @@ -1,6 +1,5 @@ #![allow(missing_docs, nonstandard_style)] -use crate::ffi::CStr; use crate::io::ErrorKind; pub use self::rand::hashmap_random_keys; @@ -75,7 +74,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // thread-id for the main thread and so renaming the main thread will rename the // process and we only want to enable this on platforms we've tested. if cfg!(target_os = "macos") { - thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0")); + thread::Thread::set_name(&c"main"); } unsafe fn sanitize_standard_fds() { @@ -121,7 +120,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { if pfd.revents & libc::POLLNVAL == 0 { continue; } - if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or @@ -151,7 +150,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { use libc::open64; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or diff --git a/std/src/sys/unix/process/process_common.rs b/std/src/sys/unix/process/process_common.rs index 640648e87..5f316b12b 100644 --- a/std/src/sys/unix/process/process_common.rs +++ b/std/src/sys/unix/process/process_common.rs @@ -24,11 +24,11 @@ cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { - const DEV_NULL: &str = "null:\0"; + const DEV_NULL: &CStr = c"null:"; } else if #[cfg(target_os = "vxworks")] { - const DEV_NULL: &str = "/null\0"; + const DEV_NULL: &CStr = c"/null"; } else { - const DEV_NULL: &str = "/dev/null\0"; + const DEV_NULL: &CStr = c"/dev/null"; } } @@ -474,8 +474,7 @@ impl Stdio { let mut opts = OpenOptions::new(); opts.read(readable); opts.write(!readable); - let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) }; - let fd = File::open_c(&path, &opts)?; + let fd = File::open_c(DEV_NULL, &opts)?; Ok((ChildStdio::Owned(fd.into_inner()), None)) } diff --git a/std/src/sys/unix/thread.rs b/std/src/sys/unix/thread.rs index 7307d9b2c..878af5088 100644 --- a/std/src/sys/unix/thread.rs +++ b/std/src/sys/unix/thread.rs @@ -163,10 +163,9 @@ impl Thread { #[cfg(target_os = "netbsd")] pub fn set_name(name: &CStr) { unsafe { - let cname = CStr::from_bytes_with_nul_unchecked(b"%s\0".as_slice()); let res = libc::pthread_setname_np( libc::pthread_self(), - cname.as_ptr(), + c"%s".as_ptr(), name.as_ptr() as *mut libc::c_void, ); debug_assert_eq!(res, 0); diff --git a/std/src/sys/windows/c.rs b/std/src/sys/windows/c.rs index 2bc40c474..07b0610d4 100644 --- a/std/src/sys/windows/c.rs +++ b/std/src/sys/windows/c.rs @@ -317,7 +317,7 @@ pub unsafe fn NtWriteFile( // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { - pub static KERNEL32: &CStr = ansi_str!("kernel32"); + pub static KERNEL32: &CStr = c"kernel32"; // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription @@ -350,7 +350,7 @@ compat_fn_optional! { } compat_fn_with_fallback! { - pub static NTDLL: &CStr = ansi_str!("ntdll"); + pub static NTDLL: &CStr = c"ntdll"; pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, diff --git a/std/src/sys/windows/compat.rs b/std/src/sys/windows/compat.rs index 4fe95d411..649cc4bfd 100644 --- a/std/src/sys/windows/compat.rs +++ b/std/src/sys/windows/compat.rs @@ -228,9 +228,9 @@ macro_rules! compat_fn_optional { /// Load all needed functions from "api-ms-win-core-synch-l1-2-0". pub(super) fn load_synch_functions() { fn try_load() -> Option<()> { - const MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); - const WAIT_ON_ADDRESS: &CStr = ansi_str!("WaitOnAddress"); - const WAKE_BY_ADDRESS_SINGLE: &CStr = ansi_str!("WakeByAddressSingle"); + const MODULE_NAME: &CStr = c"api-ms-win-core-synch-l1-2-0"; + const WAIT_ON_ADDRESS: &CStr = c"WaitOnAddress"; + const WAKE_BY_ADDRESS_SINGLE: &CStr = c"WakeByAddressSingle"; // Try loading the library and all the required functions. // If any step fails, then they all fail. diff --git a/std/src/sys/windows/mod.rs b/std/src/sys/windows/mod.rs index bcc172b0f..b11c89622 100644 --- a/std/src/sys/windows/mod.rs +++ b/std/src/sys/windows/mod.rs @@ -1,6 +1,6 @@ #![allow(missing_docs, nonstandard_style)] -use crate::ffi::{CStr, OsStr, OsString}; +use crate::ffi::{OsStr, OsString}; use crate::io::ErrorKind; use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; @@ -51,7 +51,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already // exists, we have to call it ourselves. - thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0")); + thread::Thread::set_name(&c"main"); } // SAFETY: must be called only once during runtime cleanup. From e101f9ec335b168a43dc4c5f28058ed94cead7f8 Mon Sep 17 00:00:00 2001 From: Shane Murphy Date: Wed, 31 May 2023 17:22:44 -0700 Subject: [PATCH 052/180] Fix bug in utf16_to_utf8 for zero length strings This fixes the behavior of sending EOF by pressing Ctrl+Z => Enter in a windows console. Previously, that would trip the unpaired surrogate error, whereas now we correctly detect EOF. --- std/src/sys/windows/stdio.rs | 7 +++++++ std/src/sys/windows/stdio/tests.rs | 6 ++++++ 2 files changed, 13 insertions(+) create mode 100644 std/src/sys/windows/stdio/tests.rs diff --git a/std/src/sys/windows/stdio.rs b/std/src/sys/windows/stdio.rs index 2e3e0859d..3fcaaa508 100644 --- a/std/src/sys/windows/stdio.rs +++ b/std/src/sys/windows/stdio.rs @@ -11,6 +11,9 @@ use crate::sys::cvt; use crate::sys::handle::Handle; use core::str::utf8_char_width; +#[cfg(test)] +mod tests; + // Don't cache handles but get them fresh for every read/write. This allows us to track changes to // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490. pub struct Stdin { @@ -383,6 +386,10 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { debug_assert!(utf16.len() <= c::c_int::MAX as usize); debug_assert!(utf8.len() <= c::c_int::MAX as usize); + if utf16.is_empty() { + return Ok(0); + } + let result = unsafe { c::WideCharToMultiByte( c::CP_UTF8, // CodePage diff --git a/std/src/sys/windows/stdio/tests.rs b/std/src/sys/windows/stdio/tests.rs new file mode 100644 index 000000000..1e53e0bee --- /dev/null +++ b/std/src/sys/windows/stdio/tests.rs @@ -0,0 +1,6 @@ +use super::utf16_to_utf8; + +#[test] +fn zero_size_read() { + assert_eq!(utf16_to_utf8(&[], &mut []).unwrap(), 0); +} From ac00fcc07fda31cad870437ef723e8e86d23e1a5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 1 Jun 2023 12:55:58 +0200 Subject: [PATCH 053/180] doc: improve explanation --- std/src/sync/once.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sync/once.rs b/std/src/sync/once.rs index 1b17c3108..8c46080e4 100644 --- a/std/src/sync/once.rs +++ b/std/src/sync/once.rs @@ -91,7 +91,7 @@ impl Once { /// return). /// /// If the given closure recursively invokes `call_once` on the same [`Once`] - /// instance the exact behavior is not specified, allowed outcomes are + /// instance, the exact behavior is not specified: allowed outcomes are /// a panic or a deadlock. /// /// # Examples From de0d0cc39f0366ed08098a6cf52c579fdfd08044 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 16 May 2023 19:58:54 +0100 Subject: [PATCH 054/180] Require that const param tys implement ConstParamTy --- core/src/mem/transmutability.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/mem/transmutability.rs b/core/src/mem/transmutability.rs index 87ae30619..a6f792ed0 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -1,3 +1,5 @@ +use crate::marker::ConstParamTy; + /// Are values of a type transmutable into values of another type? /// /// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of @@ -33,6 +35,9 @@ pub struct Assume { pub validity: bool, } +#[unstable(feature = "transmutability", issue = "99571")] +impl ConstParamTy for Assume {} + impl Assume { /// Do not assume that *you* have ensured any safety properties are met. #[unstable(feature = "transmutability", issue = "99571")] From 047d3eddc96ae4acb3d9368afafa7ad17b57e868 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 17 May 2023 03:00:19 +0000 Subject: [PATCH 055/180] Impl ConstParamTy for tuples, make PartialStructuralEq a supertrait too --- core/src/marker.rs | 26 +++++++++++++++++++++++--- core/src/tuple.rs | 25 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index 2d2d5d491..9a541ccae 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -205,6 +205,20 @@ pub trait StructuralPartialEq { // Empty. } +marker_impls! { + #[unstable(feature = "structural_match", issue = "31434")] + StructuralPartialEq for + usize, u8, u16, u32, u64, u128, + isize, i8, i16, i32, i64, i128, + bool, + char, + str /* Technically requires `[u8]: StructuralEq` */, + (), + {T, const N: usize} [T; N], + {T} [T], + {T: ?Sized} &T, +} + /// Required trait for constants used in pattern matches. /// /// Any type that derives `Eq` automatically implements this trait, *regardless* @@ -267,6 +281,7 @@ marker_impls! { bool, char, str /* Technically requires `[u8]: StructuralEq` */, + (), {T, const N: usize} [T; N], {T} [T], {T: ?Sized} &T, @@ -974,7 +989,8 @@ pub trait PointerLike {} #[lang = "const_param_ty"] #[unstable(feature = "adt_const_params", issue = "95174")] #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] -pub trait ConstParamTy: StructuralEq {} +#[allow(multiple_supertrait_upcastable)] +pub trait ConstParamTy: StructuralEq + StructuralPartialEq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] @@ -983,8 +999,7 @@ pub macro ConstParamTy($item:item) { /* compiler built-in */ } -// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure` -// FIXME(generic_const_parameter_types): handle `ty::Tuple` +// FIXME(adt_const_params): handle `ty::FnDef`/`ty::Closure` marker_impls! { #[unstable(feature = "adt_const_params", issue = "95174")] ConstParamTy for @@ -998,6 +1013,11 @@ marker_impls! { {T: ?Sized + ConstParamTy} &T, } +// FIXME(adt_const_params): Add to marker_impls call above once not in bootstrap +#[unstable(feature = "adt_const_params", issue = "95174")] +#[cfg(not(bootstrap))] +impl ConstParamTy for () {} + /// A common trait implemented by all function pointers. #[unstable( feature = "fn_ptr_trait", diff --git a/core/src/tuple.rs b/core/src/tuple.rs index a1388dfee..ac8d04a82 100644 --- a/core/src/tuple.rs +++ b/core/src/tuple.rs @@ -1,6 +1,9 @@ // See src/libstd/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; +#[cfg(not(bootstrap))] +use crate::marker::ConstParamTy; +use crate::marker::{StructuralEq, StructuralPartialEq}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -45,6 +48,28 @@ macro_rules! tuple_impls { {} } + maybe_tuple_doc! { + $($T)+ @ + #[unstable(feature = "structural_match", issue = "31434")] + #[cfg(not(bootstrap))] + impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) + {} + } + + maybe_tuple_doc! { + $($T)+ @ + #[unstable(feature = "structural_match", issue = "31434")] + impl<$($T),+> StructuralPartialEq for ($($T,)+) + {} + } + + maybe_tuple_doc! { + $($T)+ @ + #[unstable(feature = "structural_match", issue = "31434")] + impl<$($T),+> StructuralEq for ($($T,)+) + {} + } + maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] From 9b3bf4187cf8a677a02e1f9d1b031399ba9d1284 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Feb 2023 00:07:32 -0500 Subject: [PATCH 056/180] Stabilize 'const_cstr_methods' --- core/src/ffi/c_str.rs | 17 ++++++++++------- core/src/lib.rs | 1 - 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 50c7516b7..3de9188ba 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -241,7 +241,7 @@ impl CStr { /// ``` /// /// ``` - /// #![feature(const_cstr_methods)] + /// #![feature(const_cstr_from_ptr)] /// /// use std::ffi::{c_char, CStr}; /// @@ -256,7 +256,7 @@ impl CStr { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "101719")] pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C // string with a NUL terminator of size less than `isize::MAX`, whose @@ -377,7 +377,7 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")] pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { @@ -561,10 +561,12 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes(&self) -> &[u8] { + #[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")] + pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); + // FIXME(const-hack) replace with range index // SAFETY: to_bytes_with_nul returns slice with length at least 1 - unsafe { bytes.get_unchecked(..bytes.len() - 1) } + unsafe { slice::from_raw_parts(bytes.as_ptr(), bytes.len() - 1) } } /// Converts this C string to a byte slice containing the trailing 0 byte. @@ -588,7 +590,7 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")] pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. @@ -612,7 +614,8 @@ impl CStr { /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_str(&self) -> Result<&str, str::Utf8Error> { + #[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")] + pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should // be rewritten to do the UTF-8 check inline with the length calculation diff --git a/core/src/lib.rs b/core/src/lib.rs index 6c419eb16..05876f5fc 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -113,7 +113,6 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_from_u32_unchecked)] -#![feature(const_cstr_methods)] #![feature(const_discriminant)] #![feature(const_eval_select)] #![feature(const_exact_div)] From cad170c2dfe99aeb4ad40e00ccc39e9b4db10691 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 2 Jun 2023 11:26:34 +0300 Subject: [PATCH 057/180] fix ptr cast --- std/src/sys/unix/args.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/std/src/sys/unix/args.rs b/std/src/sys/unix/args.rs index 1e4c24452..0efe2570d 100644 --- a/std/src/sys/unix/args.rs +++ b/std/src/sys/unix/args.rs @@ -242,13 +242,15 @@ mod imp { let mut res = Vec::new(); unsafe { - let process_info_sel = sel_registerName(c"processInfo".as_ptr()); - let arguments_sel = sel_registerName(c"arguments".as_ptr()); - let utf8_sel = sel_registerName(c"UTF8String".as_ptr()); - let count_sel = sel_registerName(c"count".as_ptr()); - let object_at_sel = sel_registerName(c"objectAtIndex:".as_ptr()); - - let klass = objc_getClass(c"NSProcessInfo".as_ptr()); + let process_info_sel = + sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar); + let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar); + let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar); + let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar); + let object_at_sel = + sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar); + + let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar); let info = objc_msgSend(klass, process_info_sel); let args = objc_msgSend(info, arguments_sel); From 492faec29a11d078c0af8ce9c314e52180cdcb98 Mon Sep 17 00:00:00 2001 From: Kourosh Date: Fri, 2 Jun 2023 15:30:40 +0330 Subject: [PATCH 058/180] Fix typo in `std::cell` module docs --- core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/cell.rs b/core/src/cell.rs index 744767aae..c1cc892eb 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -59,7 +59,7 @@ //! [`borrow`](`RefCell::borrow`), and a mutable borrow (`&mut T`) can be obtained with //! [`borrow_mut`](`RefCell::borrow_mut`). When these functions are called, they first verify that //! Rust's borrow rules will be satisfied: any number of immutable borrows are allowed or a -//! single immutable borrow is allowed, but never both. If a borrow is attempted that would violate +//! single mutable borrow is allowed, but never both. If a borrow is attempted that would violate //! these rules, the thread will panic. //! //! The corresponding [`Sync`] version of `RefCell` is [`RwLock`]. From 04efffd10289d6a759af08cbed9912dbc362a189 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Sat, 18 Mar 2023 18:45:51 +0100 Subject: [PATCH 059/180] Retry to fork/spawn with exponential backoff --- std/src/sys/unix/process/process_unix.rs | 54 +++++++++++++++++++----- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/std/src/sys/unix/process/process_unix.rs b/std/src/sys/unix/process/process_unix.rs index 612d43fe2..f68f25419 100644 --- a/std/src/sys/unix/process/process_unix.rs +++ b/std/src/sys/unix/process/process_unix.rs @@ -35,8 +35,20 @@ cfg_if::cfg_if! { if #[cfg(all(target_os = "nto", target_env = "nto71"))] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; - // arbitrary number of tries: - const MAX_FORKSPAWN_TRIES: u32 = 4; + use crate::time::Duration; + // Get smallest amount of time we can sleep. + // Return a common value if it cannot be determined. + fn get_clock_resolution() -> Duration { + let mut mindelay = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + if unsafe { libc::clock_getres(libc::CLOCK_MONOTONIC, &mut mindelay) } == 0 + { + Duration::from_nanos(mindelay.tv_nsec as u64) + } else { + Duration::from_millis(1) + } + } + // Arbitrary minimum sleep duration for retrying fork/spawn + const MIN_FORKSPAWN_SLEEP: Duration = Duration::from_nanos(1); } } @@ -163,12 +175,24 @@ impl Command { unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { use crate::sys::os::errno; - let mut tries_left = MAX_FORKSPAWN_TRIES; + let mut minimum_delay = None; + let mut delay = MIN_FORKSPAWN_SLEEP; + loop { let r = libc::fork(); - if r == -1 as libc::pid_t && tries_left > 0 && errno() as libc::c_int == libc::EBADF { - thread::yield_now(); - tries_left -= 1; + if r == -1 as libc::pid_t && errno() as libc::c_int == libc::EBADF { + if minimum_delay.is_none() { + minimum_delay = Some(get_clock_resolution()); + } + if delay < minimum_delay.unwrap() { + // We cannot sleep this short (it would be longer). + // Yield instead. + thread::yield_now(); + } else { + thread::sleep(delay); + } + delay *= 2; + continue; } else { return cvt(r).map(|res| (res, -1)); } @@ -481,12 +505,22 @@ impl Command { argv: *const *mut c_char, envp: *const *mut c_char, ) -> i32 { - let mut tries_left = MAX_FORKSPAWN_TRIES; + let mut minimum_delay = None; + let mut delay = MIN_FORKSPAWN_SLEEP; loop { match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) { - libc::EBADF if tries_left > 0 => { - thread::yield_now(); - tries_left -= 1; + libc::EBADF => { + if minimum_delay.is_none() { + minimum_delay = Some(get_clock_resolution()); + } + if delay < minimum_delay.unwrap() { + // We cannot sleep this short (it would be longer). + // Yield instead. + thread::yield_now(); + } else { + thread::sleep(delay); + } + delay *= 2; continue; } r => { From a97184c9d772cfbba0c0d48864506cb088390329 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Fri, 2 Jun 2023 17:52:14 +0200 Subject: [PATCH 060/180] Only determine clock res once; give up before sleeping more than 1 second --- std/src/sys/unix/process/process_unix.rs | 60 +++++++++++++++--------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/std/src/sys/unix/process/process_unix.rs b/std/src/sys/unix/process/process_unix.rs index f68f25419..3721988b4 100644 --- a/std/src/sys/unix/process/process_unix.rs +++ b/std/src/sys/unix/process/process_unix.rs @@ -36,19 +36,25 @@ cfg_if::cfg_if! { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; + use crate::sync::LazyLock; // Get smallest amount of time we can sleep. // Return a common value if it cannot be determined. fn get_clock_resolution() -> Duration { - let mut mindelay = libc::timespec { tv_sec: 0, tv_nsec: 0 }; - if unsafe { libc::clock_getres(libc::CLOCK_MONOTONIC, &mut mindelay) } == 0 - { - Duration::from_nanos(mindelay.tv_nsec as u64) - } else { - Duration::from_millis(1) - } + static MIN_DELAY: LazyLock Duration> = LazyLock::new(|| { + let mut mindelay = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + if unsafe { libc::clock_getres(libc::CLOCK_MONOTONIC, &mut mindelay) } == 0 + { + Duration::from_nanos(mindelay.tv_nsec as u64) + } else { + Duration::from_millis(1) + } + }); + *MIN_DELAY } // Arbitrary minimum sleep duration for retrying fork/spawn const MIN_FORKSPAWN_SLEEP: Duration = Duration::from_nanos(1); + // Maximum duration of sleeping before giving up and returning an error + const MAX_FORKSPAWN_SLEEP: Duration = Duration::from_millis(1000); } } @@ -175,21 +181,22 @@ impl Command { unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { use crate::sys::os::errno; - let mut minimum_delay = None; let mut delay = MIN_FORKSPAWN_SLEEP; loop { let r = libc::fork(); if r == -1 as libc::pid_t && errno() as libc::c_int == libc::EBADF { - if minimum_delay.is_none() { - minimum_delay = Some(get_clock_resolution()); - } - if delay < minimum_delay.unwrap() { + if delay < get_clock_resolution() { // We cannot sleep this short (it would be longer). // Yield instead. thread::yield_now(); - } else { + } else if delay < MAX_FORKSPAWN_SLEEP { thread::sleep(delay); + } else { + return Err(io::const_io_error!( + ErrorKind::WouldBlock, + "forking returned EBADF too often", + )); } delay *= 2; continue; @@ -504,27 +511,28 @@ impl Command { attrp: *const posix_spawnattr_t, argv: *const *mut c_char, envp: *const *mut c_char, - ) -> i32 { - let mut minimum_delay = None; + ) -> io::Result { let mut delay = MIN_FORKSPAWN_SLEEP; loop { match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) { libc::EBADF => { - if minimum_delay.is_none() { - minimum_delay = Some(get_clock_resolution()); - } - if delay < minimum_delay.unwrap() { + if delay < get_clock_resolution() { // We cannot sleep this short (it would be longer). // Yield instead. thread::yield_now(); - } else { + } else if delay < MAX_FORKSPAWN_SLEEP { thread::sleep(delay); + } else { + return Err(io::const_io_error!( + ErrorKind::WouldBlock, + "posix_spawnp returned EBADF too often", + )); } delay *= 2; continue; } r => { - return r; + return Ok(r); } } } @@ -654,14 +662,20 @@ impl Command { let spawn_fn = libc::posix_spawnp; #[cfg(target_os = "nto")] let spawn_fn = retrying_libc_posix_spawnp; - cvt_nz(spawn_fn( + + let spawn_res = spawn_fn( &mut p.pid, self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, envp as *const _, - ))?; + ); + + #[cfg(target_os = "nto")] + let spawn_res = spawn_res?; + + cvt_nz(spawn_res)?; Ok(Some(p)) } } From ec43acc34c4fb69eef106b744cac15eec719efc9 Mon Sep 17 00:00:00 2001 From: Grisha Vartanyan Date: Sun, 4 Jun 2023 08:06:25 +0200 Subject: [PATCH 061/180] Remove ExtendWith and ExtendElement --- alloc/src/vec/mod.rs | 30 +++++++----------------------- alloc/src/vec/spec_from_elem.rs | 6 +++--- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 47661a3d3..d89cdff8e 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2355,7 +2355,7 @@ impl Vec { let len = self.len(); if new_len > len { - self.extend_with(new_len - len, ExtendElement(value)) + self.extend_with(new_len - len, value) } else { self.truncate(new_len); } @@ -2469,26 +2469,10 @@ impl Vec<[T; N], A> { } } -// This code generalizes `extend_with_{element,default}`. -trait ExtendWith { - fn next(&mut self) -> T; - fn last(self) -> T; -} - -struct ExtendElement(T); -impl ExtendWith for ExtendElement { - fn next(&mut self) -> T { - self.0.clone() - } - fn last(self) -> T { - self.0 - } -} - -impl Vec { +impl Vec { #[cfg(not(no_global_oom_handling))] - /// Extend the vector by `n` values, using the given generator. - fn extend_with>(&mut self, n: usize, mut value: E) { + /// Extend the vector by `n` clones of value. + fn extend_with(&mut self, n: usize, value: T) { self.reserve(n); unsafe { @@ -2500,15 +2484,15 @@ impl Vec { // Write all elements except the last one for _ in 1..n { - ptr::write(ptr, value.next()); + ptr::write(ptr, value.clone()); ptr = ptr.add(1); - // Increment the length in every step in case next() panics + // Increment the length in every step in case clone() panics local_len.increment_len(1); } if n > 0 { // We can write the last element directly without cloning needlessly - ptr::write(ptr, value.last()); + ptr::write(ptr, value); local_len.increment_len(1); } diff --git a/alloc/src/vec/spec_from_elem.rs b/alloc/src/vec/spec_from_elem.rs index ff364c033..da43d17bf 100644 --- a/alloc/src/vec/spec_from_elem.rs +++ b/alloc/src/vec/spec_from_elem.rs @@ -3,7 +3,7 @@ use core::ptr; use crate::alloc::Allocator; use crate::raw_vec::RawVec; -use super::{ExtendElement, IsZero, Vec}; +use super::{IsZero, Vec}; // Specialization trait used for Vec::from_elem pub(super) trait SpecFromElem: Sized { @@ -13,7 +13,7 @@ pub(super) trait SpecFromElem: Sized { impl SpecFromElem for T { default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); + v.extend_with(n, elem); v } } @@ -25,7 +25,7 @@ impl SpecFromElem for T { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); + v.extend_with(n, elem); v } } From 62329cfae79045e72bbff95dc4a661fe34a7e728 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 4 Apr 2023 17:55:20 -0700 Subject: [PATCH 062/180] Use 128 bits for TypeId hash - Switch TypeId to 128 bits - Hack around the fact that tracing-subscriber dislikes how TypeId is hashed - Remove lowering of type_id128 from rustc_codegen_llvm - Remove unnecessary `type_id128` intrinsic (just change return type of `type_id`) - Only hash the lower 64 bits of the TypeId - Reword comment --- core/src/any.rs | 31 ++++++++++++++++++++++++++++--- core/src/intrinsics.rs | 17 +++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/core/src/any.rs b/core/src/any.rs index 7969f4055..89c613aef 100644 --- a/core/src/any.rs +++ b/core/src/any.rs @@ -153,6 +153,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fmt; +use crate::hash; use crate::intrinsics; /////////////////////////////////////////////////////////////////////////////// @@ -662,10 +663,10 @@ impl dyn Any + Send + Sync { /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware /// of relying on them inside of your code! -#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { - t: u64, + t: u128, } #[stable(feature = "rust1", since = "1.0.0")] @@ -696,7 +697,31 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of() -> TypeId { - TypeId { t: intrinsics::type_id::() } + #[cfg(bootstrap)] + let t = intrinsics::type_id::() as u128; + #[cfg(not(bootstrap))] + let t: u128 = intrinsics::type_id::(); + TypeId { t } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for TypeId { + #[inline] + fn hash(&self, state: &mut H) { + // We only hash the lower 64 bits of our (128 bit) internal numeric ID, + // because: + // - The hashing algorithm which backs `TypeId` is expected to be + // unbiased and high quality, meaning further mixing would be somewhat + // redundant compared to choosing (the lower) 64 bits arbitrarially. + // - `Hasher::finish` returns a u64 anyway, so the extra entropy we'd + // get from hashing the full value would probably not be useful + // (especially given the previous point about the lower 64 bits being + // high quality on their own). + // - It is correct to do so -- only hashing a subset of `self` is still + // with an `Eq` implementation that considers the entire value, as + // ours does. + (self.t as u64).hash(state); } } diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs index 6dca1fe1e..9b8612485 100644 --- a/core/src/intrinsics.rs +++ b/core/src/intrinsics.rs @@ -1057,8 +1057,25 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] #[rustc_safe_intrinsic] #[rustc_nounwind] + #[cfg(bootstrap)] pub fn type_id() -> u64; + /// Gets an identifier which is globally unique to the specified type. This + /// function will return the same value for a type regardless of whichever + /// crate it is invoked in. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. + #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] + #[rustc_safe_intrinsic] + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn type_id() -> u128; + /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: /// This will statically either panic, or do nothing. /// From 7d30c629006b8cc9e90dad4a355d1312a9267e60 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 14:54:28 -0700 Subject: [PATCH 063/180] Avoid unwind across `extern "C"` in `thread_local::fast_local.rs` --- std/src/sys/common/thread_local/fast_local.rs | 22 +++++++++---------- std/src/sys/common/thread_local/mod.rs | 21 ++++++++++++++++++ std/src/thread/mod.rs | 2 +- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/std/src/sys/common/thread_local/fast_local.rs b/std/src/sys/common/thread_local/fast_local.rs index 447044a79..bc5da1a18 100644 --- a/std/src/sys/common/thread_local/fast_local.rs +++ b/std/src/sys/common/thread_local/fast_local.rs @@ -33,20 +33,21 @@ pub macro thread_local_inner { // 1 == dtor registered, dtor not run // 2 == dtor registered and is running or has run #[thread_local] - static mut STATE: $crate::primitive::u8 = 0; + static STATE: $crate::cell::Cell<$crate::primitive::u8> = $crate::cell::Cell::new(0); + // Safety: Performs `drop_in_place(ptr as *mut $t)`, and requires + // all that comes with it. unsafe extern "C" fn destroy(ptr: *mut $crate::primitive::u8) { - let ptr = ptr as *mut $t; - - unsafe { - $crate::debug_assert_eq!(STATE, 1); - STATE = 2; - $crate::ptr::drop_in_place(ptr); - } + $crate::thread::local_impl::abort_on_dtor_unwind(|| { + let old_state = STATE.replace(2); + $crate::debug_assert_eq!(old_state, 1); + // Safety: safety requirement is passed on to caller. + unsafe { $crate::ptr::drop_in_place(ptr.cast::<$t>()); } + }); } unsafe { - match STATE { + match STATE.get() { // 0 == we haven't registered a destructor, so do // so now. 0 => { @@ -54,7 +55,7 @@ pub macro thread_local_inner { $crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8, destroy, ); - STATE = 1; + STATE.set(1); $crate::option::Option::Some(&VAL) } // 1 == the destructor is registered and the value @@ -148,7 +149,6 @@ impl fmt::Debug for Key { f.debug_struct("Key").finish_non_exhaustive() } } - impl Key { pub const fn new() -> Key { Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) } diff --git a/std/src/sys/common/thread_local/mod.rs b/std/src/sys/common/thread_local/mod.rs index 77f645883..975509bd4 100644 --- a/std/src/sys/common/thread_local/mod.rs +++ b/std/src/sys/common/thread_local/mod.rs @@ -101,3 +101,24 @@ mod lazy { } } } + +/// Run a callback in a scenario which must not unwind (such as a `extern "C" +/// fn` declared in a user crate). If the callback unwinds anyway, then +/// `rtabort` with a message about thread local panicking on drop. +#[inline] +pub fn abort_on_dtor_unwind(f: impl FnOnce()) { + // Using a guard like this is lower cost. + let guard = DtorUnwindGuard; + f(); + core::mem::forget(guard); + + struct DtorUnwindGuard; + impl Drop for DtorUnwindGuard { + #[inline] + fn drop(&mut self) { + // This is not terribly descriptive, but it doesn't need to be as we'll + // already have printed a panic message at this point. + rtabort!("thread local panicked on drop"); + } + } +} diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index f712c8727..d9973185b 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -206,7 +206,7 @@ cfg_if::cfg_if! { #[doc(hidden)] #[unstable(feature = "thread_local_internals", issue = "none")] pub mod local_impl { - pub use crate::sys::common::thread_local::{thread_local_inner, Key}; + pub use crate::sys::common::thread_local::{thread_local_inner, Key, abort_on_dtor_unwind}; } } } From c88e92d241e3ab04f5150d3a3f0bf31d33c35336 Mon Sep 17 00:00:00 2001 From: Nikolay Arhipov Date: Sun, 4 Jun 2023 17:44:43 +0300 Subject: [PATCH 064/180] Std support improvement for ps vita target --- std/Cargo.toml | 2 +- std/src/os/unix/process.rs | 2 +- std/src/sys/unix/fd.rs | 11 ++++--- std/src/sys/unix/fs.rs | 37 ++++++++++++++++++++-- std/src/sys/unix/mod.rs | 12 +++---- std/src/sys/unix/net.rs | 11 ++++++- std/src/sys/unix/thread_parking/pthread.rs | 3 +- 7 files changed, 59 insertions(+), 19 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 72d910bf9..74b61db0c 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 } -libc = { version = "0.2.143", default-features = false, features = ['rustc-dep-of-std'], public = true } +libc = { version = "0.2.145", default-features = false, features = ['rustc-dep-of-std'], public = true } compiler_builtins = { version = "0.1.92" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/std/src/os/unix/process.rs b/std/src/os/unix/process.rs index 729c63d18..2b40b672d 100644 --- a/std/src/os/unix/process.rs +++ b/std/src/os/unix/process.rs @@ -15,7 +15,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use cfg_if::cfg_if; cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] { + if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita"))] { type UserId = u16; type GroupId = u16; } else if #[cfg(target_os = "nto")] { diff --git a/std/src/sys/unix/fd.rs b/std/src/sys/unix/fd.rs index cb630eede..69c93c920 100644 --- a/std/src/sys/unix/fd.rs +++ b/std/src/sys/unix/fd.rs @@ -402,7 +402,10 @@ impl FileDesc { } } #[cfg(any( - all(target_env = "newlib", not(any(target_os = "espidf", target_os = "horizon"))), + all( + target_env = "newlib", + not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")) + ), target_os = "solaris", target_os = "illumos", target_os = "emscripten", @@ -424,10 +427,10 @@ impl FileDesc { Ok(()) } } - #[cfg(any(target_os = "espidf", target_os = "horizon"))] + #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] pub fn set_cloexec(&self) -> io::Result<()> { - // FD_CLOEXEC is not supported in ESP-IDF and Horizon OS but there's no need to, - // because neither supports spawning processes. + // FD_CLOEXEC is not supported in ESP-IDF, Horizon OS and Vita but there's no need to, + // because none of them supports spawning processes. Ok(()) } diff --git a/std/src/sys/unix/fs.rs b/std/src/sys/unix/fs.rs index 0e5691d40..d2fb62383 100644 --- a/std/src/sys/unix/fs.rs +++ b/std/src/sys/unix/fs.rs @@ -15,6 +15,7 @@ use crate::mem; target_os = "redox", target_os = "illumos", target_os = "nto", + target_os = "vita", ))] use crate::mem::MaybeUninit; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; @@ -58,6 +59,7 @@ use libc::fstatat64; target_os = "redox", target_os = "illumos", target_os = "nto", + target_os = "vita", ))] use libc::readdir as readdir64; #[cfg(target_os = "linux")] @@ -74,6 +76,7 @@ use libc::readdir64_r; target_os = "fuchsia", target_os = "redox", target_os = "nto", + target_os = "vita", )))] use libc::readdir_r as readdir64_r; #[cfg(target_os = "android")] @@ -283,6 +286,7 @@ unsafe impl Sync for Dir {} target_os = "fuchsia", target_os = "redox", target_os = "nto", + target_os = "vita" ))] pub struct DirEntry { dir: Arc, @@ -304,10 +308,16 @@ pub struct DirEntry { target_os = "fuchsia", target_os = "redox", target_os = "nto", + target_os = "vita", ))] struct dirent64_min { d_ino: u64, - #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))] + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "nto", + target_os = "vita" + )))] d_type: u8, } @@ -319,6 +329,7 @@ struct dirent64_min { target_os = "fuchsia", target_os = "redox", target_os = "nto", + target_os = "vita", )))] pub struct DirEntry { dir: Arc, @@ -520,6 +531,7 @@ impl FileAttr { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "vita", )))] pub fn created(&self) -> io::Result { cfg_has_statx! { @@ -541,6 +553,11 @@ impl FileAttr { currently", )) } + + #[cfg(target_os = "vita")] + pub fn created(&self) -> io::Result { + Ok(SystemTime::new(self.stat.st_ctime as i64, 0)) + } } #[cfg(target_os = "nto")] @@ -645,6 +662,7 @@ impl Iterator for ReadDir { target_os = "redox", target_os = "illumos", target_os = "nto", + target_os = "vita", ))] fn next(&mut self) -> Option> { if self.end_of_stream { @@ -725,6 +743,7 @@ impl Iterator for ReadDir { continue; } + #[cfg(not(target_os = "vita"))] let entry = dirent64_min { d_ino: *offset_ptr!(entry_ptr, d_ino) as u64, #[cfg(not(any( @@ -735,6 +754,9 @@ impl Iterator for ReadDir { d_type: *offset_ptr!(entry_ptr, d_type) as u8, }; + #[cfg(target_os = "vita")] + let entry = dirent64_min { d_ino: 0u64 }; + return Some(Ok(DirEntry { entry, name: name.to_owned(), @@ -752,6 +774,7 @@ impl Iterator for ReadDir { target_os = "redox", target_os = "illumos", target_os = "nto", + target_os = "vita", )))] fn next(&mut self) -> Option> { if self.end_of_stream { @@ -842,6 +865,7 @@ impl DirEntry { target_os = "haiku", target_os = "vxworks", target_os = "nto", + target_os = "vita", ))] pub fn file_type(&self) -> io::Result { self.metadata().map(|m| m.file_type()) @@ -853,6 +877,7 @@ impl DirEntry { target_os = "haiku", target_os = "vxworks", target_os = "nto", + target_os = "vita", )))] pub fn file_type(&self) -> io::Result { match self.entry.d_type { @@ -939,6 +964,7 @@ impl DirEntry { target_os = "fuchsia", target_os = "redox", target_os = "nto", + target_os = "vita", )))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } @@ -951,6 +977,7 @@ impl DirEntry { target_os = "fuchsia", target_os = "redox", target_os = "nto", + target_os = "vita", ))] fn name_cstr(&self) -> &CStr { &self.name @@ -1543,7 +1570,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { run_path_with_cstr(original, |original| { run_path_with_cstr(link, |link| { cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon"))] { + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita"))] { // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves // it implementation-defined whether `link` follows symlinks, so rely on the // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. @@ -1666,6 +1693,8 @@ fn open_to_and_set_permissions( .truncate(true) .open(to)?; let writer_metadata = writer.metadata()?; + // fchmod is broken on vita + #[cfg(not(target_os = "vita"))] if writer_metadata.is_file() { // Set the correct file permissions, in case the file already existed. // Don't set the permissions on already existing non-files like @@ -1844,11 +1873,12 @@ pub fn chroot(dir: &Path) -> io::Result<()> { pub use remove_dir_impl::remove_dir_all; -// Fallback for REDOX, ESP-ID, Horizon, and Miri +// Fallback for REDOX, ESP-ID, Horizon, Vita and Miri #[cfg(any( target_os = "redox", target_os = "espidf", target_os = "horizon", + target_os = "vita", target_os = "nto", miri ))] @@ -1861,6 +1891,7 @@ mod remove_dir_impl { target_os = "redox", target_os = "espidf", target_os = "horizon", + target_os = "vita", target_os = "nto", miri )))] diff --git a/std/src/sys/unix/mod.rs b/std/src/sys/unix/mod.rs index 54e2f20b3..24566d96b 100644 --- a/std/src/sys/unix/mod.rs +++ b/std/src/sys/unix/mod.rs @@ -163,12 +163,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { } unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) { - #[cfg(not(any( - target_os = "emscripten", - target_os = "fuchsia", - target_os = "horizon", - target_os = "vita" - )))] + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))] { // We don't want to add this as a public type to std, nor do we // want to `include!` a file from the compiler (which would break @@ -206,7 +201,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "emscripten", target_os = "fuchsia", target_os = "horizon", - target_os = "vita" )))] static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool = crate::sync::atomic::AtomicBool::new(false); @@ -216,7 +210,6 @@ static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool = target_os = "emscripten", target_os = "fuchsia", target_os = "horizon", - target_os = "vita", )))] pub(crate) fn unix_sigpipe_attr_specified() -> bool { UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed) @@ -407,6 +400,9 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] { #[link(name = "dl")] extern "C" {} + } else if #[cfg(target_os = "vita")] { + #[link(name = "pthread", kind = "static", modifiers = "-bundle")] + extern "C" {} } } diff --git a/std/src/sys/unix/net.rs b/std/src/sys/unix/net.rs index 39edb136c..ca80cabc3 100644 --- a/std/src/sys/unix/net.rs +++ b/std/src/sys/unix/net.rs @@ -454,12 +454,21 @@ impl Socket { Ok(passcred != 0) } - #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "vita")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop) } + #[cfg(target_os = "vita")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let option = match nonblocking { + true => 1, + false => 0, + }; + setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option) + } + #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { // FIONBIO is inadequate for sockets on illumos/Solaris, so use the diff --git a/std/src/sys/unix/thread_parking/pthread.rs b/std/src/sys/unix/thread_parking/pthread.rs index 43046ed07..8bf4bae7a 100644 --- a/std/src/sys/unix/thread_parking/pthread.rs +++ b/std/src/sys/unix/thread_parking/pthread.rs @@ -123,7 +123,8 @@ impl Parker { target_os = "watchos", target_os = "l4re", target_os = "android", - target_os = "redox" + target_os = "redox", + target_os = "vita", ))] { addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { From ab08bf5628d0259b95b2f4ec4f639fd825ba9588 Mon Sep 17 00:00:00 2001 From: Nikolay Arhipov Date: Mon, 5 Jun 2023 19:26:04 +0300 Subject: [PATCH 065/180] Simplified bool to int conversion --- std/src/sys/unix/net.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/std/src/sys/unix/net.rs b/std/src/sys/unix/net.rs index ca80cabc3..7258c222a 100644 --- a/std/src/sys/unix/net.rs +++ b/std/src/sys/unix/net.rs @@ -462,10 +462,7 @@ impl Socket { #[cfg(target_os = "vita")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let option = match nonblocking { - true => 1, - false => 0, - }; + let option = nonblocking as libc::c_int; setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option) } From 4b5664406ef9357f77770c50e350e2c344cfab7d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 2 Jun 2023 22:18:11 +0100 Subject: [PATCH 066/180] std: available_parallelism using native netbsd api first before falling back to existing code paths like FreeBSD does. --- std/src/sys/unix/thread.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/std/src/sys/unix/thread.rs b/std/src/sys/unix/thread.rs index 878af5088..010015667 100644 --- a/std/src/sys/unix/thread.rs +++ b/std/src/sys/unix/thread.rs @@ -344,6 +344,29 @@ pub fn available_parallelism() -> io::Result { } } + #[cfg(target_os = "netbsd")] + { + unsafe { + let set = libc::_cpuset_create(); + if !set.is_null() { + let mut count: usize = 0; + if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 { + for i in 0..u64::MAX { + match libc::_cpuset_isset(i, set) { + -1 => break, + 0 => continue, + _ => count = count + 1, + } + } + } + libc::_cpuset_destroy(set); + if let Some(count) = NonZeroUsize::new(count) { + return Ok(count); + } + } + } + } + let mut cpus: libc::c_uint = 0; let mut cpus_size = crate::mem::size_of_val(&cpus); From 58d8be67d8be0d893cdf5cd9755ff20107190e89 Mon Sep 17 00:00:00 2001 From: Nikolay Arhipov Date: Tue, 6 Jun 2023 16:09:05 +0300 Subject: [PATCH 067/180] Bumped libc version --- std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 74b61db0c..4b52894c5 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 } -libc = { version = "0.2.145", default-features = false, features = ['rustc-dep-of-std'], public = true } +libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } compiler_builtins = { version = "0.1.92" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } From b8eaa203f2b411f3b04a24e29bef1f017db05590 Mon Sep 17 00:00:00 2001 From: Dan McGregor Date: Tue, 6 Jun 2023 10:15:11 -0600 Subject: [PATCH 068/180] Fix documentation build on FreeBSD After the socket ancillary data implementation was introduced, the build was broken on FreeBSD, add the same workaround as for the existing implementations. --- std/src/os/unix/net/ancillary.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/std/src/os/unix/net/ancillary.rs b/std/src/os/unix/net/ancillary.rs index 7565fbc0d..6bd87d61a 100644 --- a/std/src/os/unix/net/ancillary.rs +++ b/std/src/os/unix/net/ancillary.rs @@ -11,7 +11,13 @@ use crate::slice::from_raw_parts; use crate::sys::net::Socket; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))] +#[cfg(all( + doc, + not(target_os = "linux"), + not(target_os = "android"), + not(target_os = "netbsd"), + not(target_os = "freebsd") +))] #[allow(non_camel_case_types)] mod libc { pub use libc::c_int; From e5a8352cf3fd6a778e10b9f05cd80891fc94b30e Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Wed, 7 Jun 2023 08:17:58 -0700 Subject: [PATCH 069/180] Safe Transmute: Disable coinduction support This patch just removes the `#[rustc_coinductive]` annotation from `BikeshedIntrinsicFrom` and flips the related tests to `check-fail`. Once an FCP for setting the annotation on the trait is approved, it could be enabled again. --- core/src/mem/transmutability.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/mem/transmutability.rs b/core/src/mem/transmutability.rs index d0c30e715..87ae30619 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -5,7 +5,6 @@ /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[rustc_coinductive] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, From 3099f898f58d1bf37228e1664ec0270108043e9b Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 7 Jun 2023 21:27:51 -0700 Subject: [PATCH 070/180] Fix typo Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- core/src/any.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/any.rs b/core/src/any.rs index 89c613aef..09f52d692 100644 --- a/core/src/any.rs +++ b/core/src/any.rs @@ -713,7 +713,7 @@ impl hash::Hash for TypeId { // because: // - The hashing algorithm which backs `TypeId` is expected to be // unbiased and high quality, meaning further mixing would be somewhat - // redundant compared to choosing (the lower) 64 bits arbitrarially. + // redundant compared to choosing (the lower) 64 bits arbitrarily. // - `Hasher::finish` returns a u64 anyway, so the extra entropy we'd // get from hashing the full value would probably not be useful // (especially given the previous point about the lower 64 bits being From 28a73a66f7c711e06b8dd73961bd72affc798b62 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 12:13:37 +0200 Subject: [PATCH 071/180] Allow undropped_manually_drops for some tests --- core/tests/manually_drop.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/tests/manually_drop.rs b/core/tests/manually_drop.rs index 9eac27973..22d72d219 100644 --- a/core/tests/manually_drop.rs +++ b/core/tests/manually_drop.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), allow(undropped_manually_drops))] + use core::mem::ManuallyDrop; #[test] From 578cfd995f44f31886a36e542306dd51ff4fcc62 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jun 2023 22:48:29 +0200 Subject: [PATCH 072/180] Fix intra-doc links from pointer appearing in windows HANDLE type alias --- core/src/ptr/mut_ptr.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index c6f438578..e753647ff 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -106,7 +106,7 @@ impl *mut T { /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit /// coercion. /// - /// [`cast_mut`]: #method.cast_mut + /// [`cast_mut`]: pointer::cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] #[inline(always)] @@ -117,7 +117,7 @@ impl *mut T { /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](#method.from_bits-1). + /// The inverse method is [`from_bits`](pointer#method.from_bits-1). /// /// In particular, `*p as usize` and `p as usize` will both compile for /// pointers to numeric types but do very different things, so using this @@ -153,7 +153,7 @@ impl *mut T { /// Creates a pointer from its raw bits. /// /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](#method.to_bits-1). + /// The inverse method is [`to_bits`](pointer#method.to_bits-1). /// /// # Examples /// @@ -303,7 +303,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// [`as_mut`]: #method.as_mut /// /// # Safety @@ -369,7 +369,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Safety @@ -624,7 +624,7 @@ impl *mut T { /// For the shared counterpart see [`as_ref`]. /// /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// /// # Safety /// @@ -689,7 +689,7 @@ impl *mut T { /// For the shared counterpart see [`as_uninit_ref`]. /// /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// /// # Safety /// @@ -779,7 +779,7 @@ impl *mut T { /// /// This function is the inverse of [`offset`]. /// - /// [`offset`]: #method.offset-1 + /// [`offset`]: pointer#method.offset-1 /// /// # Safety /// @@ -2051,7 +2051,7 @@ impl *mut [T] { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut /// /// # Safety From c94ce58479473fd3eed5d78fa308a94fa7e0d875 Mon Sep 17 00:00:00 2001 From: yanchith Date: Fri, 9 Jun 2023 11:48:11 +0200 Subject: [PATCH 073/180] Reallocatorize after merge --- alloc/src/collections/binary_heap/mod.rs | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index f5e6bd20e..abc29b32b 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -280,7 +280,6 @@ pub struct BinaryHeap< data: Vec, } -// XXX: PeekMut /// Structure wrapping a mutable reference to the greatest item on a /// `BinaryHeap`. /// @@ -289,8 +288,12 @@ pub struct BinaryHeap< /// /// [`peek_mut`]: BinaryHeap::peek_mut #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -pub struct PeekMut<'a, T: 'a + Ord> { - heap: &'a mut BinaryHeap, +pub struct PeekMut< + 'a, + T: 'a + Ord, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + heap: &'a mut BinaryHeap, // If a set_len + sift_down are required, this is Some. If a &mut T has not // yet been exposed to peek_mut()'s caller, it's None. original_len: Option, @@ -359,11 +362,10 @@ impl<'a, T: Ord, A: Allocator + 'a> DerefMut for PeekMut<'a, T, A> { } } -// XXX: PeekMut impl<'a, T: Ord, A: Allocator + 'a> PeekMut<'a, T, A> { /// Removes the peeked value from the heap and returns it. #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")] - pub fn pop(mut this: PeekMut<'a, T>) -> T { + pub fn pop(mut this: PeekMut<'a, T, A>) -> T { if let Some(original_len) = this.original_len.take() { // SAFETY: This is how many elements were in the Vec at the time of // the BinaryHeap::peek_mut call. @@ -404,18 +406,21 @@ impl fmt::Debug for BinaryHeap { } } -struct RebuildOnDrop<'a, T: Ord> { - heap: &'a mut BinaryHeap, +struct RebuildOnDrop< + 'a, + T: Ord, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + heap: &'a mut BinaryHeap, rebuild_from: usize, } -impl<'a, T: Ord> Drop for RebuildOnDrop<'a, T> { +impl<'a, T: Ord, A: Allocator> Drop for RebuildOnDrop<'a, T, A> { fn drop(&mut self) { self.heap.rebuild_tail(self.rebuild_from); } } -// XXX: BinaryHeap impl BinaryHeap { /// Creates an empty `BinaryHeap` as a max-heap. /// @@ -501,7 +506,6 @@ impl BinaryHeap { BinaryHeap { data: Vec::with_capacity_in(capacity, alloc) } } - // XXX: peek_mut /// Returns a mutable reference to the greatest item in the binary heap, or /// `None` if it is empty. /// @@ -533,7 +537,7 @@ impl BinaryHeap { /// If the item is modified then the worst case time complexity is *O*(log(*n*)), /// otherwise it's *O*(1). #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] - pub fn peek_mut(&mut self) -> Option> { + pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { @@ -1813,7 +1817,7 @@ impl Extend for BinaryHeap { } #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { +impl<'a, T: 'a + Ord + Copy, A: Allocator> Extend<&'a T> for BinaryHeap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } From 7894f544940a7429a73690e90ad199f601653183 Mon Sep 17 00:00:00 2001 From: yanchith Date: Fri, 9 Jun 2023 11:53:28 +0200 Subject: [PATCH 074/180] Add allocator function --- alloc/src/collections/binary_heap/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index abc29b32b..9c2588c26 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -1245,6 +1245,13 @@ impl BinaryHeap { self.into() } + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + self.data.allocator() + } + /// Returns the length of the binary heap. /// /// # Examples From f65658569f448753f0709d63f98c8288514e33ce Mon Sep 17 00:00:00 2001 From: yanchith Date: Fri, 9 Jun 2023 12:02:25 +0200 Subject: [PATCH 075/180] Pass tidy again --- alloc/src/collections/binary_heap/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 9c2588c26..657c380d6 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -538,11 +538,7 @@ impl BinaryHeap { /// otherwise it's *O*(1). #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { - if self.is_empty() { - None - } else { - Some(PeekMut { heap: self, original_len: None }) - } + if self.is_empty() { None } else { Some(PeekMut { heap: self, original_len: None }) } } /// Removes the greatest item from the binary heap and returns it, or `None` if it From e602feecef5243cd619c88680c2753ad290e6a8d Mon Sep 17 00:00:00 2001 From: yanchith Date: Fri, 9 Jun 2023 12:19:17 +0200 Subject: [PATCH 076/180] Don't explicitly name Global --- alloc/src/collections/binary_heap/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 657c380d6..904e163da 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -1563,7 +1563,7 @@ unsafe impl SourceIter for IntoIter { #[doc(hidden)] unsafe impl InPlaceIterable for IntoIter {} -unsafe impl AsVecIntoIter for IntoIter { +unsafe impl AsVecIntoIter for IntoIter { type Item = I; fn as_into_iter(&mut self) -> &mut vec::IntoIter { From 6c13e3b5434424b65c6f096e2955cad5a8e0e62e Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 20 May 2023 11:28:25 +0200 Subject: [PATCH 077/180] Add diagnostic items for `f32::NAN` and `f64::NAN` --- core/src/num/f32.rs | 1 + core/src/num/f64.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index 4a035ad61..d050d21c8 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -403,6 +403,7 @@ impl f32 { /// and the stability of its representation over Rust versions /// and target platforms isn't guaranteed. #[stable(feature = "assoc_int_consts", since = "1.43.0")] + #[rustc_diagnostic_item = "f32_nan"] pub const NAN: f32 = 0.0_f32 / 0.0_f32; /// Infinity (∞). #[stable(feature = "assoc_int_consts", since = "1.43.0")] diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 3aafc435f..d9a738191 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -401,6 +401,7 @@ impl f64 { /// This constant isn't guaranteed to equal to any specific NaN bitpattern, /// and the stability of its representation over Rust versions /// and target platforms isn't guaranteed. + #[rustc_diagnostic_item = "f64_nan"] #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NAN: f64 = 0.0_f64 / 0.0_f64; /// Infinity (∞). From 3bbb09dfb868d7efe992567d75e4d7b8a4ba226c Mon Sep 17 00:00:00 2001 From: bdbai Date: Sat, 10 Jun 2023 16:30:26 +0800 Subject: [PATCH 078/180] Lazy load ntdll functions on UWP --- std/src/sys/windows/c.rs | 58 +++++++++++++++++++++++++++++++++++++ std/src/sys/windows/rand.rs | 5 ++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/std/src/sys/windows/c.rs b/std/src/sys/windows/c.rs index 07b0610d4..929aaf5a2 100644 --- a/std/src/sys/windows/c.rs +++ b/std/src/sys/windows/c.rs @@ -19,6 +19,7 @@ pub use windows_sys::*; pub type DWORD = c_ulong; pub type NonZeroDWORD = NonZero_c_ulong; pub type LARGE_INTEGER = c_longlong; +#[cfg_attr(target_vendor = "uwp", allow(unused))] pub type LONG = c_long; pub type UINT = c_uint; pub type WCHAR = u16; @@ -50,6 +51,9 @@ pub type CONDITION_VARIABLE = RTL_CONDITION_VARIABLE; pub type SRWLOCK = RTL_SRWLOCK; pub type INIT_ONCE = RTL_RUN_ONCE; +#[cfg(target_vendor = "uwp")] +pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; + pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: ptr::null_mut() }; pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: ptr::null_mut() }; pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() }; @@ -267,6 +271,8 @@ pub unsafe fn getaddrinfo( windows_sys::getaddrinfo(node.cast::(), service.cast::(), hints, res) } +cfg_if::cfg_if! { +if #[cfg(not(target_vendor = "uwp"))] { pub unsafe fn NtReadFile( filehandle: BorrowedHandle<'_>, event: HANDLE, @@ -313,6 +319,8 @@ pub unsafe fn NtWriteFile( key.map(|k| k as *const u32).unwrap_or(ptr::null()), ) } +} +} // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. @@ -376,4 +384,54 @@ compat_fn_with_fallback! { ) -> NTSTATUS { panic!("keyed events not available") } + + // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically. + #[cfg(target_vendor = "uwp")] + pub fn NtCreateFile( + filehandle: *mut HANDLE, + desiredaccess: FILE_ACCESS_RIGHTS, + objectattributes: *const OBJECT_ATTRIBUTES, + iostatusblock: *mut IO_STATUS_BLOCK, + allocationsize: *const i64, + fileattributes: FILE_FLAGS_AND_ATTRIBUTES, + shareaccess: FILE_SHARE_MODE, + createdisposition: NTCREATEFILE_CREATE_DISPOSITION, + createoptions: NTCREATEFILE_CREATE_OPTIONS, + eabuffer: *const ::core::ffi::c_void, + ealength: u32 + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + #[cfg(target_vendor = "uwp")] + pub fn NtReadFile( + filehandle: BorrowedHandle<'_>, + event: HANDLE, + apcroutine: PIO_APC_ROUTINE, + apccontext: *mut c_void, + iostatusblock: &mut IO_STATUS_BLOCK, + buffer: *mut crate::mem::MaybeUninit, + length: ULONG, + byteoffset: Option<&LARGE_INTEGER>, + key: Option<&ULONG> + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + #[cfg(target_vendor = "uwp")] + pub fn NtWriteFile( + filehandle: BorrowedHandle<'_>, + event: HANDLE, + apcroutine: PIO_APC_ROUTINE, + apccontext: *mut c_void, + iostatusblock: &mut IO_STATUS_BLOCK, + buffer: *const u8, + length: ULONG, + byteoffset: Option<&LARGE_INTEGER>, + key: Option<&ULONG> + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + #[cfg(target_vendor = "uwp")] + pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG { + Status as ULONG + } } diff --git a/std/src/sys/windows/rand.rs b/std/src/sys/windows/rand.rs index bca4e38d9..5d8fd1378 100644 --- a/std/src/sys/windows/rand.rs +++ b/std/src/sys/windows/rand.rs @@ -1,5 +1,3 @@ -use crate::ffi::c_void; -use crate::io; use crate::mem; use crate::ptr; use crate::sys::c; @@ -25,6 +23,9 @@ pub fn hashmap_random_keys() -> (u64, u64) { #[cfg(not(target_vendor = "uwp"))] #[inline(never)] fn fallback_rng() -> (u64, u64) { + use crate::ffi::c_void; + use crate::io; + let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut c_void, mem::size_of_val(&v) as c::ULONG) From c107466e9649674e9796be463cbdb027d899ad60 Mon Sep 17 00:00:00 2001 From: bdbai Date: Sat, 10 Jun 2023 20:47:10 +0800 Subject: [PATCH 079/180] Keep uwp specific code in sync with windows-sys --- std/src/sys/windows/c.rs | 7 ++----- std/src/sys/windows/c/windows_sys.lst | 1 + std/src/sys/windows/c/windows_sys.rs | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/std/src/sys/windows/c.rs b/std/src/sys/windows/c.rs index 929aaf5a2..5fc6136ba 100644 --- a/std/src/sys/windows/c.rs +++ b/std/src/sys/windows/c.rs @@ -51,9 +51,6 @@ pub type CONDITION_VARIABLE = RTL_CONDITION_VARIABLE; pub type SRWLOCK = RTL_SRWLOCK; pub type INIT_ONCE = RTL_RUN_ONCE; -#[cfg(target_vendor = "uwp")] -pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; - pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: ptr::null_mut() }; pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: ptr::null_mut() }; pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() }; @@ -431,7 +428,7 @@ compat_fn_with_fallback! { STATUS_NOT_IMPLEMENTED } #[cfg(target_vendor = "uwp")] - pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG { - Status as ULONG + pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 { + Status as u32 } } diff --git a/std/src/sys/windows/c/windows_sys.lst b/std/src/sys/windows/c/windows_sys.lst index 3e454199f..2cf1ade99 100644 --- a/std/src/sys/windows/c/windows_sys.lst +++ b/std/src/sys/windows/c/windows_sys.lst @@ -1930,6 +1930,7 @@ Windows.Win32.Foundation.SetLastError Windows.Win32.Foundation.STATUS_DELETE_PENDING Windows.Win32.Foundation.STATUS_END_OF_FILE Windows.Win32.Foundation.STATUS_INVALID_PARAMETER +Windows.Win32.Foundation.STATUS_NOT_IMPLEMENTED Windows.Win32.Foundation.STATUS_PENDING Windows.Win32.Foundation.STATUS_SUCCESS Windows.Win32.Foundation.TRUE diff --git a/std/src/sys/windows/c/windows_sys.rs b/std/src/sys/windows/c/windows_sys.rs index 36a30f6ba..8c8b006a1 100644 --- a/std/src/sys/windows/c/windows_sys.rs +++ b/std/src/sys/windows/c/windows_sys.rs @@ -3888,6 +3888,7 @@ pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = -1073741738i32; pub const STATUS_END_OF_FILE: NTSTATUS = -1073741807i32; pub const STATUS_INVALID_PARAMETER: NTSTATUS = -1073741811i32; +pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = -1073741822i32; pub const STATUS_PENDING: NTSTATUS = 259i32; pub const STATUS_SUCCESS: NTSTATUS = 0i32; pub const STD_ERROR_HANDLE: STD_HANDLE = 4294967284u32; From 0d8be2e673eed1b7bd3ed7501499a4aafcd6e454 Mon Sep 17 00:00:00 2001 From: icecream17 Date: Sat, 10 Jun 2023 10:45:50 -0500 Subject: [PATCH 080/180] abs_sub: fix typo 0[-:][+.]0 --- std/src/f32.rs | 2 +- std/src/f64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/f32.rs b/std/src/f32.rs index 408244b2c..bed90418b 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -528,7 +528,7 @@ impl f32 { /// The positive difference of two numbers. /// - /// * If `self <= other`: `0:0` + /// * If `self <= other`: `0.0` /// * Else: `self - other` /// /// # Examples diff --git a/std/src/f64.rs b/std/src/f64.rs index 6782b861f..e72de05ca 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -530,7 +530,7 @@ impl f64 { /// The positive difference of two numbers. /// - /// * If `self <= other`: `0:0` + /// * If `self <= other`: `0.0` /// * Else: `self - other` /// /// # Examples From a022a637d8e4e89f7a16f99593960540ebd61921 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Mon, 1 May 2023 22:22:43 -0400 Subject: [PATCH 081/180] implement `Sync` for `mpsc::Sender` --- std/src/sync/mpsc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/sync/mpsc/mod.rs b/std/src/sync/mpsc/mod.rs index 0e0c87d1c..71ff4237d 100644 --- a/std/src/sync/mpsc/mod.rs +++ b/std/src/sync/mpsc/mod.rs @@ -347,8 +347,8 @@ pub struct Sender { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Sender {} -#[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Sender {} +#[stable(feature = "mpsc_sender_sync", since = "CURRENT_RUSTC_VERSION")] +unsafe impl Sync for Sender {} /// The sending-half of Rust's synchronous [`sync_channel`] type. /// From baeec37d13d4c159a252d261fc13b0827118303e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Jun 2023 22:15:46 +0200 Subject: [PATCH 082/180] reorder attributes to make miri-test-libstd work again --- alloc/src/lib.rs | 10 +++++----- std/src/lib.rs | 13 +++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index 59fa91c10..967ad3a0e 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -56,6 +56,11 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell +// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -75,11 +80,6 @@ ))] #![no_std] #![needs_allocator] -// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be -// able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// // Lints: #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] diff --git a/std/src/lib.rs b/std/src/lib.rs index d53f1a2b2..da08c018d 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -188,6 +188,13 @@ //! [array]: prim@array //! [slice]: prim@slice +// To run std tests without x.py without ending up with two copies of std, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. +#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] +// #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![doc( @@ -202,12 +209,6 @@ no_global_oom_handling, not(no_global_oom_handling) ))] -// To run std tests without x.py without ending up with two copies of std, Miri needs to be -// able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. -#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] // Don't link to std. We are std. #![no_std] // Tell the compiler to link to either panic_abort or panic_unwind From be9a1d21349266f4d4013ef3c9d537806b78335a Mon Sep 17 00:00:00 2001 From: yanchith Date: Sun, 11 Jun 2023 22:42:50 +0200 Subject: [PATCH 083/180] Remove explicit lifetimes --- alloc/src/collections/binary_heap/mod.rs | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 904e163da..93e799410 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -300,14 +300,14 @@ pub struct PeekMut< } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: Ord + fmt::Debug, A: Allocator + 'a> fmt::Debug for PeekMut<'a, T, A> { +impl fmt::Debug for PeekMut<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish() } } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord, A: Allocator + 'a> Drop for PeekMut<'a, T, A> { +impl Drop for PeekMut<'_, T, A> { fn drop(&mut self) { if let Some(original_len) = self.original_len { // SAFETY: That's how many elements were in the Vec at the time of @@ -324,7 +324,7 @@ impl<'a, T: Ord, A: Allocator + 'a> Drop for PeekMut<'a, T, A> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord, A: Allocator + 'a> Deref for PeekMut<'a, T, A> { +impl Deref for PeekMut<'_, T, A> { type Target = T; fn deref(&self) -> &T { debug_assert!(!self.heap.is_empty()); @@ -334,7 +334,7 @@ impl<'a, T: Ord, A: Allocator + 'a> Deref for PeekMut<'a, T, A> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord, A: Allocator + 'a> DerefMut for PeekMut<'a, T, A> { +impl DerefMut for PeekMut<'_, T, A> { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); @@ -362,7 +362,7 @@ impl<'a, T: Ord, A: Allocator + 'a> DerefMut for PeekMut<'a, T, A> { } } -impl<'a, T: Ord, A: Allocator + 'a> PeekMut<'a, T, A> { +impl<'a, T: Ord, A: Allocator> PeekMut<'a, T, A> { /// Removes the peeked value from the heap and returns it. #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")] pub fn pop(mut this: PeekMut<'a, T, A>) -> T { @@ -415,7 +415,7 @@ struct RebuildOnDrop< rebuild_from: usize, } -impl<'a, T: Ord, A: Allocator> Drop for RebuildOnDrop<'a, T, A> { +impl Drop for RebuildOnDrop<'_, T, A> { fn drop(&mut self) { self.heap.rebuild_tail(self.rebuild_from); } @@ -1617,13 +1617,13 @@ unsafe impl TrustedLen for IntoIterSorted {} pub struct Drain< 'a, T: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { iter: vec::Drain<'a, T, A>, } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T, A: Allocator + 'a> Iterator for Drain<'a, T, A> { +impl Iterator for Drain<'_, T, A> { type Item = T; #[inline] @@ -1638,7 +1638,7 @@ impl<'a, T, A: Allocator + 'a> Iterator for Drain<'a, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T, A: Allocator + 'a> DoubleEndedIterator for Drain<'a, T, A> { +impl DoubleEndedIterator for Drain<'_, T, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -1646,14 +1646,14 @@ impl<'a, T, A: Allocator + 'a> DoubleEndedIterator for Drain<'a, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T, A: Allocator + 'a> ExactSizeIterator for Drain<'a, T, A> { +impl ExactSizeIterator for Drain<'_, T, A> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T, A: Allocator + 'a> FusedIterator for Drain<'a, T, A> {} +impl FusedIterator for Drain<'_, T, A> {} /// A draining iterator over the elements of a `BinaryHeap`. /// @@ -1666,18 +1666,18 @@ impl<'a, T, A: Allocator + 'a> FusedIterator for Drain<'a, T, A> {} pub struct DrainSorted< 'a, T: Ord, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { inner: &'a mut BinaryHeap, } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl<'a, T: Ord, A: Allocator + 'a> Drop for DrainSorted<'a, T, A> { +impl<'a, T: Ord, A: Allocator> Drop for DrainSorted<'a, T, A> { /// Removes heap elements in heap order. fn drop(&mut self) { - struct DropGuard<'r, 'a, T: Ord, A: Allocator + 'a>(&'r mut DrainSorted<'a, T, A>); + struct DropGuard<'r, 'a, T: Ord, A: Allocator>(&'r mut DrainSorted<'a, T, A>); - impl<'r, 'a, T: Ord, A: Allocator + 'a> Drop for DropGuard<'r, 'a, T, A> { + impl<'r, 'a, T: Ord, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { fn drop(&mut self) { while self.0.inner.pop().is_some() {} } @@ -1692,7 +1692,7 @@ impl<'a, T: Ord, A: Allocator + 'a> Drop for DrainSorted<'a, T, A> { } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl<'a, T: Ord, A: Allocator + 'a> Iterator for DrainSorted<'a, T, A> { +impl Iterator for DrainSorted<'_, T, A> { type Item = T; #[inline] @@ -1708,13 +1708,13 @@ impl<'a, T: Ord, A: Allocator + 'a> Iterator for DrainSorted<'a, T, A> { } #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl<'a, T: Ord, A: Allocator + 'a> ExactSizeIterator for DrainSorted<'a, T, A> {} +impl ExactSizeIterator for DrainSorted<'_, T, A> {} #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] -impl<'a, T: Ord, A: Allocator + 'a> FusedIterator for DrainSorted<'a, T, A> {} +impl FusedIterator for DrainSorted<'_, T, A> {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T: Ord, A: Allocator + 'a> TrustedLen for DrainSorted<'a, T, A> {} +unsafe impl TrustedLen for DrainSorted<'_, T, A> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for BinaryHeap { @@ -1791,7 +1791,7 @@ impl IntoIterator for BinaryHeap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, A: Allocator + 'a> IntoIterator for &'a BinaryHeap { +impl<'a, T, A: Allocator> IntoIterator for &'a BinaryHeap { type Item = &'a T; type IntoIter = Iter<'a, T>; From f1a4535b30cc5b8c379c9b5687fc0a0f01464ab1 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sun, 11 Jun 2023 22:56:16 +0200 Subject: [PATCH 084/180] Impl allocator function for iterators --- alloc/src/collections/binary_heap/mod.rs | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/alloc/src/collections/binary_heap/mod.rs b/alloc/src/collections/binary_heap/mod.rs index 93e799410..66573b90d 100644 --- a/alloc/src/collections/binary_heap/mod.rs +++ b/alloc/src/collections/binary_heap/mod.rs @@ -1492,6 +1492,14 @@ pub struct IntoIter< iter: vec::IntoIter, } +impl IntoIter { + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + self.iter.allocator() + } +} + #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1581,6 +1589,14 @@ pub struct IntoIterSorted< inner: BinaryHeap, } +impl IntoIterSorted { + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + self.inner.allocator() + } +} + #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] impl Iterator for IntoIterSorted { type Item = T; @@ -1622,6 +1638,14 @@ pub struct Drain< iter: vec::Drain<'a, T, A>, } +impl Drain<'_, T, A> { + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + self.iter.allocator() + } +} + #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_, T, A> { type Item = T; @@ -1671,6 +1695,14 @@ pub struct DrainSorted< inner: &'a mut BinaryHeap, } +impl<'a, T: Ord, A: Allocator> DrainSorted<'a, T, A> { + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + self.inner.allocator() + } +} + #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] impl<'a, T: Ord, A: Allocator> Drop for DrainSorted<'a, T, A> { /// Removes heap elements in heap order. From 07bb050711b1f691d17312b050fbc4260642fe47 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 8 Jun 2023 09:53:01 +0200 Subject: [PATCH 085/180] make sure the standard library compiles properly with synthetic targets It might happen that a synthetic target name does not match one of the hardcoded ones in std's build script, causing std to fail to build. This commit changes the std build script avoid including the restricted-std feature unconditionally when a synthetic target is being built. --- std/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/build.rs b/std/build.rs index 0fb03c8e8..d0b379409 100644 --- a/std/build.rs +++ b/std/build.rs @@ -36,6 +36,8 @@ fn main() { || target.contains("nintendo-3ds") || target.contains("vita") || target.contains("nto") + // See src/bootstrap/synthetic_targets.rs + || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() { // These platforms don't have any special requirements. } else { From b1919dde46625ef5af4d6e7044244f101c241bb1 Mon Sep 17 00:00:00 2001 From: aticu <15schnic@gmail.com> Date: Fri, 17 Jun 2022 16:31:36 +0200 Subject: [PATCH 086/180] Implement `TryFrom<&OsStr>` for `&str` --- std/src/ffi/os_str.rs | 20 +++++++++++++++++++- std/src/sys/unix/os_str.rs | 4 ++-- std/src/sys/windows/os_str.rs | 2 +- std/src/sys_common/wtf8.rs | 9 ++------- std/src/sys_common/wtf8/tests.rs | 6 +++--- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index f2bbcc85c..29f4d4182 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -692,7 +692,7 @@ impl OsStr { without modifying the original"] #[inline] pub fn to_str(&self) -> Option<&str> { - self.inner.to_str() + self.inner.to_str().ok() } /// Converts an `OsStr` to a [Cow]<[str]>. @@ -1101,6 +1101,24 @@ impl<'a> From> for OsString { } } +#[stable(feature = "str_tryfrom_osstr_impl", since = "CURRENT_RUSTC_VERSION")] +impl<'a> TryFrom<&'a OsStr> for &'a str { + type Error = crate::str::Utf8Error; + + /// Tries to convert an `&OsStr` to a `&str`. + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// let as_str = <&str>::try_from(os_str).unwrap(); + /// assert_eq!(as_str, "foo"); + /// ``` + fn try_from(value: &'a OsStr) -> Result { + value.inner.to_str() + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box { #[inline] diff --git a/std/src/sys/unix/os_str.rs b/std/src/sys/unix/os_str.rs index ccbc18224..b88107479 100644 --- a/std/src/sys/unix/os_str.rs +++ b/std/src/sys/unix/os_str.rs @@ -195,8 +195,8 @@ impl Slice { Slice::from_u8_slice(s.as_bytes()) } - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() + pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { + str::from_utf8(&self.inner) } pub fn to_string_lossy(&self) -> Cow<'_, str> { diff --git a/std/src/sys/windows/os_str.rs b/std/src/sys/windows/os_str.rs index 11883f150..aca2b7392 100644 --- a/std/src/sys/windows/os_str.rs +++ b/std/src/sys/windows/os_str.rs @@ -155,7 +155,7 @@ impl Slice { unsafe { mem::transmute(Wtf8::from_str(s)) } } - pub fn to_str(&self) -> Option<&str> { + pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { self.inner.as_str() } diff --git a/std/src/sys_common/wtf8.rs b/std/src/sys_common/wtf8.rs index 57fa49893..f357824ae 100644 --- a/std/src/sys_common/wtf8.rs +++ b/std/src/sys_common/wtf8.rs @@ -566,13 +566,8 @@ impl Wtf8 { /// /// This does not copy the data. #[inline] - pub fn as_str(&self) -> Option<&str> { - // Well-formed WTF-8 is also well-formed UTF-8 - // if and only if it contains no surrogate. - match self.next_surrogate(0) { - None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }), - Some(_) => None, - } + pub fn as_str(&self) -> Result<&str, str::Utf8Error> { + str::from_utf8(&self.bytes) } /// Lossily converts the string to UTF-8. diff --git a/std/src/sys_common/wtf8/tests.rs b/std/src/sys_common/wtf8/tests.rs index 931996791..cb6391458 100644 --- a/std/src/sys_common/wtf8/tests.rs +++ b/std/src/sys_common/wtf8/tests.rs @@ -354,11 +354,11 @@ fn wtf8_code_points() { #[test] fn wtf8_as_str() { - assert_eq!(Wtf8::from_str("").as_str(), Some("")); - assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩")); + assert_eq!(Wtf8::from_str("").as_str(), Ok("")); + assert_eq!(Wtf8::from_str("aé 💩").as_str(), Ok("aé 💩")); let mut string = Wtf8Buf::new(); string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.as_str(), None); + assert!(string.as_str().is_err()); } #[test] From e029489caacc217decadf2653698fd2b6543a992 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Jun 2023 11:16:57 +0200 Subject: [PATCH 087/180] Revert "Fix intra-doc links from pointer appearing in windows HANDLE type alias" This reverts commit 2ce7cd906bde70d8cbd9b07b31c6a7bf1131c345. --- core/src/ptr/mut_ptr.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index e753647ff..c6f438578 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -106,7 +106,7 @@ impl *mut T { /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit /// coercion. /// - /// [`cast_mut`]: pointer::cast_mut + /// [`cast_mut`]: #method.cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] #[inline(always)] @@ -117,7 +117,7 @@ impl *mut T { /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](pointer#method.from_bits-1). + /// The inverse method is [`from_bits`](#method.from_bits-1). /// /// In particular, `*p as usize` and `p as usize` will both compile for /// pointers to numeric types but do very different things, so using this @@ -153,7 +153,7 @@ impl *mut T { /// Creates a pointer from its raw bits. /// /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](pointer#method.to_bits-1). + /// The inverse method is [`to_bits`](#method.to_bits-1). /// /// # Examples /// @@ -303,7 +303,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 + /// [`as_uninit_ref`]: #method.as_uninit_ref-1 /// [`as_mut`]: #method.as_mut /// /// # Safety @@ -369,7 +369,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: pointer#method.as_ref-1 + /// [`as_ref`]: #method.as_ref-1 /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Safety @@ -624,7 +624,7 @@ impl *mut T { /// For the shared counterpart see [`as_ref`]. /// /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: pointer#method.as_ref-1 + /// [`as_ref`]: #method.as_ref-1 /// /// # Safety /// @@ -689,7 +689,7 @@ impl *mut T { /// For the shared counterpart see [`as_uninit_ref`]. /// /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 + /// [`as_uninit_ref`]: #method.as_uninit_ref-1 /// /// # Safety /// @@ -779,7 +779,7 @@ impl *mut T { /// /// This function is the inverse of [`offset`]. /// - /// [`offset`]: pointer#method.offset-1 + /// [`offset`]: #method.offset-1 /// /// # Safety /// @@ -2051,7 +2051,7 @@ impl *mut [T] { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: pointer#method.as_ref-1 + /// [`as_ref`]: #method.as_ref-1 /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut /// /// # Safety From 9a9e598ae7883c06d2a6f120a1564465402c8c51 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 2 Jan 2023 05:17:47 +0100 Subject: [PATCH 088/180] add benchmark --- core/benches/slice.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/benches/slice.rs b/core/benches/slice.rs index 9b86a0ca9..3bfb35e68 100644 --- a/core/benches/slice.rs +++ b/core/benches/slice.rs @@ -1,3 +1,4 @@ +use core::ptr::NonNull; use test::black_box; use test::Bencher; @@ -162,3 +163,11 @@ fn fill_byte_sized(b: &mut Bencher) { black_box(slice.fill(black_box(NewType(42)))); }); } + +// Tests the ability of the compiler to recognize that only the last slice item is needed +// based on issue #106288 +#[bench] +fn fold_to_last(b: &mut Bencher) { + let slice: &[i32] = &[0; 1024]; + b.iter(|| black_box(slice).iter().fold(None, |_, r| Some(NonNull::from(r)))); +} From e7ec6673d80d87b1431e058a69c12a47f1dd7ccf Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 1 Jan 2023 05:22:54 +0100 Subject: [PATCH 089/180] optimize slice::Iter::fold --- core/src/slice/iter/macros.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/core/src/slice/iter/macros.rs b/core/src/slice/iter/macros.rs index 3462c0e02..dd809ca45 100644 --- a/core/src/slice/iter/macros.rs +++ b/core/src/slice/iter/macros.rs @@ -191,6 +191,29 @@ macro_rules! iterator { self.next_back() } + #[inline] + fn fold(mut self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + // Handling the 0-len case explicitly and then using a do-while style loop + // helps the optimizer. See issue #106288 + if is_empty!(self) { + return init; + } + let mut acc = init; + // SAFETY: The 0-len case was handled above so one loop iteration is guaranteed. + unsafe { + loop { + acc = f(acc, next_unchecked!(self)); + if is_empty!(self) { + break; + } + } + } + acc + } + // We override the default implementation, which uses `try_fold`, // because this simple implementation generates less LLVM IR and is // faster to compile. From 8967cb7306fbbcb51caf264079ea8e8080d42a90 Mon Sep 17 00:00:00 2001 From: bdbai Date: Sun, 11 Jun 2023 22:50:30 +0800 Subject: [PATCH 090/180] Add windows_sys typedef for Win ARM32 --- std/src/sys/windows/c/windows_sys.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/std/src/sys/windows/c/windows_sys.rs b/std/src/sys/windows/c/windows_sys.rs index 8c8b006a1..d3ecd70dc 100644 --- a/std/src/sys/windows/c/windows_sys.rs +++ b/std/src/sys/windows/c/windows_sys.rs @@ -4275,3 +4275,20 @@ impl ::core::clone::Clone for XSAVE_FORMAT { *self } } +// Begin of ARM32 shim +cfg_if::cfg_if! { +if #[cfg(target_arch = "arm")] { +#[repr(C)] +pub struct WSADATA { + pub wVersion: u16, + pub wHighVersion: u16, + pub szDescription: [u8; 257], + pub szSystemStatus: [u8; 129], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: PSTR, +} +pub enum CONTEXT {} +} +} +// End of ARM32 shim From 4d7363d7514d0d0ef851173febea1474bcb2df00 Mon Sep 17 00:00:00 2001 From: bdbai Date: Mon, 12 Jun 2023 22:40:11 +0800 Subject: [PATCH 091/180] Add comment for arm_shim in generate-windows-sys --- std/src/sys/windows/c/windows_sys.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/src/sys/windows/c/windows_sys.rs b/std/src/sys/windows/c/windows_sys.rs index d3ecd70dc..a4294f336 100644 --- a/std/src/sys/windows/c/windows_sys.rs +++ b/std/src/sys/windows/c/windows_sys.rs @@ -4276,6 +4276,9 @@ impl ::core::clone::Clone for XSAVE_FORMAT { } } // Begin of ARM32 shim +// The raw content of this file should be processed by `generate-windows-sys` +// to be merged with the generated binding. It is not supposed to be used as +// a normal Rust module. cfg_if::cfg_if! { if #[cfg(target_arch = "arm")] { #[repr(C)] From dbe2bc37f42c8f934676e3002f68d57d250ee808 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Tue, 13 Jun 2023 00:09:13 +0900 Subject: [PATCH 092/180] Fix typo in mod.rs assoicated -> associated --- std/src/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index d9973185b..1230bb5de 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -195,7 +195,7 @@ mod local; cfg_if::cfg_if! { if #[cfg(test)] { - // Avoid duplicating the global state assoicated with thread-locals between this crate and + // Avoid duplicating the global state associated with thread-locals between this crate and // realstd. Miri relies on this. pub use realstd::thread::{local_impl, AccessError, LocalKey}; } else { From 65fefd887d1221e03f74d65508468e742278540f Mon Sep 17 00:00:00 2001 From: MikaelUrankar Date: Tue, 13 Jun 2023 13:14:06 +0200 Subject: [PATCH 093/180] Fix building the documentation on FreeBSD. It fixes the following error: error[E0412]: cannot find type `sockcred2` in module `libc` --> library/std/src/os/unix/net/ancillary.rs:211:29 | 211 | pub struct SocketCred(libc::sockcred2); | ^^^^^^^^^ not found in `libc` --- std/src/os/unix/net/ancillary.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/os/unix/net/ancillary.rs b/std/src/os/unix/net/ancillary.rs index 7565fbc0d..814f1c7c2 100644 --- a/std/src/os/unix/net/ancillary.rs +++ b/std/src/os/unix/net/ancillary.rs @@ -17,6 +17,7 @@ mod libc { pub use libc::c_int; pub struct ucred; pub struct cmsghdr; + pub struct sockcred2; pub type pid_t = i32; pub type gid_t = u32; pub type uid_t = u32; From 183e08afa96f34d3b63bd461ae46dbb9f91b7733 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 5 Jun 2023 15:13:15 +0200 Subject: [PATCH 094/180] ignore core, alloc and test tests that require unwinding on panic=abort --- alloc/src/collections/binary_heap/tests.rs | 3 +++ alloc/src/collections/btree/map/tests.rs | 9 +++++++++ alloc/src/collections/btree/set/tests.rs | 2 ++ alloc/src/collections/linked_list/tests.rs | 3 +++ alloc/src/slice/tests.rs | 1 + alloc/tests/slice.rs | 1 + alloc/tests/string.rs | 1 + alloc/tests/vec.rs | 11 +++++++++++ alloc/tests/vec_deque.rs | 3 +++ core/tests/array.rs | 15 +++------------ test/src/tests.rs | 5 +++++ 11 files changed, 42 insertions(+), 12 deletions(-) diff --git a/alloc/src/collections/binary_heap/tests.rs b/alloc/src/collections/binary_heap/tests.rs index 500caa356..565a7b797 100644 --- a/alloc/src/collections/binary_heap/tests.rs +++ b/alloc/src/collections/binary_heap/tests.rs @@ -309,6 +309,7 @@ fn test_drain_sorted() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_sorted_leak() { let d0 = CrashTestDummy::new(0); let d1 = CrashTestDummy::new(1); @@ -475,6 +476,7 @@ fn test_retain() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_retain_catch_unwind() { let mut heap = BinaryHeap::from(vec![3, 1, 2]); @@ -502,6 +504,7 @@ fn test_retain_catch_unwind() { // 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 rand::seq::SliceRandom; use std::cmp; diff --git a/alloc/src/collections/btree/map/tests.rs b/alloc/src/collections/btree/map/tests.rs index 7ecffe3ee..8efd9a03a 100644 --- a/alloc/src/collections/btree/map/tests.rs +++ b/alloc/src/collections/btree/map/tests.rs @@ -1155,6 +1155,7 @@ mod test_drain_filter { } #[test] + #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn drop_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -1175,6 +1176,7 @@ mod test_drain_filter { } #[test] + #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn pred_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -1201,6 +1203,7 @@ mod test_drain_filter { // Same as above, but attempt to use the iterator again after the panic in the predicate #[test] + #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn pred_panic_reuse() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -1449,6 +1452,7 @@ fn test_clear() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_clear_drop_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -1540,11 +1544,13 @@ fn test_clone_panic_leak(size: usize) { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_clone_panic_leak_height_0() { test_clone_panic_leak(3) } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_clone_panic_leak_height_1() { test_clone_panic_leak(MIN_INSERTS_HEIGHT_1) } @@ -2099,6 +2105,7 @@ create_append_test!(test_append_239, 239); create_append_test!(test_append_1700, 1700); #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_append_drop_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -2240,6 +2247,7 @@ fn test_split_off_large_random_sorted() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_iter_drop_leak_height_0() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -2263,6 +2271,7 @@ fn test_into_iter_drop_leak_height_0() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_iter_drop_leak_height_1() { let size = MIN_INSERTS_HEIGHT_1; for panic_point in vec![0, 1, size - 2, size - 1] { diff --git a/alloc/src/collections/btree/set/tests.rs b/alloc/src/collections/btree/set/tests.rs index a7c839d77..8eb730f4a 100644 --- a/alloc/src/collections/btree/set/tests.rs +++ b/alloc/src/collections/btree/set/tests.rs @@ -377,6 +377,7 @@ fn test_drain_filter() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_filter_drop_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); @@ -397,6 +398,7 @@ fn test_drain_filter_drop_panic_leak() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_filter_pred_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); diff --git a/alloc/src/collections/linked_list/tests.rs b/alloc/src/collections/linked_list/tests.rs index 04594d55b..6a0ea6183 100644 --- a/alloc/src/collections/linked_list/tests.rs +++ b/alloc/src/collections/linked_list/tests.rs @@ -985,6 +985,7 @@ fn drain_filter_complex() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn drain_filter_drop_panic_leak() { let d0 = CrashTestDummy::new(0); let d1 = CrashTestDummy::new(1); @@ -1018,6 +1019,7 @@ fn drain_filter_drop_panic_leak() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn drain_filter_pred_panic_leak() { static mut DROPS: i32 = 0; @@ -1124,6 +1126,7 @@ fn test_drop_clear() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drop_panic() { static mut DROPS: i32 = 0; diff --git a/alloc/src/slice/tests.rs b/alloc/src/slice/tests.rs index f674530aa..54bc4e77b 100644 --- a/alloc/src/slice/tests.rs +++ b/alloc/src/slice/tests.rs @@ -187,6 +187,7 @@ std::thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); #[test] #[cfg_attr(target_os = "emscripten", ignore)] // no threads +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_safe() { panic::update_hook(move |prev, info| { if !SILENCE_PANIC.with(|s| s.get()) { diff --git a/alloc/tests/slice.rs b/alloc/tests/slice.rs index 9aa5575ca..784839a3f 100644 --- a/alloc/tests/slice.rs +++ b/alloc/tests/slice.rs @@ -1418,6 +1418,7 @@ 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::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; diff --git a/alloc/tests/string.rs b/alloc/tests/string.rs index 99d1296a4..17d56d491 100644 --- a/alloc/tests/string.rs +++ b/alloc/tests/string.rs @@ -394,6 +394,7 @@ fn test_remove_matches() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_retain() { let mut s = String::from("α_β_γ"); diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index cc4c1f127..155431689 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -314,6 +314,7 @@ fn test_retain_predicate_order() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_retain_pred_panic_with_hole() { let v = (0..5).map(Rc::new).collect::>(); catch_unwind(AssertUnwindSafe(|| { @@ -331,6 +332,7 @@ fn test_retain_pred_panic_with_hole() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_retain_pred_panic_no_hole() { let v = (0..5).map(Rc::new).collect::>(); catch_unwind(AssertUnwindSafe(|| { @@ -346,6 +348,7 @@ fn test_retain_pred_panic_no_hole() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_retain_drop_panic() { struct Wrap(Rc); @@ -806,6 +809,7 @@ fn test_drain_end_overflow() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_leak() { static mut DROPS: i32 = 0; @@ -1038,6 +1042,7 @@ fn test_into_iter_clone() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_iter_leak() { static mut DROPS: i32 = 0; @@ -1195,6 +1200,7 @@ fn test_from_iter_specialization_head_tail_drop() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_from_iter_specialization_panic_during_iteration_drops() { let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); let src: Vec<_> = drop_count.iter().cloned().collect(); @@ -1219,6 +1225,7 @@ fn test_from_iter_specialization_panic_during_iteration_drops() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_from_iter_specialization_panic_during_drop_doesnt_leak() { static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5]; static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2]; @@ -1494,6 +1501,7 @@ fn drain_filter_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 drain_filter_consumed_panic() { use std::rc::Rc; use std::sync::Mutex; @@ -1546,6 +1554,7 @@ fn drain_filter_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 drain_filter_unconsumed_panic() { use std::rc::Rc; use std::sync::Mutex; @@ -2414,6 +2423,7 @@ fn test_vec_dedup() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_vec_dedup_panicking() { #[derive(Debug)] struct Panic<'a> { @@ -2470,6 +2480,7 @@ fn test_vec_dedup_panicking() { // Regression test for issue #82533 #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_extend_from_within_panicking_clone() { struct Panic<'dc> { drop_count: &'dc AtomicU32, diff --git a/alloc/tests/vec_deque.rs b/alloc/tests/vec_deque.rs index ddc27e34e..f6fb1f73e 100644 --- a/alloc/tests/vec_deque.rs +++ b/alloc/tests/vec_deque.rs @@ -747,6 +747,7 @@ fn test_drop_clear() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drop_panic() { static mut DROPS: i32 = 0; @@ -1601,6 +1602,7 @@ fn test_try_rfold_moves_iter() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn truncate_leak() { static mut DROPS: i32 = 0; @@ -1634,6 +1636,7 @@ fn truncate_leak() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_leak() { static mut DROPS: i32 = 0; diff --git a/core/tests/array.rs b/core/tests/array.rs index 0869644c0..982d7853f 100644 --- a/core/tests/array.rs +++ b/core/tests/array.rs @@ -257,14 +257,8 @@ fn iterator_drops() { assert_eq!(i.get(), 5); } -// This test does not work on targets without panic=unwind support. -// To work around this problem, test is marked is should_panic, so it will -// be automagically skipped on unsuitable targets, such as -// wasm32-unknown-unknown. -// -// It means that we use panic for indicating success. -#[test] -#[should_panic(expected = "test succeeded")] +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn array_default_impl_avoids_leaks_on_panic() { use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; static COUNTER: AtomicUsize = AtomicUsize::new(0); @@ -296,7 +290,6 @@ fn array_default_impl_avoids_leaks_on_panic() { assert_eq!(*panic_msg, "bomb limit exceeded"); // check that all bombs are successfully dropped assert_eq!(COUNTER.load(Relaxed), 0); - panic!("test succeeded") } #[test] @@ -317,9 +310,8 @@ fn array_map() { assert_eq!(b, [1, 2, 3]); } -// See note on above test for why `should_panic` is used. #[test] -#[should_panic(expected = "test succeeded")] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn array_map_drop_safety() { static DROPPED: AtomicUsize = AtomicUsize::new(0); struct DropCounter; @@ -341,7 +333,6 @@ fn array_map_drop_safety() { }); assert!(success.is_err()); assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); - panic!("test succeeded") } #[test] diff --git a/test/src/tests.rs b/test/src/tests.rs index c34583e69..4ef18b14f 100644 --- a/test/src/tests.rs +++ b/test/src/tests.rs @@ -154,6 +154,7 @@ pub fn ignored_tests_result_in_ignored() { // 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> { panic!(); @@ -184,6 +185,7 @@ fn test_should_panic() { // 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> { panic!("an error message"); @@ -214,6 +216,7 @@ fn test_should_panic_good_message() { // 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; fn f() -> Result<(), String> { @@ -249,6 +252,7 @@ fn test_should_panic_bad_message() { // 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 crate::tests::TrFailedMsg; use std::any::TypeId; @@ -288,6 +292,7 @@ fn test_should_panic_non_string_message_type() { // 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 30aed8a5ee6f8957e1398e2a345e1a76e25434d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20B=C3=B6ving?= Date: Tue, 13 Jun 2023 20:20:17 +0000 Subject: [PATCH 095/180] fix: get the l4re target working again --- std/src/personality.rs | 2 +- std/src/sys/unix/l4re.rs | 6 +++++- std/src/sys/unix/process/process_unix.rs | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/std/src/personality.rs b/std/src/personality.rs index 63f0ad4f1..386a399f5 100644 --- a/std/src/personality.rs +++ b/std/src/personality.rs @@ -29,7 +29,7 @@ cfg_if::cfg_if! { all(target_family = "windows", target_env = "gnu"), target_os = "psp", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf")), + all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod gcc; diff --git a/std/src/sys/unix/l4re.rs b/std/src/sys/unix/l4re.rs index ee016887e..fe9559f2a 100644 --- a/std/src/sys/unix/l4re.rs +++ b/std/src/sys/unix/l4re.rs @@ -10,7 +10,7 @@ macro_rules! unimpl { pub mod net { #![allow(warnings)] use crate::fmt; - use crate::io::{self, IoSlice, IoSliceMut}; + 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; @@ -218,6 +218,10 @@ pub mod net { unimpl!(); } + pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> { + unimpl!(); + } + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { unimpl!(); } diff --git a/std/src/sys/unix/process/process_unix.rs b/std/src/sys/unix/process/process_unix.rs index 3721988b4..22d9d6141 100644 --- a/std/src/sys/unix/process/process_unix.rs +++ b/std/src/sys/unix/process/process_unix.rs @@ -836,31 +836,47 @@ fn signal_string(signal: i32) -> &'static str { libc::SIGILL => " (SIGILL)", libc::SIGTRAP => " (SIGTRAP)", libc::SIGABRT => " (SIGABRT)", + #[cfg(not(target_os = "l4re"))] libc::SIGBUS => " (SIGBUS)", libc::SIGFPE => " (SIGFPE)", libc::SIGKILL => " (SIGKILL)", + #[cfg(not(target_os = "l4re"))] libc::SIGUSR1 => " (SIGUSR1)", libc::SIGSEGV => " (SIGSEGV)", + #[cfg(not(target_os = "l4re"))] libc::SIGUSR2 => " (SIGUSR2)", libc::SIGPIPE => " (SIGPIPE)", libc::SIGALRM => " (SIGALRM)", libc::SIGTERM => " (SIGTERM)", + #[cfg(not(target_os = "l4re"))] libc::SIGCHLD => " (SIGCHLD)", + #[cfg(not(target_os = "l4re"))] libc::SIGCONT => " (SIGCONT)", + #[cfg(not(target_os = "l4re"))] libc::SIGSTOP => " (SIGSTOP)", + #[cfg(not(target_os = "l4re"))] libc::SIGTSTP => " (SIGTSTP)", + #[cfg(not(target_os = "l4re"))] libc::SIGTTIN => " (SIGTTIN)", + #[cfg(not(target_os = "l4re"))] libc::SIGTTOU => " (SIGTTOU)", + #[cfg(not(target_os = "l4re"))] libc::SIGURG => " (SIGURG)", + #[cfg(not(target_os = "l4re"))] libc::SIGXCPU => " (SIGXCPU)", + #[cfg(not(target_os = "l4re"))] libc::SIGXFSZ => " (SIGXFSZ)", + #[cfg(not(target_os = "l4re"))] libc::SIGVTALRM => " (SIGVTALRM)", + #[cfg(not(target_os = "l4re"))] libc::SIGPROF => " (SIGPROF)", + #[cfg(not(target_os = "l4re"))] libc::SIGWINCH => " (SIGWINCH)", - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "haiku", target_os = "l4re")))] libc::SIGIO => " (SIGIO)", #[cfg(target_os = "haiku")] libc::SIGPOLL => " (SIGPOLL)", + #[cfg(not(target_os = "l4re"))] libc::SIGSYS => " (SIGSYS)", // For information on Linux signals, run `man 7 signal` #[cfg(all( From f24820aa658c5a15555aa2163f072455c03450fd Mon Sep 17 00:00:00 2001 From: ltdk Date: Tue, 13 Jun 2023 22:30:38 -0400 Subject: [PATCH 096/180] Alter `Display` for `Ipv6Addr` for IPv4-compatible addresses --- core/src/net/ip_addr.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/src/net/ip_addr.rs b/core/src/net/ip_addr.rs index 954d88d54..c51913fa8 100644 --- a/core/src/net/ip_addr.rs +++ b/core/src/net/ip_addr.rs @@ -1770,14 +1770,8 @@ impl fmt::Display for Ipv6Addr { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4() { - match segments[5] { - // IPv4 Compatible address - 0 => write!(f, "::{}", ipv4), - // IPv4 Mapped address - 0xffff => write!(f, "::ffff:{}", ipv4), - _ => unreachable!(), - } + } else if let Some(ipv4) = self.to_ipv4_mapped() { + write!(f, "::ffff:{}", ipv4) } else { #[derive(Copy, Clone, Default)] struct Span { From b2883343899bc28adfdbcc777d5845894e09db8b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 13 Jun 2023 21:45:04 -0700 Subject: [PATCH 097/180] Bump stdarch --- stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdarch b/stdarch index 7e2cdc675..d77878b72 160000 --- a/stdarch +++ b/stdarch @@ -1 +1 @@ -Subproject commit 7e2cdc675b92165c5f8c4c794620252be4605e74 +Subproject commit d77878b7299dd7e286799a6e8447048b65d2a861 From 566a10ca6927d6b8869285667b43874cb13196ef Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 15 Nov 2022 19:50:11 +0100 Subject: [PATCH 098/180] remove drain-on-drop behavior from vec::DrainFilter and add #[must_use] --- alloc/src/vec/drain_filter.rs | 106 +++++----------------------------- alloc/src/vec/mod.rs | 6 ++ alloc/tests/vec.rs | 31 +--------- 3 files changed, 22 insertions(+), 121 deletions(-) diff --git a/alloc/src/vec/drain_filter.rs b/alloc/src/vec/drain_filter.rs index 21b090234..ebee3d6ec 100644 --- a/alloc/src/vec/drain_filter.rs +++ b/alloc/src/vec/drain_filter.rs @@ -1,5 +1,4 @@ use crate::alloc::{Allocator, Global}; -use core::mem::{ManuallyDrop, SizedTypeProperties}; use core::ptr; use core::slice; @@ -20,6 +19,7 @@ use super::Vec; /// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[derive(Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] pub struct DrainFilter< 'a, T, @@ -55,59 +55,6 @@ where pub fn allocator(&self) -> &A { self.vec.allocator() } - - /// Keep unyielded elements in the source `Vec`. - /// - /// # Examples - /// - /// ``` - /// #![feature(drain_filter)] - /// #![feature(drain_keep_rest)] - /// - /// let mut vec = vec!['a', 'b', 'c']; - /// let mut drain = vec.drain_filter(|_| true); - /// - /// assert_eq!(drain.next().unwrap(), 'a'); - /// - /// // This call keeps 'b' and 'c' in the vec. - /// drain.keep_rest(); - /// - /// // If we wouldn't call `keep_rest()`, - /// // `vec` would be empty. - /// assert_eq!(vec, ['b', 'c']); - /// ``` - #[unstable(feature = "drain_keep_rest", issue = "101122")] - pub fn keep_rest(self) { - // At this moment layout looks like this: - // - // _____________________/-- old_len - // / \ - // [kept] [yielded] [tail] - // \_______/ ^-- idx - // \-- del - // - // Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`) - // - // 1. Move [tail] after [kept] - // 2. Update length of the original vec to `old_len - del` - // a. In case of ZST, this is the only thing we want to do - // 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do - let mut this = ManuallyDrop::new(self); - - unsafe { - // ZSTs have no identity, so we don't need to move them around. - if !T::IS_ZST && this.idx < this.old_len && this.del > 0 { - let ptr = this.vec.as_mut_ptr(); - let src = ptr.add(this.idx); - let dst = src.sub(this.del); - let tail_len = this.old_len - this.idx; - src.copy_to(dst, tail_len); - } - - let new_len = this.old_len - this.del; - this.vec.set_len(new_len); - } - } } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] @@ -154,44 +101,21 @@ where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> - where - F: FnMut(&mut T) -> bool, - { - drain: &'b mut DrainFilter<'a, T, F, A>, - } - - impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> - where - F: FnMut(&mut T) -> bool, - { - fn drop(&mut self) { - unsafe { - if self.drain.idx < self.drain.old_len && self.drain.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.drain.vec.as_mut_ptr(); - let src = ptr.add(self.drain.idx); - let dst = src.sub(self.drain.del); - let tail_len = self.drain.old_len - self.drain.idx; - src.copy_to(dst, tail_len); - } - self.drain.vec.set_len(self.drain.old_len - self.drain.del); - } + 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); + let tail_len = self.old_len - self.idx; + src.copy_to(dst, tail_len); } - } - - let backshift = BackshiftOnDrop { drain: self }; - - // Attempt to consume any remaining elements if the filter predicate - // has not yet panicked. We'll backshift any remaining elements - // whether we've already panicked or if the consumption here panics. - if !backshift.drain.panic_flag { - backshift.drain.for_each(drop); + self.vec.set_len(self.old_len - self.del); } } } diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index d89cdff8e..75f1a96c4 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2892,6 +2892,12 @@ impl Vec { /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// + /// If the returned `DrainFilter` 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. + /// + /// [`retain`]: Vec::retain + /// /// Using this method is equivalent to the following code: /// /// ``` diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index 155431689..acb744ad9 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1608,36 +1608,7 @@ fn drain_filter_unconsumed() { let mut vec = vec![1, 2, 3, 4]; let drain = vec.drain_filter(|&mut x| x % 2 != 0); drop(drain); - assert_eq!(vec, [2, 4]); -} - -#[test] -fn test_drain_filter_keep_rest() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6]; - let mut drain = v.drain_filter(|&mut x| x % 2 == 0); - assert_eq!(drain.next(), Some(0)); - assert_eq!(drain.next(), Some(2)); - - drain.keep_rest(); - assert_eq!(v, &[1, 3, 4, 5, 6]); -} - -#[test] -fn test_drain_filter_keep_rest_all() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6]; - v.drain_filter(|_| true).keep_rest(); - assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]); -} - -#[test] -fn test_drain_filter_keep_rest_none() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6]; - let mut drain = v.drain_filter(|_| true); - - drain.by_ref().for_each(drop); - - drain.keep_rest(); - assert_eq!(v, &[]); + assert_eq!(vec, [1, 2, 3, 4]); } #[test] From 002ee8eccc1c668e4aab7e01bceddee0f15746ab Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 15 Nov 2022 19:51:24 +0100 Subject: [PATCH 099/180] remove drain-on-drop behavior from BTree{Set,Map}::DrainFilter and add #[must_use] --- alloc/src/collections/btree/map.rs | 24 ++++----------- alloc/src/collections/btree/map/tests.rs | 39 +++++++++++++----------- alloc/src/collections/btree/set.rs | 24 ++++----------- alloc/src/collections/btree/set/tests.rs | 11 ++++--- 4 files changed, 40 insertions(+), 58 deletions(-) diff --git a/alloc/src/collections/btree/map.rs b/alloc/src/collections/btree/map.rs index 1f8a1ecba..4f50cdefc 100644 --- a/alloc/src/collections/btree/map.rs +++ b/alloc/src/collections/btree/map.rs @@ -1132,7 +1132,7 @@ impl BTreeMap { K: Ord, F: FnMut(&K, &mut V) -> bool, { - self.drain_filter(|k, v| !f(k, v)); + self.drain_filter(|k, v| !f(k, v)).for_each(drop); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -1395,14 +1395,11 @@ impl BTreeMap { /// The iterator also lets you mutate the value of each element in the /// closure, regardless of whether you choose to keep or remove it. /// - /// If the iterator is only partially consumed or not consumed at all, each - /// of the remaining elements is still subjected to the closure, which may - /// change its value and, by returning `true`, have the element removed and - /// dropped. + /// If the returned `DrainFilter` 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. /// - /// It is unspecified how many more elements will be subjected to the - /// closure if a panic occurs in the closure, or a panic occurs while - /// dropping an element, or if the `DrainFilter` value is leaked. + /// [`retain`]: BTreeMap::retain /// /// # Examples /// @@ -1901,6 +1898,7 @@ impl Default for Values<'_, K, V> { /// An iterator produced by calling `drain_filter` on BTreeMap. #[unstable(feature = "btree_drain_filter", issue = "70530")] +#[must_use = "iterators are lazy and do nothing unless consumed"] pub struct DrainFilter< 'a, K, @@ -1929,16 +1927,6 @@ pub(super) struct DrainFilterInner<'a, K, V> { cur_leaf_edge: Option, K, V, marker::Leaf>, marker::Edge>>, } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl Drop for DrainFilter<'_, K, V, F, A> -where - F: FnMut(&K, &mut V) -> bool, -{ - fn drop(&mut self) { - self.for_each(drop); - } -} - #[unstable(feature = "btree_drain_filter", issue = "70530")] impl fmt::Debug for DrainFilter<'_, K, V, F> where diff --git a/alloc/src/collections/btree/map/tests.rs b/alloc/src/collections/btree/map/tests.rs index 8efd9a03a..1b9957fcd 100644 --- a/alloc/src/collections/btree/map/tests.rs +++ b/alloc/src/collections/btree/map/tests.rs @@ -947,7 +947,7 @@ mod test_drain_filter { #[test] fn empty() { let mut map: BTreeMap = BTreeMap::new(); - map.drain_filter(|_, _| unreachable!("there's nothing to decide on")); + map.drain_filter(|_, _| unreachable!("there's nothing to decide on")).for_each(drop); assert_eq!(map.height(), None); map.check(); } @@ -1008,7 +1008,7 @@ mod test_drain_filter { fn underfull_keeping_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| false); + map.drain_filter(|_, _| false).for_each(drop); assert!(map.keys().copied().eq(0..3)); map.check(); } @@ -1018,7 +1018,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); for doomed in 0..3 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed); + map.drain_filter(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), 2); map.check(); } @@ -1029,7 +1029,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); for sacred in 0..3 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred); + map.drain_filter(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1039,7 +1039,7 @@ mod test_drain_filter { fn underfull_removing_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true); + map.drain_filter(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1048,7 +1048,7 @@ mod test_drain_filter { fn height_0_keeping_all() { let pairs = (0..node::CAPACITY).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| false); + map.drain_filter(|_, _| false).for_each(drop); assert!(map.keys().copied().eq(0..node::CAPACITY)); map.check(); } @@ -1058,7 +1058,7 @@ mod test_drain_filter { let pairs = (0..node::CAPACITY).map(|i| (i, i)); for doomed in 0..node::CAPACITY { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed); + map.drain_filter(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), node::CAPACITY - 1); map.check(); } @@ -1069,7 +1069,7 @@ mod test_drain_filter { let pairs = (0..node::CAPACITY).map(|i| (i, i)); for sacred in 0..node::CAPACITY { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred); + map.drain_filter(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1079,7 +1079,7 @@ mod test_drain_filter { fn height_0_removing_all() { let pairs = (0..node::CAPACITY).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true); + map.drain_filter(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1096,7 +1096,7 @@ mod test_drain_filter { fn height_1_removing_all() { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true); + map.drain_filter(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1106,7 +1106,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); for doomed in 0..MIN_INSERTS_HEIGHT_1 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed); + map.drain_filter(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1); map.check(); } @@ -1117,7 +1117,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); for sacred in 0..MIN_INSERTS_HEIGHT_1 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred); + map.drain_filter(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1128,7 +1128,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); for doomed in (0..MIN_INSERTS_HEIGHT_2).step_by(12) { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed); + map.drain_filter(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1); map.check(); } @@ -1139,7 +1139,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); for sacred in (0..MIN_INSERTS_HEIGHT_2).step_by(12) { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred); + map.drain_filter(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1149,7 +1149,7 @@ mod test_drain_filter { fn height_2_removing_all() { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true); + map.drain_filter(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1165,7 +1165,8 @@ mod test_drain_filter { map.insert(b.spawn(Panic::InDrop), ()); map.insert(c.spawn(Panic::Never), ()); - catch_unwind(move || drop(map.drain_filter(|dummy, _| dummy.query(true)))).unwrap_err(); + catch_unwind(move || map.drain_filter(|dummy, _| dummy.query(true)).for_each(drop)) + .unwrap_err(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); @@ -1186,8 +1187,10 @@ mod test_drain_filter { map.insert(b.spawn(Panic::InQuery), ()); map.insert(c.spawn(Panic::InQuery), ()); - catch_unwind(AssertUnwindSafe(|| drop(map.drain_filter(|dummy, _| dummy.query(true))))) - .unwrap_err(); + catch_unwind(AssertUnwindSafe(|| { + map.drain_filter(|dummy, _| dummy.query(true)).for_each(drop) + })) + .unwrap_err(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 940fa30af..d8f34a7fa 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -999,7 +999,7 @@ impl BTreeSet { T: Ord, F: FnMut(&T) -> bool, { - self.drain_filter(|v| !f(v)); + self.drain_filter(|v| !f(v)).for_each(drop); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -1084,14 +1084,11 @@ impl BTreeSet { /// yielded. If the closure returns `false`, or panics, the element remains /// in the set and will not be yielded. /// - /// If the iterator is only partially consumed or not consumed at all, each - /// of the remaining elements is still subjected to the closure and removed - /// and dropped if it returns `true`. - /// - /// It is unspecified how many more elements will be subjected to the - /// closure if a panic occurs in the closure, or if a panic occurs while - /// dropping an element, or if the `DrainFilter` itself is leaked. + /// If the returned `DrainFilter` 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. /// + /// [`retain`]: BTreeSet::retain /// # Examples /// /// Splitting a set into even and odd values, reusing the original set: @@ -1277,6 +1274,7 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet { /// An iterator produced by calling `drain_filter` on BTreeSet. #[unstable(feature = "btree_drain_filter", issue = "70530")] +#[must_use = "iterators are lazy and do nothing unless consumed"] pub struct DrainFilter< 'a, T, @@ -1292,16 +1290,6 @@ pub struct DrainFilter< alloc: A, } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl Drop for DrainFilter<'_, T, F, A> -where - F: FnMut(&T) -> bool, -{ - fn drop(&mut self) { - self.for_each(drop); - } -} - #[unstable(feature = "btree_drain_filter", issue = "70530")] impl fmt::Debug for DrainFilter<'_, T, F, A> where diff --git a/alloc/src/collections/btree/set/tests.rs b/alloc/src/collections/btree/set/tests.rs index 8eb730f4a..9e4be2f67 100644 --- a/alloc/src/collections/btree/set/tests.rs +++ b/alloc/src/collections/btree/set/tests.rs @@ -370,8 +370,8 @@ fn test_drain_filter() { let mut x = BTreeSet::from([1]); let mut y = BTreeSet::from([1]); - x.drain_filter(|_| true); - y.drain_filter(|_| false); + x.drain_filter(|_| true).for_each(drop); + y.drain_filter(|_| false).for_each(drop); assert_eq!(x.len(), 0); assert_eq!(y.len(), 1); } @@ -387,7 +387,7 @@ fn test_drain_filter_drop_panic_leak() { set.insert(b.spawn(Panic::InDrop)); set.insert(c.spawn(Panic::Never)); - catch_unwind(move || drop(set.drain_filter(|dummy| dummy.query(true)))).ok(); + catch_unwind(move || set.drain_filter(|dummy| dummy.query(true)).for_each(drop)).ok(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); @@ -408,7 +408,10 @@ fn test_drain_filter_pred_panic_leak() { set.insert(b.spawn(Panic::InQuery)); set.insert(c.spawn(Panic::InQuery)); - catch_unwind(AssertUnwindSafe(|| drop(set.drain_filter(|dummy| dummy.query(true))))).ok(); + catch_unwind(AssertUnwindSafe(|| { + set.drain_filter(|dummy| dummy.query(true)).for_each(drop) + })) + .ok(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); From af4efeb852e0fbc5a582fc056076cbd2138202a6 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 15 Nov 2022 19:51:49 +0100 Subject: [PATCH 100/180] remove drain-on-drop behavior from linked_list::DrainFilter and add #[must_use] --- alloc/src/collections/linked_list.rs | 32 ++++------------------ alloc/src/collections/linked_list/tests.rs | 12 ++++++-- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/alloc/src/collections/linked_list.rs b/alloc/src/collections/linked_list.rs index 4cd34ac2f..2e00e286e 100644 --- a/alloc/src/collections/linked_list.rs +++ b/alloc/src/collections/linked_list.rs @@ -1030,6 +1030,10 @@ impl LinkedList { /// If the closure returns false, the element will remain in the list and will not be yielded /// by the iterator. /// + /// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use `drain_filter().for_each(drop)` if you do not need the returned iterator. + /// /// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of /// whether you choose to keep or remove it. /// @@ -1805,6 +1809,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// An iterator produced by calling `drain_filter` on LinkedList. #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +#[must_use = "iterators are lazy and do nothing unless consumed"] pub struct DrainFilter< 'a, T: 'a, @@ -1849,33 +1854,6 @@ where } } -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - fn drop(&mut self) { - struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>) - where - F: FnMut(&mut T) -> bool; - - impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A> - where - F: FnMut(&mut T) -> bool, - { - fn drop(&mut self) { - self.0.for_each(drop); - } - } - - while let Some(item) = self.next() { - let guard = DropGuard(self); - drop(item); - mem::forget(guard); - } - } -} - #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] impl fmt::Debug for DrainFilter<'_, T, F> where diff --git a/alloc/src/collections/linked_list/tests.rs b/alloc/src/collections/linked_list/tests.rs index 6a0ea6183..7627b3e8b 100644 --- a/alloc/src/collections/linked_list/tests.rs +++ b/alloc/src/collections/linked_list/tests.rs @@ -1005,17 +1005,23 @@ fn drain_filter_drop_panic_leak() { q.push_front(d1.spawn(Panic::InDrop)); q.push_front(d0.spawn(Panic::Never)); - catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err(); + catch_unwind(AssertUnwindSafe(|| q.drain_filter(|_| true).for_each(drop))).unwrap_err(); assert_eq!(d0.dropped(), 1); assert_eq!(d1.dropped(), 1); + assert_eq!(d2.dropped(), 0); + assert_eq!(d3.dropped(), 0); + assert_eq!(d4.dropped(), 0); + assert_eq!(d5.dropped(), 0); + assert_eq!(d6.dropped(), 0); + assert_eq!(d7.dropped(), 0); + drop(q); assert_eq!(d2.dropped(), 1); assert_eq!(d3.dropped(), 1); assert_eq!(d4.dropped(), 1); assert_eq!(d5.dropped(), 1); assert_eq!(d6.dropped(), 1); assert_eq!(d7.dropped(), 1); - assert!(q.is_empty()); } #[test] @@ -1045,7 +1051,7 @@ fn drain_filter_pred_panic_leak() { q.push_front(D(0)); catch_unwind(AssertUnwindSafe(|| { - drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true })) + q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop) })) .ok(); From 5a0e770f7c8b100506eadfb8c31a39265394d373 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 9 Apr 2023 00:37:21 +0200 Subject: [PATCH 101/180] s/drain_filter/extract_if/ for Vec, Btree{Map,Set} and LinkedList --- alloc/benches/btree/map.rs | 12 ++-- alloc/benches/btree/set.rs | 8 +-- alloc/benches/lib.rs | 2 +- alloc/src/collections/btree/map.rs | 56 +++++++++---------- alloc/src/collections/btree/map/tests.rs | 56 +++++++++---------- alloc/src/collections/btree/set.rs | 41 +++++++------- alloc/src/collections/btree/set/tests.rs | 26 ++++----- alloc/src/collections/linked_list.rs | 32 +++++------ alloc/src/collections/linked_list/tests.rs | 42 +++++++------- .../vec/{drain_filter.rs => extract_if.rs} | 22 ++++---- alloc/src/vec/mod.rs | 22 ++++---- alloc/tests/autotraits.rs | 6 +- alloc/tests/lib.rs | 4 +- alloc/tests/vec.rs | 44 +++++++-------- 14 files changed, 184 insertions(+), 189 deletions(-) rename alloc/src/vec/{drain_filter.rs => extract_if.rs} (83%) diff --git a/alloc/benches/btree/map.rs b/alloc/benches/btree/map.rs index ec1b0a8eb..7d2366477 100644 --- a/alloc/benches/btree/map.rs +++ b/alloc/benches/btree/map.rs @@ -385,7 +385,7 @@ pub fn clone_slim_100_and_clear(b: &mut Bencher) { #[bench] pub fn clone_slim_100_and_drain_all(b: &mut Bencher) { let src = slim_map(100); - b.iter(|| src.clone().drain_filter(|_, _| true).count()) + b.iter(|| src.clone().extract_if(|_, _| true).count()) } #[bench] @@ -393,7 +393,7 @@ pub fn clone_slim_100_and_drain_half(b: &mut Bencher) { let src = slim_map(100); b.iter(|| { let mut map = src.clone(); - assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 100 / 2); + assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2); assert_eq!(map.len(), 100 / 2); }) } @@ -456,7 +456,7 @@ pub fn clone_slim_10k_and_clear(b: &mut Bencher) { #[bench] pub fn clone_slim_10k_and_drain_all(b: &mut Bencher) { let src = slim_map(10_000); - b.iter(|| src.clone().drain_filter(|_, _| true).count()) + b.iter(|| src.clone().extract_if(|_, _| true).count()) } #[bench] @@ -464,7 +464,7 @@ pub fn clone_slim_10k_and_drain_half(b: &mut Bencher) { let src = slim_map(10_000); b.iter(|| { let mut map = src.clone(); - assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 10_000 / 2); + assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 10_000 / 2); assert_eq!(map.len(), 10_000 / 2); }) } @@ -527,7 +527,7 @@ pub fn clone_fat_val_100_and_clear(b: &mut Bencher) { #[bench] pub fn clone_fat_val_100_and_drain_all(b: &mut Bencher) { let src = fat_val_map(100); - b.iter(|| src.clone().drain_filter(|_, _| true).count()) + b.iter(|| src.clone().extract_if(|_, _| true).count()) } #[bench] @@ -535,7 +535,7 @@ pub fn clone_fat_val_100_and_drain_half(b: &mut Bencher) { let src = fat_val_map(100); b.iter(|| { let mut map = src.clone(); - assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 100 / 2); + assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2); assert_eq!(map.len(), 100 / 2); }) } diff --git a/alloc/benches/btree/set.rs b/alloc/benches/btree/set.rs index 3f4b0e0f1..09d72c720 100644 --- a/alloc/benches/btree/set.rs +++ b/alloc/benches/btree/set.rs @@ -69,7 +69,7 @@ pub fn clone_100_and_clear(b: &mut Bencher) { #[bench] pub fn clone_100_and_drain_all(b: &mut Bencher) { let src = slim_set(100); - b.iter(|| src.clone().drain_filter(|_| true).count()) + b.iter(|| src.clone().extract_if(|_| true).count()) } #[bench] @@ -77,7 +77,7 @@ pub fn clone_100_and_drain_half(b: &mut Bencher) { let src = slim_set(100); b.iter(|| { let mut set = src.clone(); - assert_eq!(set.drain_filter(|i| i % 2 == 0).count(), 100 / 2); + assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 100 / 2); assert_eq!(set.len(), 100 / 2); }) } @@ -140,7 +140,7 @@ pub fn clone_10k_and_clear(b: &mut Bencher) { #[bench] pub fn clone_10k_and_drain_all(b: &mut Bencher) { let src = slim_set(10_000); - b.iter(|| src.clone().drain_filter(|_| true).count()) + b.iter(|| src.clone().extract_if(|_| true).count()) } #[bench] @@ -148,7 +148,7 @@ pub fn clone_10k_and_drain_half(b: &mut Bencher) { let src = slim_set(10_000); b.iter(|| { let mut set = src.clone(); - assert_eq!(set.drain_filter(|i| i % 2 == 0).count(), 10_000 / 2); + assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 10_000 / 2); assert_eq!(set.len(), 10_000 / 2); }) } diff --git a/alloc/benches/lib.rs b/alloc/benches/lib.rs index b25d63d83..638f343fb 100644 --- a/alloc/benches/lib.rs +++ b/alloc/benches/lib.rs @@ -1,7 +1,7 @@ // Disabling on android for the time being // See https://github.com/rust-lang/rust/issues/73535#event-3477699747 #![cfg(not(target_os = "android"))] -#![feature(btree_drain_filter)] +#![feature(btree_extract_if)] #![feature(iter_next_chunk)] #![feature(repr_simd)] #![feature(slice_partition_dedup)] diff --git a/alloc/src/collections/btree/map.rs b/alloc/src/collections/btree/map.rs index 4f50cdefc..ff908ec12 100644 --- a/alloc/src/collections/btree/map.rs +++ b/alloc/src/collections/btree/map.rs @@ -1132,7 +1132,7 @@ impl BTreeMap { K: Ord, F: FnMut(&K, &mut V) -> bool, { - self.drain_filter(|k, v| !f(k, v)).for_each(drop); + self.extract_if(|k, v| !f(k, v)).for_each(drop); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -1395,7 +1395,7 @@ impl BTreeMap { /// The iterator also lets you mutate the value of each element in the /// closure, regardless of whether you choose to keep or remove it. /// - /// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating + /// 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. /// @@ -1406,26 +1406,26 @@ impl BTreeMap { /// Splitting a map into even and odd keys, reusing the original map: /// /// ``` - /// #![feature(btree_drain_filter)] + /// #![feature(btree_extract_if)] /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap = (0..8).map(|x| (x, x)).collect(); - /// let evens: BTreeMap<_, _> = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).collect(); /// let odds = map; /// assert_eq!(evens.keys().copied().collect::>(), [0, 2, 4, 6]); /// assert_eq!(odds.keys().copied().collect::>(), [1, 3, 5, 7]); /// ``` - #[unstable(feature = "btree_drain_filter", issue = "70530")] - pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, K, V, F, A> + #[unstable(feature = "btree_extract_if", issue = "70530")] + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A> where K: Ord, F: FnMut(&K, &mut V) -> bool, { - let (inner, alloc) = self.drain_filter_inner(); - DrainFilter { pred, inner, alloc } + let (inner, alloc) = self.extract_if_inner(); + ExtractIf { pred, inner, alloc } } - pub(super) fn drain_filter_inner(&mut self) -> (DrainFilterInner<'_, K, V>, A) + pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A) where K: Ord, { @@ -1433,7 +1433,7 @@ impl BTreeMap { let (root, dormant_root) = DormantMutRef::new(root); let front = root.borrow_mut().first_leaf_edge(); ( - DrainFilterInner { + ExtractIfInner { length: &mut self.length, dormant_root: Some(dormant_root), cur_leaf_edge: Some(front), @@ -1442,7 +1442,7 @@ impl BTreeMap { ) } else { ( - DrainFilterInner { + ExtractIfInner { length: &mut self.length, dormant_root: None, cur_leaf_edge: None, @@ -1896,10 +1896,10 @@ impl Default for Values<'_, K, V> { } } -/// An iterator produced by calling `drain_filter` on BTreeMap. -#[unstable(feature = "btree_drain_filter", issue = "70530")] +/// An iterator produced by calling `extract_if` on BTreeMap. +#[unstable(feature = "btree_extract_if", issue = "70530")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct DrainFilter< +pub struct ExtractIf< 'a, K, V, @@ -1909,13 +1909,13 @@ pub struct DrainFilter< F: 'a + FnMut(&K, &mut V) -> bool, { pred: F, - inner: DrainFilterInner<'a, K, V>, + inner: ExtractIfInner<'a, K, V>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. alloc: A, } -/// Most of the implementation of DrainFilter are generic over the type -/// of the predicate, thus also serving for BTreeSet::DrainFilter. -pub(super) struct DrainFilterInner<'a, K, V> { +/// Most of the implementation of ExtractIf are generic over the type +/// of the predicate, thus also serving for BTreeSet::ExtractIf. +pub(super) struct ExtractIfInner<'a, K, V> { /// Reference to the length field in the borrowed map, updated live. length: &'a mut usize, /// Buried reference to the root field in the borrowed map. @@ -1927,20 +1927,20 @@ pub(super) struct DrainFilterInner<'a, K, V> { cur_leaf_edge: Option, K, V, marker::Leaf>, marker::Edge>>, } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl fmt::Debug for DrainFilter<'_, K, V, F> +#[unstable(feature = "btree_extract_if", issue = "70530")] +impl fmt::Debug for ExtractIf<'_, K, V, F> where K: fmt::Debug, V: fmt::Debug, F: FnMut(&K, &mut V) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DrainFilter").field(&self.inner.peek()).finish() + f.debug_tuple("ExtractIf").field(&self.inner.peek()).finish() } } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl Iterator for DrainFilter<'_, K, V, F, A> +#[unstable(feature = "btree_extract_if", issue = "70530")] +impl Iterator for ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, { @@ -1955,14 +1955,14 @@ where } } -impl<'a, K, V> DrainFilterInner<'a, K, V> { +impl<'a, K, V> ExtractIfInner<'a, K, V> { /// Allow Debug implementations to predict the next element. pub(super) fn peek(&self) -> Option<(&K, &V)> { let edge = self.cur_leaf_edge.as_ref()?; edge.reborrow().next_kv().ok().map(Handle::into_kv) } - /// Implementation of a typical `DrainFilter::next` method, given the predicate. + /// Implementation of a typical `ExtractIf::next` method, given the predicate. pub(super) fn next(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)> where F: FnMut(&K, &mut V) -> bool, @@ -1989,7 +1989,7 @@ impl<'a, K, V> DrainFilterInner<'a, K, V> { None } - /// Implementation of a typical `DrainFilter::size_hint` method. + /// Implementation of a typical `ExtractIf::size_hint` method. pub(super) fn size_hint(&self) -> (usize, Option) { // In most of the btree iterators, `self.length` is the number of elements // yet to be visited. Here, it includes elements that were visited and that @@ -1999,8 +1999,8 @@ impl<'a, K, V> DrainFilterInner<'a, K, V> { } } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} +#[unstable(feature = "btree_extract_if", issue = "70530")] +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} #[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for Range<'a, K, V> { diff --git a/alloc/src/collections/btree/map/tests.rs b/alloc/src/collections/btree/map/tests.rs index 1b9957fcd..8681cfcd6 100644 --- a/alloc/src/collections/btree/map/tests.rs +++ b/alloc/src/collections/btree/map/tests.rs @@ -941,13 +941,13 @@ fn test_retain() { assert_eq!(map[&6], 60); } -mod test_drain_filter { +mod test_extract_if { use super::*; #[test] fn empty() { let mut map: BTreeMap = BTreeMap::new(); - map.drain_filter(|_, _| unreachable!("there's nothing to decide on")).for_each(drop); + map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop); assert_eq!(map.height(), None); map.check(); } @@ -957,7 +957,7 @@ mod test_drain_filter { fn consumed_keeping_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - assert!(map.drain_filter(|_, _| false).eq(iter::empty())); + assert!(map.extract_if(|_, _| false).eq(iter::empty())); map.check(); } @@ -966,7 +966,7 @@ mod test_drain_filter { fn consumed_removing_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs.clone()); - assert!(map.drain_filter(|_, _| true).eq(pairs)); + assert!(map.extract_if(|_, _| true).eq(pairs)); assert!(map.is_empty()); map.check(); } @@ -977,7 +977,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); assert!( - map.drain_filter(|_, v| { + map.extract_if(|_, v| { *v += 6; false }) @@ -994,7 +994,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); assert!( - map.drain_filter(|_, v| { + map.extract_if(|_, v| { *v += 6; true }) @@ -1008,7 +1008,7 @@ mod test_drain_filter { fn underfull_keeping_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| false).for_each(drop); + map.extract_if(|_, _| false).for_each(drop); assert!(map.keys().copied().eq(0..3)); map.check(); } @@ -1018,7 +1018,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); for doomed in 0..3 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed).for_each(drop); + map.extract_if(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), 2); map.check(); } @@ -1029,7 +1029,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); for sacred in 0..3 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred).for_each(drop); + map.extract_if(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1039,7 +1039,7 @@ mod test_drain_filter { fn underfull_removing_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true).for_each(drop); + map.extract_if(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1048,7 +1048,7 @@ mod test_drain_filter { fn height_0_keeping_all() { let pairs = (0..node::CAPACITY).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| false).for_each(drop); + map.extract_if(|_, _| false).for_each(drop); assert!(map.keys().copied().eq(0..node::CAPACITY)); map.check(); } @@ -1058,7 +1058,7 @@ mod test_drain_filter { let pairs = (0..node::CAPACITY).map(|i| (i, i)); for doomed in 0..node::CAPACITY { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed).for_each(drop); + map.extract_if(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), node::CAPACITY - 1); map.check(); } @@ -1069,7 +1069,7 @@ mod test_drain_filter { let pairs = (0..node::CAPACITY).map(|i| (i, i)); for sacred in 0..node::CAPACITY { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred).for_each(drop); + map.extract_if(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1079,7 +1079,7 @@ mod test_drain_filter { fn height_0_removing_all() { let pairs = (0..node::CAPACITY).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true).for_each(drop); + map.extract_if(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1087,7 +1087,7 @@ mod test_drain_filter { #[test] fn height_0_keeping_half() { let mut map = BTreeMap::from_iter((0..16).map(|i| (i, i))); - assert_eq!(map.drain_filter(|i, _| *i % 2 == 0).count(), 8); + assert_eq!(map.extract_if(|i, _| *i % 2 == 0).count(), 8); assert_eq!(map.len(), 8); map.check(); } @@ -1096,7 +1096,7 @@ mod test_drain_filter { fn height_1_removing_all() { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true).for_each(drop); + map.extract_if(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1106,7 +1106,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); for doomed in 0..MIN_INSERTS_HEIGHT_1 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed).for_each(drop); + map.extract_if(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1); map.check(); } @@ -1117,7 +1117,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); for sacred in 0..MIN_INSERTS_HEIGHT_1 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred).for_each(drop); + map.extract_if(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1128,7 +1128,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); for doomed in (0..MIN_INSERTS_HEIGHT_2).step_by(12) { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i == doomed).for_each(drop); + map.extract_if(|i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1); map.check(); } @@ -1139,7 +1139,7 @@ mod test_drain_filter { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); for sacred in (0..MIN_INSERTS_HEIGHT_2).step_by(12) { let mut map = BTreeMap::from_iter(pairs.clone()); - map.drain_filter(|i, _| *i != sacred).for_each(drop); + map.extract_if(|i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1149,7 +1149,7 @@ mod test_drain_filter { fn height_2_removing_all() { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.drain_filter(|_, _| true).for_each(drop); + map.extract_if(|_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1165,7 +1165,7 @@ mod test_drain_filter { map.insert(b.spawn(Panic::InDrop), ()); map.insert(c.spawn(Panic::Never), ()); - catch_unwind(move || map.drain_filter(|dummy, _| dummy.query(true)).for_each(drop)) + catch_unwind(move || map.extract_if(|dummy, _| dummy.query(true)).for_each(drop)) .unwrap_err(); assert_eq!(a.queried(), 1); @@ -1188,7 +1188,7 @@ mod test_drain_filter { map.insert(c.spawn(Panic::InQuery), ()); catch_unwind(AssertUnwindSafe(|| { - map.drain_filter(|dummy, _| dummy.query(true)).for_each(drop) + map.extract_if(|dummy, _| dummy.query(true)).for_each(drop) })) .unwrap_err(); @@ -1217,7 +1217,7 @@ mod test_drain_filter { map.insert(c.spawn(Panic::InQuery), ()); { - let mut it = map.drain_filter(|dummy, _| dummy.query(true)); + let mut it = map.extract_if(|dummy, _| dummy.query(true)); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); // Iterator behaviour after a panic is explicitly unspecified, // so this is just the current implementation: @@ -1660,8 +1660,8 @@ fn assert_sync() { v.into_values() } - fn drain_filter(v: &mut BTreeMap) -> impl Sync + '_ { - v.drain_filter(|_, _| false) + fn extract_if(v: &mut BTreeMap) -> impl Sync + '_ { + v.extract_if(|_, _| false) } fn iter(v: &BTreeMap) -> impl Sync + '_ { @@ -1729,8 +1729,8 @@ fn assert_send() { v.into_values() } - fn drain_filter(v: &mut BTreeMap) -> impl Send + '_ { - v.drain_filter(|_, _| false) + fn extract_if(v: &mut BTreeMap) -> impl Send + '_ { + v.extract_if(|_, _| false) } fn iter(v: &BTreeMap) -> impl Send + '_ { diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index d8f34a7fa..c4461040b 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -999,7 +999,7 @@ impl BTreeSet { T: Ord, F: FnMut(&T) -> bool, { - self.drain_filter(|v| !f(v)).for_each(drop); + self.extract_if(|v| !f(v)).for_each(drop); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -1084,7 +1084,7 @@ impl BTreeSet { /// yielded. If the closure returns `false`, or panics, the element remains /// in the set and will not be yielded. /// - /// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating + /// 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. /// @@ -1094,23 +1094,23 @@ impl BTreeSet { /// Splitting a set into even and odd values, reusing the original set: /// /// ``` - /// #![feature(btree_drain_filter)] + /// #![feature(btree_extract_if)] /// use std::collections::BTreeSet; /// /// let mut set: BTreeSet = (0..8).collect(); - /// let evens: BTreeSet<_> = set.drain_filter(|v| v % 2 == 0).collect(); + /// let evens: BTreeSet<_> = set.extract_if(|v| v % 2 == 0).collect(); /// let odds = set; /// assert_eq!(evens.into_iter().collect::>(), vec![0, 2, 4, 6]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 7]); /// ``` - #[unstable(feature = "btree_drain_filter", issue = "70530")] - pub fn drain_filter<'a, F>(&'a mut self, pred: F) -> DrainFilter<'a, T, F, A> + #[unstable(feature = "btree_extract_if", issue = "70530")] + pub fn extract_if<'a, F>(&'a mut self, pred: F) -> ExtractIf<'a, T, F, A> where T: Ord, F: 'a + FnMut(&T) -> bool, { - let (inner, alloc) = self.map.drain_filter_inner(); - DrainFilter { pred, inner, alloc } + let (inner, alloc) = self.map.extract_if_inner(); + ExtractIf { pred, inner, alloc } } /// Gets an iterator that visits the elements in the `BTreeSet` in ascending @@ -1272,10 +1272,10 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet { } } -/// An iterator produced by calling `drain_filter` on BTreeSet. -#[unstable(feature = "btree_drain_filter", issue = "70530")] +/// An iterator produced by calling `extract_if` on BTreeSet. +#[unstable(feature = "btree_extract_if", issue = "70530")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct DrainFilter< +pub struct ExtractIf< 'a, T, F, @@ -1285,24 +1285,24 @@ pub struct DrainFilter< F: 'a + FnMut(&T) -> bool, { pred: F, - inner: super::map::DrainFilterInner<'a, T, SetValZST>, + inner: super::map::ExtractIfInner<'a, T, SetValZST>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. alloc: A, } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl fmt::Debug for DrainFilter<'_, T, F, A> +#[unstable(feature = "btree_extract_if", issue = "70530")] +impl fmt::Debug for ExtractIf<'_, T, F, A> where T: fmt::Debug, F: FnMut(&T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DrainFilter").field(&self.inner.peek().map(|(k, _)| k)).finish() + f.debug_tuple("ExtractIf").field(&self.inner.peek().map(|(k, _)| k)).finish() } } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, T, F, A: Allocator + Clone> Iterator for DrainFilter<'_, T, F, A> +#[unstable(feature = "btree_extract_if", issue = "70530")] +impl<'a, T, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, F, A> where F: 'a + FnMut(&T) -> bool, { @@ -1319,11 +1319,8 @@ where } } -#[unstable(feature = "btree_drain_filter", issue = "70530")] -impl FusedIterator for DrainFilter<'_, T, F, A> where - F: FnMut(&T) -> bool -{ -} +#[unstable(feature = "btree_extract_if", issue = "70530")] +impl FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool {} #[stable(feature = "rust1", since = "1.0.0")] impl Extend for BTreeSet { diff --git a/alloc/src/collections/btree/set/tests.rs b/alloc/src/collections/btree/set/tests.rs index 9e4be2f67..e05bf0e20 100644 --- a/alloc/src/collections/btree/set/tests.rs +++ b/alloc/src/collections/btree/set/tests.rs @@ -366,19 +366,19 @@ fn test_retain() { } #[test] -fn test_drain_filter() { +fn test_extract_if() { let mut x = BTreeSet::from([1]); let mut y = BTreeSet::from([1]); - x.drain_filter(|_| true).for_each(drop); - y.drain_filter(|_| false).for_each(drop); + x.extract_if(|_| true).for_each(drop); + y.extract_if(|_| false).for_each(drop); assert_eq!(x.len(), 0); assert_eq!(y.len(), 1); } #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_drain_filter_drop_panic_leak() { +fn test_extract_if_drop_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); let c = CrashTestDummy::new(2); @@ -387,7 +387,7 @@ fn test_drain_filter_drop_panic_leak() { set.insert(b.spawn(Panic::InDrop)); set.insert(c.spawn(Panic::Never)); - catch_unwind(move || set.drain_filter(|dummy| dummy.query(true)).for_each(drop)).ok(); + catch_unwind(move || set.extract_if(|dummy| dummy.query(true)).for_each(drop)).ok(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); @@ -399,7 +399,7 @@ fn test_drain_filter_drop_panic_leak() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_drain_filter_pred_panic_leak() { +fn test_extract_if_pred_panic_leak() { let a = CrashTestDummy::new(0); let b = CrashTestDummy::new(1); let c = CrashTestDummy::new(2); @@ -408,10 +408,8 @@ fn test_drain_filter_pred_panic_leak() { set.insert(b.spawn(Panic::InQuery)); set.insert(c.spawn(Panic::InQuery)); - catch_unwind(AssertUnwindSafe(|| { - set.drain_filter(|dummy| dummy.query(true)).for_each(drop) - })) - .ok(); + catch_unwind(AssertUnwindSafe(|| set.extract_if(|dummy| dummy.query(true)).for_each(drop))) + .ok(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); @@ -608,8 +606,8 @@ fn assert_sync() { v.range(..) } - fn drain_filter(v: &mut BTreeSet) -> impl Sync + '_ { - v.drain_filter(|_| false) + fn extract_if(v: &mut BTreeSet) -> impl Sync + '_ { + v.extract_if(|_| false) } fn difference(v: &BTreeSet) -> impl Sync + '_ { @@ -647,8 +645,8 @@ fn assert_send() { v.range(..) } - fn drain_filter(v: &mut BTreeSet) -> impl Send + '_ { - v.drain_filter(|_| false) + fn extract_if(v: &mut BTreeSet) -> impl Send + '_ { + v.extract_if(|_| false) } fn difference(v: &BTreeSet) -> impl Send + '_ { diff --git a/alloc/src/collections/linked_list.rs b/alloc/src/collections/linked_list.rs index 2e00e286e..052edf453 100644 --- a/alloc/src/collections/linked_list.rs +++ b/alloc/src/collections/linked_list.rs @@ -1030,11 +1030,11 @@ impl LinkedList { /// If the closure returns false, the element will remain in the list and will not be yielded /// by the iterator. /// - /// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating + /// 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 `drain_filter().for_each(drop)` if you do not need the returned iterator. + /// Use `extract_if().for_each(drop)` if you do not need the returned iterator. /// - /// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of + /// Note that `extract_if` lets you mutate every element in the filter closure, regardless of /// whether you choose to keep or remove it. /// /// # Examples @@ -1042,20 +1042,20 @@ impl LinkedList { /// Splitting a list into evens and odds, reusing the original list: /// /// ``` - /// #![feature(drain_filter)] + /// #![feature(extract_if)] /// use std::collections::LinkedList; /// /// let mut numbers: LinkedList = LinkedList::new(); /// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); /// - /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::>(); + /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::>(); /// let odds = numbers; /// /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); /// ``` - #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F, A> + #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] + pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -1063,7 +1063,7 @@ impl LinkedList { let it = self.head; let old_len = self.len; - DrainFilter { list: self, it, pred: filter, idx: 0, old_len } + ExtractIf { list: self, it, pred: filter, idx: 0, old_len } } } @@ -1807,10 +1807,10 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { } } -/// An iterator produced by calling `drain_filter` on LinkedList. -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +/// An iterator produced by calling `extract_if` on LinkedList. +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct DrainFilter< +pub struct ExtractIf< 'a, T: 'a, F: 'a, @@ -1825,8 +1825,8 @@ pub struct DrainFilter< old_len: usize, } -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F, A> +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -1854,13 +1854,13 @@ where } } -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl fmt::Debug for DrainFilter<'_, T, F> +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl fmt::Debug for ExtractIf<'_, T, F> where F: FnMut(&mut T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DrainFilter").field(&self.list).finish() + f.debug_tuple("ExtractIf").field(&self.list).finish() } } diff --git a/alloc/src/collections/linked_list/tests.rs b/alloc/src/collections/linked_list/tests.rs index 7627b3e8b..8dcd59d12 100644 --- a/alloc/src/collections/linked_list/tests.rs +++ b/alloc/src/collections/linked_list/tests.rs @@ -540,10 +540,10 @@ fn test_show() { } #[test] -fn drain_filter_test() { +fn extract_if_test() { let mut m: LinkedList = LinkedList::new(); m.extend(&[1, 2, 3, 4, 5, 6]); - let deleted = m.drain_filter(|v| *v < 4).collect::>(); + let deleted = m.extract_if(|v| *v < 4).collect::>(); check_links(&m); @@ -555,7 +555,7 @@ fn drain_filter_test() { fn drain_to_empty_test() { let mut m: LinkedList = LinkedList::new(); m.extend(&[1, 2, 3, 4, 5, 6]); - let deleted = m.drain_filter(|_| true).collect::>(); + let deleted = m.extract_if(|_| true).collect::>(); check_links(&m); @@ -811,11 +811,11 @@ fn test_contains() { } #[test] -fn drain_filter_empty() { +fn extract_if_empty() { let mut list: LinkedList = LinkedList::new(); { - let mut iter = list.drain_filter(|_| true); + let mut iter = list.extract_if(|_| true); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); assert_eq!(iter.size_hint(), (0, Some(0))); @@ -828,13 +828,13 @@ fn drain_filter_empty() { } #[test] -fn drain_filter_zst() { +fn extract_if_zst() { let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect(); let initial_len = list.len(); let mut count = 0; { - let mut iter = list.drain_filter(|_| true); + let mut iter = list.extract_if(|_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -851,14 +851,14 @@ fn drain_filter_zst() { } #[test] -fn drain_filter_false() { +fn extract_if_false() { let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); let initial_len = list.len(); let mut count = 0; { - let mut iter = list.drain_filter(|_| false); + let mut iter = list.extract_if(|_| false); assert_eq!(iter.size_hint(), (0, Some(initial_len))); for _ in iter.by_ref() { count += 1; @@ -874,14 +874,14 @@ fn drain_filter_false() { } #[test] -fn drain_filter_true() { +fn extract_if_true() { let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); let initial_len = list.len(); let mut count = 0; { - let mut iter = list.drain_filter(|_| true); + let mut iter = list.extract_if(|_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -898,7 +898,7 @@ fn drain_filter_true() { } #[test] -fn drain_filter_complex() { +fn extract_if_complex() { { // [+xxx++++++xxxxx++++x+x++] let mut list = [ @@ -908,7 +908,7 @@ fn drain_filter_complex() { .into_iter() .collect::>(); - let removed = list.drain_filter(|x| *x % 2 == 0).collect::>(); + let removed = list.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]); @@ -926,7 +926,7 @@ fn drain_filter_complex() { .into_iter() .collect::>(); - let removed = list.drain_filter(|x| *x % 2 == 0).collect::>(); + let removed = list.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]); @@ -944,7 +944,7 @@ fn drain_filter_complex() { .into_iter() .collect::>(); - let removed = list.drain_filter(|x| *x % 2 == 0).collect::>(); + let removed = list.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]); @@ -961,7 +961,7 @@ fn drain_filter_complex() { .into_iter() .collect::>(); - let removed = list.drain_filter(|x| *x % 2 == 0).collect::>(); + let removed = list.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]); @@ -975,7 +975,7 @@ fn drain_filter_complex() { .into_iter() .collect::>(); - let removed = list.drain_filter(|x| *x % 2 == 0).collect::>(); + let removed = list.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]); @@ -986,7 +986,7 @@ fn drain_filter_complex() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn drain_filter_drop_panic_leak() { +fn extract_if_drop_panic_leak() { let d0 = CrashTestDummy::new(0); let d1 = CrashTestDummy::new(1); let d2 = CrashTestDummy::new(2); @@ -1005,7 +1005,7 @@ fn drain_filter_drop_panic_leak() { q.push_front(d1.spawn(Panic::InDrop)); q.push_front(d0.spawn(Panic::Never)); - catch_unwind(AssertUnwindSafe(|| q.drain_filter(|_| true).for_each(drop))).unwrap_err(); + catch_unwind(AssertUnwindSafe(|| q.extract_if(|_| true).for_each(drop))).unwrap_err(); assert_eq!(d0.dropped(), 1); assert_eq!(d1.dropped(), 1); @@ -1026,7 +1026,7 @@ fn drain_filter_drop_panic_leak() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn drain_filter_pred_panic_leak() { +fn extract_if_pred_panic_leak() { static mut DROPS: i32 = 0; #[derive(Debug)] @@ -1051,7 +1051,7 @@ fn drain_filter_pred_panic_leak() { q.push_front(D(0)); catch_unwind(AssertUnwindSafe(|| { - q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop) + q.extract_if(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop) })) .ok(); diff --git a/alloc/src/vec/drain_filter.rs b/alloc/src/vec/extract_if.rs similarity index 83% rename from alloc/src/vec/drain_filter.rs rename to alloc/src/vec/extract_if.rs index ebee3d6ec..e8e6bd56d 100644 --- a/alloc/src/vec/drain_filter.rs +++ b/alloc/src/vec/extract_if.rs @@ -6,21 +6,21 @@ use super::Vec; /// An iterator which uses a closure to determine if an element should be removed. /// -/// This struct is created by [`Vec::drain_filter`]. +/// This struct is created by [`Vec::extract_if`]. /// See its documentation for more. /// /// # Example /// /// ``` -/// #![feature(drain_filter)] +/// #![feature(extract_if)] /// /// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0); +/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0); /// ``` -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] #[derive(Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct DrainFilter< +pub struct ExtractIf< 'a, T, F, @@ -39,13 +39,13 @@ pub struct DrainFilter< pub(super) pred: F, /// A flag that indicates a panic has occurred in the filter test predicate. /// This is used as a hint in the drop implementation to prevent consumption - /// of the remainder of the `DrainFilter`. Any unprocessed items will be + /// of the remainder of the `ExtractIf`. Any unprocessed items will be /// backshifted in the `vec`, but no further items will be dropped or /// tested by the filter predicate. pub(super) panic_flag: bool, } -impl DrainFilter<'_, T, F, A> +impl ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -57,8 +57,8 @@ where } } -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F, A> +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -95,8 +95,8 @@ where } } -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F, A> +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl Drop for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 75f1a96c4..289bbc7d2 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -71,10 +71,10 @@ use crate::boxed::Box; use crate::collections::TryReserveError; use crate::raw_vec::RawVec; -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -pub use self::drain_filter::DrainFilter; +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +pub use self::extract_if::ExtractIf; -mod drain_filter; +mod extract_if; #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_splice", since = "1.21.0")] @@ -2892,7 +2892,7 @@ impl Vec { /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// - /// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating + /// 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. /// @@ -2916,10 +2916,10 @@ impl Vec { /// # assert_eq!(vec, vec![1, 4, 5]); /// ``` /// - /// But `drain_filter` is easier to use. `drain_filter` is also more efficient, + /// 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 `drain_filter` also lets you mutate every element in the filter closure, + /// Note that `extract_if` also lets you mutate every element in the filter closure, /// regardless of whether you choose to keep or remove it. /// /// # Examples @@ -2927,17 +2927,17 @@ impl Vec { /// Splitting an array into evens and odds, reusing the original allocation: /// /// ``` - /// #![feature(drain_filter)] + /// #![feature(extract_if)] /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// - /// let evens = numbers.drain_filter(|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]); /// ``` - #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F, A> + #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] + pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -2948,7 +2948,7 @@ impl Vec { self.set_len(0); } - DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false } + ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false } } } diff --git a/alloc/tests/autotraits.rs b/alloc/tests/autotraits.rs index 879e32b3f..6a8e55bff 100644 --- a/alloc/tests/autotraits.rs +++ b/alloc/tests/autotraits.rs @@ -55,7 +55,7 @@ fn test_btree_map() { require_send_sync(async { let _v = None::< - alloc::collections::btree_map::DrainFilter< + alloc::collections::btree_map::ExtractIf< '_, &u32, &u32, @@ -149,7 +149,7 @@ fn test_btree_set() { }); require_send_sync(async { - let _v = None:: bool>>; + let _v = None:: bool>>; async {}.await; }); @@ -238,7 +238,7 @@ fn test_linked_list() { /* require_send_sync(async { let _v = - None:: bool>>; + None:: bool>>; async {}.await; }); */ diff --git a/alloc/tests/lib.rs b/alloc/tests/lib.rs index 0eca4c9bb..aa7a331b3 100644 --- a/alloc/tests/lib.rs +++ b/alloc/tests/lib.rs @@ -1,7 +1,7 @@ #![feature(allocator_api)] #![feature(alloc_layout_extra)] #![feature(assert_matches)] -#![feature(btree_drain_filter)] +#![feature(btree_extract_if)] #![feature(cow_is_borrowed)] #![feature(const_cow_is_borrowed)] #![feature(const_heap)] @@ -10,7 +10,7 @@ #![feature(const_ptr_write)] #![feature(const_try)] #![feature(core_intrinsics)] -#![feature(drain_filter)] +#![feature(extract_if)] #![feature(exact_size_is_empty)] #![feature(linked_list_cursors)] #![feature(map_try_insert)] diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index acb744ad9..21824c8a1 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1347,11 +1347,11 @@ fn overaligned_allocations() { } #[test] -fn drain_filter_empty() { +fn extract_if_empty() { let mut vec: Vec = vec![]; { - let mut iter = vec.drain_filter(|_| 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))); @@ -1363,12 +1363,12 @@ fn drain_filter_empty() { } #[test] -fn drain_filter_zst() { +fn extract_if_zst() { let mut vec = vec![(), (), (), (), ()]; let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.drain_filter(|_| true); + let mut iter = vec.extract_if(|_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1385,13 +1385,13 @@ fn drain_filter_zst() { } #[test] -fn drain_filter_false() { +fn extract_if_false() { let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.drain_filter(|_| false); + let mut iter = vec.extract_if(|_| false); assert_eq!(iter.size_hint(), (0, Some(initial_len))); for _ in iter.by_ref() { count += 1; @@ -1407,13 +1407,13 @@ fn drain_filter_false() { } #[test] -fn drain_filter_true() { +fn extract_if_true() { let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.drain_filter(|_| true); + let mut iter = vec.extract_if(|_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1430,7 +1430,7 @@ fn drain_filter_true() { } #[test] -fn drain_filter_complex() { +fn extract_if_complex() { { // [+xxx++++++xxxxx++++x+x++] let mut vec = vec![ @@ -1438,7 +1438,7 @@ fn drain_filter_complex() { 39, ]; - let removed = vec.drain_filter(|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]); @@ -1452,7 +1452,7 @@ fn drain_filter_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.drain_filter(|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]); @@ -1465,7 +1465,7 @@ fn drain_filter_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.drain_filter(|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]); @@ -1477,7 +1477,7 @@ fn drain_filter_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.drain_filter(|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]); @@ -1489,7 +1489,7 @@ fn drain_filter_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.drain_filter(|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]); @@ -1502,7 +1502,7 @@ fn drain_filter_complex() { #[test] #[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn drain_filter_consumed_panic() { +fn extract_if_consumed_panic() { use std::rc::Rc; use std::sync::Mutex; @@ -1537,9 +1537,9 @@ fn drain_filter_consumed_panic() { } c.index < 6 }; - let drain = data.drain_filter(filter); + let drain = data.extract_if(filter); - // NOTE: The DrainFilter is explicitly consumed + // NOTE: The ExtractIf is explicitly consumed drain.for_each(drop); }); @@ -1555,7 +1555,7 @@ fn drain_filter_consumed_panic() { #[test] #[cfg(not(target_os = "emscripten"))] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn drain_filter_unconsumed_panic() { +fn extract_if_unconsumed_panic() { use std::rc::Rc; use std::sync::Mutex; @@ -1590,9 +1590,9 @@ fn drain_filter_unconsumed_panic() { } c.index < 6 }; - let _drain = data.drain_filter(filter); + let _drain = data.extract_if(filter); - // NOTE: The DrainFilter is dropped without being consumed + // NOTE: The ExtractIf is dropped without being consumed }); let drop_counts = drop_counts.lock().unwrap(); @@ -1604,9 +1604,9 @@ fn drain_filter_unconsumed_panic() { } #[test] -fn drain_filter_unconsumed() { +fn extract_if_unconsumed() { let mut vec = vec![1, 2, 3, 4]; - let drain = vec.drain_filter(|&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 6acd7ee78dcea93e4d40616192818127eecb0d18 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 8 Jun 2023 16:55:49 +0200 Subject: [PATCH 102/180] update hashbrown and replace Hash{Set,Map}::DrainFilter with ExtractIf --- std/Cargo.toml | 2 +- std/src/collections/hash/map.rs | 52 +++++++++++++-------------- std/src/collections/hash/map/tests.rs | 26 +++++++------- std/src/collections/hash/set.rs | 49 +++++++++++++------------ std/src/collections/hash/set/tests.rs | 22 ++++++------ 5 files changed, 77 insertions(+), 74 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 4b52894c5..e6b051838 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -21,7 +21,7 @@ libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-o compiler_builtins = { version = "0.1.92" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.13", default-features = false, features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index c722bad2e..f3316d97c 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -623,28 +623,27 @@ impl HashMap { /// If the closure returns false, or panics, the element remains in the map and will not be /// yielded. /// - /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of /// whether you choose to keep or remove it. /// - /// If the iterator is only partially consumed or not consumed at all, each of the remaining - /// elements will still be subjected to the closure and removed and dropped if it returns true. + /// 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. /// - /// It is unspecified how many more elements will be subjected to the closure - /// if a panic occurs in the closure, or a panic occurs while dropping an element, - /// or if the `DrainFilter` value is leaked. + /// [`retain`]: HashMap::retain /// /// # Examples /// /// Splitting a map into even and odd keys, reusing the original map: /// /// ``` - /// #![feature(hash_drain_filter)] + /// #![feature(hash_extract_if)] /// use std::collections::HashMap; /// /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); - /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// let extracted: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); /// - /// let mut evens = drained.keys().copied().collect::>(); + /// let mut evens = extracted.keys().copied().collect::>(); /// let mut odds = map.keys().copied().collect::>(); /// evens.sort(); /// odds.sort(); @@ -654,12 +653,12 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[unstable(feature = "hash_drain_filter", issue = "59618")] - pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, K, V, F> + #[unstable(feature = "hash_extract_if", issue = "59618")] + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, { - DrainFilter { base: self.base.drain_filter(pred) } + ExtractIf { base: self.base.extract_if(pred) } } /// Retains only the elements specified by the predicate. @@ -1578,28 +1577,29 @@ impl<'a, K, V> Drain<'a, K, V> { /// A draining, filtering iterator over the entries of a `HashMap`. /// -/// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. /// -/// [`drain_filter`]: HashMap::drain_filter +/// [`extract_if`]: HashMap::extract_if /// /// # Example /// /// ``` -/// #![feature(hash_drain_filter)] +/// #![feature(hash_extract_if)] /// /// use std::collections::HashMap; /// /// let mut map = HashMap::from([ /// ("a", 1), /// ]); -/// let iter = map.drain_filter(|_k, v| *v % 2 == 0); +/// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[unstable(feature = "hash_drain_filter", issue = "59618")] -pub struct DrainFilter<'a, K, V, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ExtractIf<'a, K, V, F> where F: FnMut(&K, &mut V) -> bool, { - base: base::DrainFilter<'a, K, V, F>, + base: base::ExtractIf<'a, K, V, F>, } /// A mutable iterator over the values of a `HashMap`. @@ -2479,8 +2479,8 @@ where } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl Iterator for DrainFilter<'_, K, V, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, { @@ -2496,16 +2496,16 @@ where } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> where F: FnMut(&K, &mut V) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DrainFilter").finish_non_exhaustive() + f.debug_struct("ExtractIf").finish_non_exhaustive() } } diff --git a/std/src/collections/hash/map/tests.rs b/std/src/collections/hash/map/tests.rs index 6b89518e2..91a3776e7 100644 --- a/std/src/collections/hash/map/tests.rs +++ b/std/src/collections/hash/map/tests.rs @@ -944,7 +944,7 @@ fn test_raw_entry() { } } -mod test_drain_filter { +mod test_extract_if { use super::*; use crate::panic::{catch_unwind, AssertUnwindSafe}; @@ -968,7 +968,7 @@ mod test_drain_filter { #[test] fn empty() { let mut map: HashMap = HashMap::new(); - map.drain_filter(|_, _| unreachable!("there's nothing to decide on")); + map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop); assert!(map.is_empty()); } @@ -976,7 +976,7 @@ mod test_drain_filter { fn consuming_nothing() { let pairs = (0..3).map(|i| (i, i)); let mut map: HashMap<_, _> = pairs.collect(); - assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty())); + assert!(map.extract_if(|_, _| false).eq_sorted(crate::iter::empty())); assert_eq!(map.len(), 3); } @@ -984,7 +984,7 @@ mod test_drain_filter { fn consuming_all() { let pairs = (0..3).map(|i| (i, i)); let mut map: HashMap<_, _> = pairs.clone().collect(); - assert!(map.drain_filter(|_, _| true).eq_sorted(pairs)); + assert!(map.extract_if(|_, _| true).eq_sorted(pairs)); assert!(map.is_empty()); } @@ -993,7 +993,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); let mut map: HashMap<_, _> = pairs.collect(); assert!( - map.drain_filter(|_, v| { + map.extract_if(|_, v| { *v += 6; false }) @@ -1008,7 +1008,7 @@ mod test_drain_filter { let pairs = (0..3).map(|i| (i, i)); let mut map: HashMap<_, _> = pairs.collect(); assert!( - map.drain_filter(|_, v| { + map.extract_if(|_, v| { *v += 6; true }) @@ -1034,14 +1034,15 @@ mod test_drain_filter { let mut map = (0..3).map(|i| (i, D)).collect::>(); catch_unwind(move || { - drop(map.drain_filter(|_, _| { + map.extract_if(|_, _| { PREDS.fetch_add(1, Ordering::SeqCst); true - })) + }) + .for_each(drop) }) .unwrap_err(); - assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(PREDS.load(Ordering::SeqCst), 2); assert_eq!(DROPS.load(Ordering::SeqCst), 3); } @@ -1060,10 +1061,11 @@ mod test_drain_filter { let mut map = (0..3).map(|i| (i, D)).collect::>(); catch_unwind(AssertUnwindSafe(|| { - drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { 0 => true, _ => panic!(), - })) + }) + .for_each(drop) })) .unwrap_err(); @@ -1088,7 +1090,7 @@ mod test_drain_filter { let mut map = (0..3).map(|i| (i, D)).collect::>(); { - let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + let mut it = map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { 0 => true, _ => panic!(), }); diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index ac906e682..5bf542629 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -262,25 +262,24 @@ impl HashSet { /// If the closure returns false, the value will remain in the list and will not be yielded /// by the iterator. /// - /// If the iterator is only partially consumed or not consumed at all, each of the remaining - /// values will still be subjected to the closure and removed and dropped if it returns true. + /// 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. /// - /// It is unspecified how many more values will be subjected to the closure - /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the - /// `DrainFilter` itself is leaked. + /// [`retain`]: HashSet::retain /// /// # Examples /// /// Splitting a set into even and odd values, reusing the original set: /// /// ``` - /// #![feature(hash_drain_filter)] + /// #![feature(hash_extract_if)] /// use std::collections::HashSet; /// /// let mut set: HashSet = (0..8).collect(); - /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// let extracted: HashSet = set.extract_if(|v| v % 2 == 0).collect(); /// - /// let mut evens = drained.into_iter().collect::>(); + /// let mut evens = extracted.into_iter().collect::>(); /// let mut odds = set.into_iter().collect::>(); /// evens.sort(); /// odds.sort(); @@ -290,12 +289,12 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[unstable(feature = "hash_drain_filter", issue = "59618")] - pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, T, F> + #[unstable(feature = "hash_extract_if", issue = "59618")] + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, { - DrainFilter { base: self.base.drain_filter(pred) } + ExtractIf { base: self.base.extract_if(pred) } } /// Retains only the elements specified by the predicate. @@ -1310,27 +1309,27 @@ pub struct Drain<'a, K: 'a> { /// A draining, filtering iterator over the items of a `HashSet`. /// -/// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. /// -/// [`drain_filter`]: HashSet::drain_filter +/// [`extract_if`]: HashSet::extract_if /// /// # Examples /// /// ``` -/// #![feature(hash_drain_filter)] +/// #![feature(hash_extract_if)] /// /// use std::collections::HashSet; /// /// let mut a = HashSet::from([1, 2, 3]); /// -/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0); +/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[unstable(feature = "hash_drain_filter", issue = "59618")] -pub struct DrainFilter<'a, K, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +pub struct ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, { - base: base::DrainFilter<'a, K, F>, + base: base::ExtractIf<'a, K, F>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1576,8 +1575,8 @@ impl fmt::Debug for Drain<'_, K> { } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl Iterator for DrainFilter<'_, K, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, { @@ -1593,16 +1592,16 @@ where } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DrainFilter").finish_non_exhaustive() + f.debug_struct("ExtractIf").finish_non_exhaustive() } } diff --git a/std/src/collections/hash/set/tests.rs b/std/src/collections/hash/set/tests.rs index 941a0450c..7ac9eae67 100644 --- a/std/src/collections/hash/set/tests.rs +++ b/std/src/collections/hash/set/tests.rs @@ -418,18 +418,18 @@ fn test_retain() { } #[test] -fn test_drain_filter() { +fn test_extract_if() { let mut x: HashSet<_> = [1].iter().copied().collect(); let mut y: HashSet<_> = [1].iter().copied().collect(); - x.drain_filter(|_| true); - y.drain_filter(|_| false); + x.extract_if(|_| true).for_each(drop); + y.extract_if(|_| false).for_each(drop); assert_eq!(x.len(), 0); assert_eq!(y.len(), 1); } #[test] -fn test_drain_filter_drop_panic_leak() { +fn test_extract_if_drop_panic_leak() { static PREDS: AtomicU32 = AtomicU32::new(0); static DROPS: AtomicU32 = AtomicU32::new(0); @@ -446,19 +446,20 @@ fn test_drain_filter_drop_panic_leak() { let mut set = (0..3).map(|i| D(i)).collect::>(); catch_unwind(move || { - drop(set.drain_filter(|_| { + set.extract_if(|_| { PREDS.fetch_add(1, Ordering::SeqCst); true - })) + }) + .for_each(drop) }) .ok(); - assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(PREDS.load(Ordering::SeqCst), 2); assert_eq!(DROPS.load(Ordering::SeqCst), 3); } #[test] -fn test_drain_filter_pred_panic_leak() { +fn test_extract_if_pred_panic_leak() { static PREDS: AtomicU32 = AtomicU32::new(0); static DROPS: AtomicU32 = AtomicU32::new(0); @@ -473,10 +474,11 @@ fn test_drain_filter_pred_panic_leak() { let mut set: HashSet<_> = (0..3).map(|_| D).collect(); catch_unwind(AssertUnwindSafe(|| { - drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) { + set.extract_if(|_| match PREDS.fetch_add(1, Ordering::SeqCst) { 0 => true, _ => panic!(), - })) + }) + .for_each(drop) })) .ok(); From ddea1a6600af6d0e46a87b11693ee576cb9d09e0 Mon Sep 17 00:00:00 2001 From: Antonios Barotsis Date: Wed, 14 Jun 2023 16:52:29 +0200 Subject: [PATCH 103/180] Fix typo --- core/src/iter/sources/successors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/iter/sources/successors.rs b/core/src/iter/sources/successors.rs index 99f058a90..6a6cbe905 100644 --- a/core/src/iter/sources/successors.rs +++ b/core/src/iter/sources/successors.rs @@ -22,7 +22,7 @@ where Successors { next: first, succ } } -/// An new iterator where each successive item is computed based on the preceding one. +/// A new iterator where each successive item is computed based on the preceding one. /// /// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. From 4cf3b36af1ce8a0c1b4951995f6e41f73ee967b8 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 14 Jun 2023 18:29:08 +0300 Subject: [PATCH 104/180] Mention `env!` in `option_env!`'s docs --- core/src/macros/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index c4134dbcd..45e5b7627 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -960,6 +960,8 @@ pub(crate) mod builtin { /// /// A compile time error is never emitted when using this macro regardless /// of whether the environment variable is present or not. + /// To emit a compile error if the environment variable is not present, + /// use the [`env!`] macro instead. /// /// # Examples /// From 700c908a64edd4c049e5a76d505f2cfd82625560 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 14 Jun 2023 14:25:25 -0400 Subject: [PATCH 105/180] Fix `Ipv6Addr: Display` tests --- core/tests/net/ip_addr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/tests/net/ip_addr.rs b/core/tests/net/ip_addr.rs index 5a6ac08c0..7530fc084 100644 --- a/core/tests/net/ip_addr.rs +++ b/core/tests/net/ip_addr.rs @@ -139,7 +139,7 @@ fn ipv6_addr_to_string() { // ipv4-compatible address let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); + assert_eq!(a1.to_string(), "::c000:280"); // v6 address with no zero segments assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); @@ -316,7 +316,7 @@ fn ip_properties() { check!("::", unspec); check!("::1", loopback); - check!("::0.0.0.2", global); + check!("::2", global); check!("1::", global); check!("fc00::"); check!("fdff:ffff::"); @@ -607,7 +607,7 @@ fn ipv6_properties() { check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + check!("::2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); From 749900bf11c2fa294ca3860dca2e0305cae076ed Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 14 Jun 2023 14:59:11 -0400 Subject: [PATCH 106/180] Fix `SocketAddrV6: Display` tests --- core/tests/net/socket_addr.rs | 2 +- std/src/net/socket_addr/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tests/net/socket_addr.rs b/core/tests/net/socket_addr.rs index 68c7cd94d..35a69cead 100644 --- a/core/tests/net/socket_addr.rs +++ b/core/tests/net/socket_addr.rs @@ -34,7 +34,7 @@ fn ipv6_socket_addr_to_string() { // IPv4-compatible address. assert_eq!( SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::192.0.2.128]:8080" + "[::c000:280]:8080" ); // IPv6 address with no zero segments. diff --git a/std/src/net/socket_addr/tests.rs b/std/src/net/socket_addr/tests.rs index dfc6dabbe..6a065cfba 100644 --- a/std/src/net/socket_addr/tests.rs +++ b/std/src/net/socket_addr/tests.rs @@ -85,7 +85,7 @@ fn ipv6_socket_addr_to_string() { // IPv4-compatible address. assert_eq!( SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::192.0.2.128]:8080" + "[::c000:280]:8080" ); // IPv6 address with no zero segments. From ebee2ffcd17da22f40ba796376753defb7b0e0fd Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 12 Jun 2023 14:06:24 +0200 Subject: [PATCH 107/180] use indexed loop instead of ptr bumping this seems to produce less IR --- core/src/slice/iter/macros.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/core/src/slice/iter/macros.rs b/core/src/slice/iter/macros.rs index dd809ca45..96a145e22 100644 --- a/core/src/slice/iter/macros.rs +++ b/core/src/slice/iter/macros.rs @@ -192,23 +192,33 @@ macro_rules! iterator { } #[inline] - fn fold(mut self, init: B, mut f: F) -> B + fn fold(self, init: B, mut f: F) -> B where F: FnMut(B, Self::Item) -> B, { - // Handling the 0-len case explicitly and then using a do-while style loop - // helps the optimizer. See issue #106288 + // this implementation consists of the following optimizations compared to the + // default implementation: + // - do-while loop, as is llvm's preferred loop shape, + // see https://releases.llvm.org/16.0.0/docs/LoopTerminology.html#more-canonical-loops + // - bumps an index instead of a pointer since the latter case inhibits + // some optimizations, see #111603 + // - avoids Option wrapping/matching if is_empty!(self) { return init; } let mut acc = init; - // SAFETY: The 0-len case was handled above so one loop iteration is guaranteed. - unsafe { - loop { - acc = f(acc, next_unchecked!(self)); - if is_empty!(self) { - break; - } + let mut i = 0; + let len = len!(self); + loop { + // SAFETY: the loop iterates `i in 0..len`, which always is in bounds of + // the slice allocation + acc = f(acc, unsafe { & $( $mut_ )? *self.ptr.add(i).as_ptr() }); + // SAFETY: `i` can't overflow since it'll only reach usize::MAX if the + // slice had that length, in which case we'll break out of the loop + // after the increment + i = unsafe { i.unchecked_add(1) }; + if i == len { + break; } } acc From 9be217472e00ceb19e2d8feaa9c6f7d483f591c2 Mon Sep 17 00:00:00 2001 From: zica <9918800@gmail.com> Date: Thu, 15 Jun 2023 11:14:24 +0800 Subject: [PATCH 108/180] Correct types in method descriptions of `NonZero*` types --- core/src/num/nonzero.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 7f06e170a..5939dedbd 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -348,7 +348,7 @@ macro_rules! nonzero_unsigned_operations { } /// Adds an unsigned integer to a non-zero value. - #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] /// /// # Examples /// @@ -579,7 +579,7 @@ macro_rules! nonzero_signed_operations { /// Checked absolute value. /// Checks for overflow and returns [`None`] if - #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] + #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")] /// The result cannot be zero. /// /// # Example @@ -800,7 +800,8 @@ macro_rules! nonzero_signed_operations { self.get().is_negative() } - /// Checked negation. Computes `-self`, returning `None` if `self == i32::MIN`. + /// Checked negation. Computes `-self`, + #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")] /// /// # Example /// @@ -859,8 +860,10 @@ macro_rules! nonzero_signed_operations { ((unsafe { $Ty::new_unchecked(result) }), overflow) } - /// Saturating negation. Computes `-self`, returning `MAX` if - /// `self == i32::MIN` instead of overflowing. + /// Saturating negation. Computes `-self`, + #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")] + #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")] + /// instead of overflowing. /// /// # Example /// @@ -993,7 +996,7 @@ macro_rules! nonzero_unsigned_signed_operations { } /// Multiplies two non-zero integers together. - #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] /// /// # Examples /// @@ -1102,11 +1105,11 @@ macro_rules! nonzero_unsigned_signed_operations { #[doc = sign_dependent_expr!{ $signedness ? if signed { - concat!("Return [`", stringify!($Int), "::MIN`] ", - "or [`", stringify!($Int), "::MAX`] on overflow.") + concat!("Return [`", stringify!($Ty), "::MIN`] ", + "or [`", stringify!($Ty), "::MAX`] on overflow.") } if unsigned { - concat!("Return [`", stringify!($Int), "::MAX`] on overflow.") + concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.") } }] /// From 8ef507a139bdd57ec6fe3623d5f98806701b2a74 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?= Date: Sun, 11 Jun 2023 23:44:28 +0800 Subject: [PATCH 109/180] Extend `unused_must_use` to cover block exprs --- core/src/primitive_docs.rs | 2 +- core/tests/ptr.rs | 2 +- std/src/primitive_docs.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/primitive_docs.rs b/core/src/primitive_docs.rs index 8266e8990..80289ca08 100644 --- a/core/src/primitive_docs.rs +++ b/core/src/primitive_docs.rs @@ -308,7 +308,7 @@ mod prim_never {} /// /// ```no_run /// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }; +/// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// /// USVs are also the exact set of values that may be encoded in UTF-8. Because diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index c02cd99cc..ee885adfe 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -1001,7 +1001,7 @@ fn nonnull_tagged_pointer_with_provenance() { assert_eq!(p.tag(), 3); assert_eq!(unsafe { *p.pointer().as_ptr() }, 10); - unsafe { Box::from_raw(p.pointer().as_ptr()) }; + unsafe { drop(Box::from_raw(p.pointer().as_ptr())) }; /// A non-null pointer type which carries several bits of metadata and maintains provenance. #[repr(transparent)] diff --git a/std/src/primitive_docs.rs b/std/src/primitive_docs.rs index 8266e8990..80289ca08 100644 --- a/std/src/primitive_docs.rs +++ b/std/src/primitive_docs.rs @@ -308,7 +308,7 @@ mod prim_never {} /// /// ```no_run /// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }; +/// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// /// USVs are also the exact set of values that may be encoded in UTF-8. Because From 3e5d3263cf84f6c1134ba2eb8e63ef3d23a662cc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 15 Jun 2023 19:07:51 +0300 Subject: [PATCH 110/180] privacy: Do not mark items reachable farther than their nominal visibility This commit reverts a change made in #111425. It was believed that this change was necessary for implementing type privacy lints, but #111801 showed that it was not necessary. Quite opposite, the revert fixes some issues. --- core/src/iter/adapters/flatten.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/iter/adapters/flatten.rs b/core/src/iter/adapters/flatten.rs index 2568aaf34..d3e454563 100644 --- a/core/src/iter/adapters/flatten.rs +++ b/core/src/iter/adapters/flatten.rs @@ -310,7 +310,7 @@ where /// Real logic of both `Flatten` and `FlatMap` which simply delegate to /// this type. #[derive(Clone, Debug)] -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] struct FlattenCompat { iter: Fuse, frontiter: Option, @@ -464,7 +464,7 @@ where } } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] impl Iterator for FlattenCompat where I: Iterator>, @@ -579,7 +579,7 @@ where } } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] impl DoubleEndedIterator for FlattenCompat where I: DoubleEndedIterator>, @@ -649,7 +649,7 @@ where } } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] unsafe impl TrustedLen for FlattenCompat::IntoIter> where @@ -657,7 +657,7 @@ where { } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] unsafe impl<'a, const N: usize, I, T> TrustedLen for FlattenCompat::IntoIter> where @@ -665,7 +665,7 @@ where { } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] unsafe impl<'a, const N: usize, I, T> TrustedLen for FlattenCompat::IntoIter> where From e3673d601a617716b2c6940ea3e321a38d812b99 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 15 Jun 2023 21:14:40 +0200 Subject: [PATCH 111/180] remove unused field since DrainFilter no longer continues draining when it's dropped the panic tracking is no longer needed. --- alloc/src/vec/extract_if.rs | 8 -------- alloc/src/vec/mod.rs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/alloc/src/vec/extract_if.rs b/alloc/src/vec/extract_if.rs index e8e6bd56d..118cfdb36 100644 --- a/alloc/src/vec/extract_if.rs +++ b/alloc/src/vec/extract_if.rs @@ -37,12 +37,6 @@ pub struct ExtractIf< pub(super) old_len: usize, /// The filter test predicate. pub(super) pred: F, - /// A flag that indicates a panic has occurred in the filter test predicate. - /// This is used as a hint in the drop implementation to prevent consumption - /// of the remainder of the `ExtractIf`. Any unprocessed items will be - /// backshifted in the `vec`, but no further items will be dropped or - /// tested by the filter predicate. - pub(super) panic_flag: bool, } impl ExtractIf<'_, T, F, A> @@ -69,9 +63,7 @@ where while self.idx < self.old_len { let i = self.idx; let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); - self.panic_flag = true; let drained = (self.pred)(&mut v[i]); - self.panic_flag = false; // Update the index *after* the predicate is called. If the index // is updated prior and the predicate panics, the element at this // index would be leaked. diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 289bbc7d2..259c659c7 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2948,7 +2948,7 @@ impl Vec { self.set_len(0); } - ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false } + ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter } } } From c43c3dda58edea1d1188240c1fd69edd613ea925 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 15 Jun 2023 15:56:00 -0700 Subject: [PATCH 112/180] std: only depend on dlmalloc for wasm*-unknown It was already filtered out for emscripten, but wasi doesn't need dlmalloc either since it reuses `unix/alloc.rs`. --- std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index e6b051838..af74efa6b 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -38,7 +38,7 @@ features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } rand_xorshift = "0.3.0" -[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] From d08ab8818632c3caca207ab3d448a23a1a375911 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Jun 2023 14:56:31 +0200 Subject: [PATCH 113/180] slice::from_raw_parts: mention no-wrap-around condition --- core/src/slice/raw.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/core/src/slice/raw.rs b/core/src/slice/raw.rs index 052fd34d0..48a6eb03b 100644 --- a/core/src/slice/raw.rs +++ b/core/src/slice/raw.rs @@ -32,7 +32,8 @@ use crate::ptr; /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// # Caveat @@ -125,7 +126,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// [valid]: ptr#safety @@ -179,15 +181,16 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. @@ -247,16 +250,17 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be accessed through any other pointer /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. From dc86e79ab71b6fe9189346d7f533895c2ed3ad40 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 13 Jun 2023 18:25:15 -0400 Subject: [PATCH 114/180] Launch a non-unwinding panic for misaligned pointer deref --- core/src/panicking.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/panicking.rs b/core/src/panicking.rs index 81be3fb22..f0fcdab00 100644 --- a/core/src/panicking.rs +++ b/core/src/panicking.rs @@ -166,14 +166,15 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref +#[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } - panic!( + panic_nounwind_fmt(format_args!( "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}" - ) + )) } /// Panic because we cannot unwind out of a function. From ce3edd7528c83ef69a41607f46cb63f528685fb6 Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Thu, 15 Jun 2023 17:43:23 +0200 Subject: [PATCH 115/180] `#[lang_item]` for `core::ptr::Unique` --- core/src/ptr/unique.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/ptr/unique.rs b/core/src/ptr/unique.rs index a853f15ed..ff7e91d3e 100644 --- a/core/src/ptr/unique.rs +++ b/core/src/ptr/unique.rs @@ -32,6 +32,8 @@ use crate::ptr::NonNull; )] #[doc(hidden)] #[repr(transparent)] +// Lang item used experimentally by Miri to define the semantics of `Unique`. +#[cfg_attr(not(bootstrap), lang = "ptr_unique")] pub struct Unique { pointer: NonNull, // NOTE: this marker has no consequences for variance, but is necessary From 26fd461d40a78587569296dabbd030acd855fbb5 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Mon, 1 Aug 2022 13:51:58 -0700 Subject: [PATCH 116/180] remove box_free and replace with drop impl --- alloc/src/alloc.rs | 7 +++++-- alloc/src/boxed.rs | 10 +++++++++- alloc/src/rc.rs | 16 +++++++--------- alloc/src/sync.rs | 16 +++++++--------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/alloc/src/alloc.rs b/alloc/src/alloc.rs index 8c4f6a73d..e24a0fe51 100644 --- a/alloc/src/alloc.rs +++ b/alloc/src/alloc.rs @@ -4,8 +4,10 @@ #[cfg(not(test))] use core::intrinsics; +#[cfg(all(bootstrap, not(test)))] use core::intrinsics::{min_align_of_val, size_of_val}; +#[cfg(all(bootstrap, not(test)))] use core::ptr::Unique; #[cfg(not(test))] use core::ptr::{self, NonNull}; @@ -335,14 +337,15 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg_attr(not(test), lang = "box_free")] +#[cfg(all(bootstrap, not(test)))] +#[lang = "box_free"] #[inline] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. // For example if `Box` is changed to `struct Box(Unique, A)`, // this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +unsafe fn box_free(ptr: Unique, alloc: A) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 1768687e8..8ef2bac92 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -1211,8 +1211,16 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { + #[inline] fn drop(&mut self) { - // FIXME: Do nothing, drop is currently performed by compiler. + // the T in the Box is dropped by the compiler before the destructor is run + + let ptr = self.0; + + unsafe { + let layout = Layout::for_value_raw(ptr.as_ptr()); + self.1.deallocate(From::from(ptr.cast()), layout) + } } } diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 38a711ac7..34d3acae5 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -270,7 +270,7 @@ use core::slice::from_raw_parts_mut; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{box_free, WriteCloneIntoRaw}; +use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(no_global_oom_handling))] @@ -1442,23 +1442,21 @@ impl Rc { } #[cfg(not(no_global_oom_handling))] - fn from_box(v: Box) -> Rc { + fn from_box(src: Box) -> Rc { unsafe { - let (box_unique, alloc) = Box::into_unique(v); - let bptr = box_unique.as_ptr(); - - let value_size = size_of_val(&*bptr); - let ptr = Self::allocate_for_ptr(bptr); + let value_size = size_of_val(&*src); + let ptr = Self::allocate_for_ptr(&*src); // Copy value as bytes ptr::copy_nonoverlapping( - bptr as *const T as *const u8, + &*src as *const T as *const u8, &mut (*ptr).value as *mut _ as *mut u8, value_size, ); // Free the allocation without dropping its contents - box_free(box_unique, alloc); + let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop); + drop(src); Self::from_ptr(ptr) } diff --git a/alloc/src/sync.rs b/alloc/src/sync.rs index bfdb7a92b..d2c87cf70 100644 --- a/alloc/src/sync.rs +++ b/alloc/src/sync.rs @@ -33,7 +33,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{box_free, WriteCloneIntoRaw}; +use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; @@ -1360,23 +1360,21 @@ impl Arc { } #[cfg(not(no_global_oom_handling))] - fn from_box(v: Box) -> Arc { + fn from_box(src: Box) -> Arc { unsafe { - let (box_unique, alloc) = Box::into_unique(v); - let bptr = box_unique.as_ptr(); - - let value_size = size_of_val(&*bptr); - let ptr = Self::allocate_for_ptr(bptr); + let value_size = size_of_val(&*src); + let ptr = Self::allocate_for_ptr(&*src); // Copy value as bytes ptr::copy_nonoverlapping( - bptr as *const T as *const u8, + &*src as *const T as *const u8, &mut (*ptr).data as *mut _ as *mut u8, value_size, ); // Free the allocation without dropping its contents - box_free(box_unique, alloc); + let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop); + drop(src); Self::from_ptr(ptr) } From 5030f5783608f9cb929d561de1f17c415ff39ed2 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 16 Jun 2023 15:21:34 -0700 Subject: [PATCH 117/180] [libs] Simplify `unchecked_{shl,shr}` There's no need for the `const_eval_select` dance here. And while I originally wrote the `.try_into().unwrap_unchecked()` implementation here, it's kinda a mess in MIR -- this new one is substantially simpler, as shown by the old one being above the inlining threshold but the new one being below it. --- core/src/num/mod.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index c9baa09f4..95dcaf5dd 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -3,7 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; -use crate::convert::TryInto; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -278,18 +277,12 @@ macro_rules! widening_impl { macro_rules! conv_rhs_for_unchecked_shift { ($SelfT:ty, $x:expr) => {{ - #[inline] - fn conv(x: u32) -> $SelfT { - // FIXME(const-hack) replace with `.try_into().ok().unwrap_unchecked()`. - // SAFETY: Any legal shift amount must be losslessly representable in the self type. - unsafe { x.try_into().ok().unwrap_unchecked() } - } - #[inline] - const fn const_conv(x: u32) -> $SelfT { - x as _ + // If the `as` cast will truncate, ensure we still tell the backend + // that the pre-truncation value was also small. + if <$SelfT>::BITS < 32 { + intrinsics::assume($x <= (<$SelfT>::MAX as u32)); } - - intrinsics::const_eval_select(($x,), const_conv, conv) + $x as $SelfT }}; } From 1e20083e17b344c300aa00343b380c8adbbe2930 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 10 Jun 2023 12:06:17 -0400 Subject: [PATCH 118/180] Apply changes to fix python linting errors --- core/src/unicode/printable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/unicode/printable.py b/core/src/unicode/printable.py index 7c37f5f09..4d39ace06 100755 --- a/core/src/unicode/printable.py +++ b/core/src/unicode/printable.py @@ -119,7 +119,7 @@ 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(l) for l in lowers[i:i+8]))) + print(" {}".format(" ".join("{:#04x},".format(x) for x in lowers[i:i+8]))) print("];") def print_normal(normal, normalname): From 369a002867d961ecf5caafe51218beefb6b8e6ac Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 6 Jun 2023 01:09:05 +0200 Subject: [PATCH 119/180] Extend io::copy buffer reuse to BufReader too previously it was only able to use BufWriter. This was due to a limitation in the BufReader generics that prevented specialization. This change works around the issue by using `where Self: Read` instead of `where I: Read`. This limits our options, e.g. we can't access BufRead methods, but it happens to work out if we rely on some implementation details. --- std/src/io/buffered/bufreader.rs | 2 +- std/src/io/copy.rs | 110 +++++++++++++++++++++++++++---- std/src/io/copy/tests.rs | 108 ++++++++++++++++++++++++++++++ std/src/io/util/tests.rs | 61 +---------------- 4 files changed, 207 insertions(+), 74 deletions(-) create mode 100644 std/src/io/copy/tests.rs diff --git a/std/src/io/buffered/bufreader.rs b/std/src/io/buffered/bufreader.rs index 3edf9d747..a66e6ccf6 100644 --- a/std/src/io/buffered/bufreader.rs +++ b/std/src/io/buffered/bufreader.rs @@ -222,7 +222,7 @@ impl BufReader { /// Invalidates all data in the internal buffer. #[inline] - fn discard_buffer(&mut self) { + pub(in crate::io) fn discard_buffer(&mut self) { self.buf.discard_buffer() } } diff --git a/std/src/io/copy.rs b/std/src/io/copy.rs index 420fc4007..ef1f4031e 100644 --- a/std/src/io/copy.rs +++ b/std/src/io/copy.rs @@ -1,6 +1,9 @@ -use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; +use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; use crate::mem::MaybeUninit; +#[cfg(test)] +mod tests; + /// Copies the entire contents of a reader into a writer. /// /// This function will continuously read data from `reader` and then @@ -71,32 +74,113 @@ where R: Read, W: Write, { - BufferedCopySpec::copy_to(reader, writer) + let read_buf = BufferedReaderSpec::buffer_size(reader); + let write_buf = BufferedWriterSpec::buffer_size(writer); + + if read_buf >= DEFAULT_BUF_SIZE && read_buf >= write_buf { + return BufferedReaderSpec::copy_to(reader, writer); + } + + BufferedWriterSpec::copy_from(writer, reader) +} + +/// Specialization of the read-write loop that reuses the internal +/// buffer of a BufReader. If there's no buffer then the writer side +/// should be used intead. +trait BufferedReaderSpec { + fn buffer_size(&self) -> usize; + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result; +} + +impl BufferedReaderSpec for T +where + Self: Read, + T: ?Sized, +{ + #[inline] + default fn buffer_size(&self) -> usize { + 0 + } + + default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result { + unimplemented!("only called from specializations"); + } +} + +impl BufferedReaderSpec for BufReader +where + Self: Read, + I: ?Sized, +{ + fn buffer_size(&self) -> usize { + self.capacity() + } + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { + let mut len = 0; + + loop { + // Hack: this relies on `impl Read for BufReader` always calling fill_buf + // if the buffer is empty, even for empty slices. + // It can't be called directly here since specialization prevents us + // from adding I: Read + match self.read(&mut []) { + Ok(_) => {} + Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + } + let buf = self.buffer(); + if self.buffer().len() == 0 { + return Ok(len); + } + + // In case the writer side is a BufWriter then its write_all + // implements an optimization that passes through large + // buffers to the underlying writer. That code path is #[cold] + // but we're still avoiding redundant memcopies when doing + // a copy between buffered inputs and outputs. + to.write_all(buf)?; + len += buf.len() as u64; + self.discard_buffer(); + } + } } /// Specialization of the read-write loop that either uses a stack buffer /// or reuses the internal buffer of a BufWriter -trait BufferedCopySpec: Write { - fn copy_to(reader: &mut R, writer: &mut Self) -> Result; +trait BufferedWriterSpec: Write { + fn buffer_size(&self) -> usize; + + fn copy_from(&mut self, reader: &mut R) -> Result; } -impl BufferedCopySpec for W { - default fn copy_to(reader: &mut R, writer: &mut Self) -> Result { - stack_buffer_copy(reader, writer) +impl BufferedWriterSpec for W { + #[inline] + default fn buffer_size(&self) -> usize { + 0 + } + + default fn copy_from(&mut self, reader: &mut R) -> Result { + stack_buffer_copy(reader, self) } } -impl BufferedCopySpec for BufWriter { - fn copy_to(reader: &mut R, writer: &mut Self) -> Result { - if writer.capacity() < DEFAULT_BUF_SIZE { - return stack_buffer_copy(reader, writer); +impl BufferedWriterSpec for BufWriter { + fn buffer_size(&self) -> usize { + self.capacity() + } + + fn copy_from(&mut self, reader: &mut R) -> Result { + if self.capacity() < DEFAULT_BUF_SIZE { + return stack_buffer_copy(reader, self); } let mut len = 0; let mut init = 0; loop { - let buf = writer.buffer_mut(); + let buf = self.buffer_mut(); let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); unsafe { @@ -127,7 +211,7 @@ impl BufferedCopySpec for BufWriter { Err(e) => return Err(e), } } else { - writer.flush_buf()?; + self.flush_buf()?; init = 0; } } diff --git a/std/src/io/copy/tests.rs b/std/src/io/copy/tests.rs new file mode 100644 index 000000000..8c816af15 --- /dev/null +++ b/std/src/io/copy/tests.rs @@ -0,0 +1,108 @@ +use crate::cmp::{max, min}; +use crate::io::*; + +#[test] +fn copy_copies() { + let mut r = repeat(0).take(4); + let mut w = sink(); + assert_eq!(copy(&mut r, &mut w).unwrap(), 4); + + let mut r = repeat(0).take(1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); +} + +struct ShortReader { + cap: usize, + read_size: usize, + observed_buffer: usize, +} + +impl Read for ShortReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + let bytes = min(self.cap, self.read_size); + self.cap -= bytes; + self.observed_buffer = max(self.observed_buffer, buf.len()); + Ok(bytes) + } +} + +struct WriteObserver { + observed_buffer: usize, +} + +impl Write for WriteObserver { + fn write(&mut self, buf: &[u8]) -> Result { + self.observed_buffer = max(self.observed_buffer, buf.len()); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +#[test] +fn copy_specializes_bufwriter() { + let cap = 117 * 1024; + let buf_sz = 16 * 1024; + let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 }; + let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 }); + assert_eq!( + copy(&mut r, &mut w).unwrap(), + cap as u64, + "expected the whole capacity to be copied" + ); + assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader"); + assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes"); +} + +#[test] +fn copy_specializes_bufreader() { + let mut source = vec![0; 768 * 1024]; + source[1] = 42; + let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source)); + + let mut sink = Vec::new(); + assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(source.as_slice(), sink.as_slice()); + + let buf_sz = 71 * 1024; + assert!(buf_sz > DEFAULT_BUF_SIZE, "test precondition"); + + let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source)); + let mut sink = WriteObserver { observed_buffer: 0 }; + assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!( + sink.observed_buffer, buf_sz, + "expected a large buffer to be provided to the writer" + ); +} + +#[cfg(unix)] +mod io_benches { + use crate::fs::File; + use crate::fs::OpenOptions; + use crate::io::prelude::*; + use crate::io::BufReader; + + use test::Bencher; + + #[bench] + 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 + let dyn_in = &mut file_in as &mut dyn Read; + let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0)); + let mut writer = + OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); + + const BYTES: u64 = 1024 * 1024; + + b.bytes = BYTES; + + b.iter(|| { + reader.get_mut().set_limit(BYTES); + crate::io::copy(&mut reader, &mut writer).unwrap() + }); + } +} diff --git a/std/src/io/util/tests.rs b/std/src/io/util/tests.rs index ce5e2c9da..1baa94e64 100644 --- a/std/src/io/util/tests.rs +++ b/std/src/io/util/tests.rs @@ -1,67 +1,8 @@ -use crate::cmp::{max, min}; use crate::io::prelude::*; -use crate::io::{ - copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink, - DEFAULT_BUF_SIZE, -}; +use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink}; use crate::mem::MaybeUninit; -#[test] -fn copy_copies() { - let mut r = repeat(0).take(4); - let mut w = sink(); - assert_eq!(copy(&mut r, &mut w).unwrap(), 4); - - let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); -} - -struct ShortReader { - cap: usize, - read_size: usize, - observed_buffer: usize, -} - -impl Read for ShortReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - let bytes = min(self.cap, self.read_size); - self.cap -= bytes; - self.observed_buffer = max(self.observed_buffer, buf.len()); - Ok(bytes) - } -} - -struct WriteObserver { - observed_buffer: usize, -} - -impl Write for WriteObserver { - fn write(&mut self, buf: &[u8]) -> Result { - self.observed_buffer = max(self.observed_buffer, buf.len()); - Ok(buf.len()) - } - - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -#[test] -fn copy_specializes_bufwriter() { - let cap = 117 * 1024; - let buf_sz = 16 * 1024; - let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 }; - let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 }); - assert_eq!( - copy(&mut r, &mut w).unwrap(), - cap as u64, - "expected the whole capacity to be copied" - ); - assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader"); - assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes"); -} - #[test] fn sink_sinks() { let mut s = sink(); From 5c87bf04b10eee0874b0bfdbf6c60849f673e842 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 9 Jun 2023 21:45:57 +0800 Subject: [PATCH 120/180] Fix windows `Socket::connect_timeout` overflow Signed-off-by: Eval EXEC --- std/src/sys/windows/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/sys/windows/net.rs b/std/src/sys/windows/net.rs index 2404bbe2b..1ae42cb7e 100644 --- a/std/src/sys/windows/net.rs +++ b/std/src/sys/windows/net.rs @@ -159,7 +159,7 @@ impl Socket { } let mut timeout = c::timeval { - tv_sec: timeout.as_secs() as c_long, + tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, tv_usec: (timeout.subsec_nanos() / 1000) as c_long, }; From dba10569795b2d6ae90274fbfb10b0dcb721610c Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 11 Jun 2023 08:57:16 +0800 Subject: [PATCH 121/180] Add unit test for `TcpStream::connect_timeout` Signed-off-by: Eval EXEC --- std/src/net/tcp/tests.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/std/src/net/tcp/tests.rs b/std/src/net/tcp/tests.rs index 7a3c66e45..08ee451df 100644 --- a/std/src/net/tcp/tests.rs +++ b/std/src/net/tcp/tests.rs @@ -46,6 +46,26 @@ fn connect_error() { } } +#[test] +fn connect_timeout_error() { + let socket_addr = next_test_ip4(); + let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); + assert!(!matches!(result, Err(e) if e.kind() == ErrorKind::TimedOut)); + + let _listener = TcpListener::bind(&socket_addr).unwrap(); + assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok()); +} + +#[test] +fn connect_timeout_ok_bind() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); // :0 picks some free port + let port = listener.local_addr().unwrap().port(); // obtain the port it picked + assert!( + TcpStream::connect_timeout(&format!("127.0.0.1:{port}").parse().unwrap(), Duration::MAX) + .is_ok() + ); +} + #[test] fn listen_localhost() { let socket_addr = next_test_ip4(); From f664f6c4b83c7f89e6f996ea8ff3c63e90e626a0 Mon Sep 17 00:00:00 2001 From: Igor Gutorov Date: Wed, 14 Jun 2023 22:40:23 +0300 Subject: [PATCH 122/180] alloc: Implement PartialOrd for `Vec`s over different allocators --- alloc/src/vec/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index d89cdff8e..a1e88d187 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -2972,9 +2972,14 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Vec { +impl PartialOrd> for Vec +where + T: PartialOrd, + A1: Allocator, + A2: Allocator, +{ #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Vec) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } From 69bea2eb1d4b6abc113a560eed25474838fddef9 Mon Sep 17 00:00:00 2001 From: Igor Gutorov Date: Wed, 14 Jun 2023 19:50:32 +0300 Subject: [PATCH 123/180] alloc: Allow comparing `Box`s over different allocators --- alloc/src/boxed.rs | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 1768687e8..ce0d19f1a 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -1311,39 +1311,56 @@ impl Clone for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Box { +impl PartialEq> for Box +where + T: ?Sized + PartialEq, + A1: Allocator, + A2: Allocator, +{ #[inline] - fn eq(&self, other: &Self) -> bool { + fn eq(&self, other: &Box) -> bool { PartialEq::eq(&**self, &**other) } + #[inline] - fn ne(&self, other: &Self) -> bool { + fn ne(&self, other: &Box) -> bool { PartialEq::ne(&**self, &**other) } } + #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Box { +impl PartialOrd> for Box +where + T: ?Sized + PartialOrd, + A1: Allocator, + A2: Allocator, +{ #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Box) -> Option { PartialOrd::partial_cmp(&**self, &**other) } + #[inline] - fn lt(&self, other: &Self) -> bool { + fn lt(&self, other: &Box) -> bool { PartialOrd::lt(&**self, &**other) } + #[inline] - fn le(&self, other: &Self) -> bool { + fn le(&self, other: &Box) -> bool { PartialOrd::le(&**self, &**other) } + #[inline] - fn ge(&self, other: &Self) -> bool { + fn ge(&self, other: &Box) -> bool { PartialOrd::ge(&**self, &**other) } + #[inline] - fn gt(&self, other: &Self) -> bool { + fn gt(&self, other: &Box) -> bool { PartialOrd::gt(&**self, &**other) } } + #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Box { #[inline] From ec467caa40989bf859f82c3df52bdc0559373781 Mon Sep 17 00:00:00 2001 From: David Weikersdorfer <517608+Danvil@users.noreply.github.com> Date: Sun, 18 Jun 2023 00:46:51 -0700 Subject: [PATCH 124/180] Use BorrowFlag instead of explicit isize The integer type tracking borrow count has a typedef called `BorrowFlag`. This type should be used instead of explicit `isize`. --- core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/cell.rs b/core/src/cell.rs index c1cc892eb..b1b15e84d 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -1756,7 +1756,7 @@ impl<'b> BorrowRefMut<'b> { let borrow = self.borrow.get(); debug_assert!(is_writing(borrow)); // Prevent the borrow counter from underflowing. - assert!(borrow != isize::MIN); + assert!(borrow != BorrowFlag::MIN); self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } From 38af2f529a627fb0cb831bbeeec98165c1f49cfb Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 18 Jun 2023 15:41:50 +0800 Subject: [PATCH 125/180] Add unit test to connect to an unreachable address Signed-off-by: Eval EXEC --- std/src/net/tcp/tests.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/std/src/net/tcp/tests.rs b/std/src/net/tcp/tests.rs index 08ee451df..4209d4b63 100644 --- a/std/src/net/tcp/tests.rs +++ b/std/src/net/tcp/tests.rs @@ -46,6 +46,17 @@ fn connect_error() { } } +#[test] +fn connect_timeout_to_unreachable_address() { + let now = Instant::now(); + match TcpStream::connect_timeout(&format!("1.1.1.1:9999").parse().unwrap(), Duration::MAX) { + Ok(..) => panic!("connected to an unreachable address, this is impossible"), + Err(e) => assert_eq!(e.kind(), ErrorKind::TimedOut), + } + + assert!(now.elapsed() > Duration::from_secs(20)); +} + #[test] fn connect_timeout_error() { let socket_addr = next_test_ip4(); From 16f0980d707467410bb281022dad1cb45c125feb Mon Sep 17 00:00:00 2001 From: David Weikersdorfer <517608+Danvil@users.noreply.github.com> Date: Sun, 18 Jun 2023 01:14:45 -0700 Subject: [PATCH 126/180] Same for BorrowRef --- core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/cell.rs b/core/src/cell.rs index b1b15e84d..909b32547 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -1374,7 +1374,7 @@ impl Clone for BorrowRef<'_> { debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow != isize::MAX); + assert!(borrow != BorrowFlag::MAX); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } From e6ebddb1eb08c4a3b39878334f8941134c11b789 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Wed, 5 Apr 2023 13:06:49 +0200 Subject: [PATCH 127/180] [doc] poll_fn: explain how to pin captured state safely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage of `Pin::new_unchecked(&mut …)` is dangerous with `poll_fn`, even though the `!Unpin`-infectiousness has made things smoother. Nonetheless, there are easy ways to avoid the need for any `unsafe` altogether, be it through `Box::pin`ning, or the `pin!` macro. Since the latter only works within an `async` context, showing an example artifically introducing one ought to help people navigate this subtlety with safety and confidence. --- core/src/future/poll_fn.rs | 87 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/core/src/future/poll_fn.rs b/core/src/future/poll_fn.rs index 90cb79739..d27a9dfc1 100644 --- a/core/src/future/poll_fn.rs +++ b/core/src/future/poll_fn.rs @@ -24,6 +24,93 @@ use crate::task::{Context, Poll}; /// assert_eq!(read_future.await, "Hello, World!".to_owned()); /// # } /// ``` +/// +/// ## Capturing a pinned state +/// +/// Example of a closure wrapping inner futures: +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select( +/// a: impl Future, +/// b: impl Future, +/// ) -> impl Future +/// { +/// let (mut a, mut b) = (Box::pin(a), Box::pin(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }) +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// +/// let a = future::pending(); +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 27); +/// +/// let a = async { 42 }; +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); // biased towards `a` in case of tie! +/// # } +/// ``` +/// +/// This time without [`Box::pin`]ning: +/// +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::pin::pin; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select( +/// a: impl Future, +/// b: impl Future, +/// ) -> impl Future +/// { +/// async { +/// let (mut a, mut b) = (pin!(a), pin!(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }).await +/// } +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// # } +/// ``` +/// +/// - Notice how, by virtue of being in an `async` context, we have been able to make the [`pin!`] +/// macro work, thereby avoiding any need for the `unsafe` +/// [Pin::new_unchecked](&mut fut) constructor. +/// +/// [`pin!`]: crate::pin::pin! #[stable(feature = "future_poll_fn", since = "1.64.0")] pub fn poll_fn(f: F) -> PollFn where From 61712f9c86f739c974672da2d4e19ef3f1573b02 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 18 Jun 2023 13:29:36 +0200 Subject: [PATCH 128/180] Bump compiler_builtins --- std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index e6b051838..f4436dc5b 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -18,7 +18,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } -compiler_builtins = { version = "0.1.92" } +compiler_builtins = { version = "0.1.93" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } From a62325651888504529a1b1fe1c03b84d37f1fb07 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 19 May 2023 10:01:49 -0700 Subject: [PATCH 129/180] Introduce `alloc::::UniqueRc` This is an `Rc` that is guaranteed to only have one strong reference. Because it is uniquely owned, it can safely implement `DerefMut`, which allows programs to have an initialization phase where structures inside the `Rc` can be mutated. The `UniqueRc` can then be converted to a regular `Rc`, allowing sharing and but read-only access. During the "initialization phase," weak references can be created, but attempting to upgrade these will fail until the `UniqueRc` has been converted to a regular `Rc`. This feature can be useful to create cyclic data structures. This API is an implementation based on the feedback provided to the ACP at https://github.com/rust-lang/libs-team/issues/90. --- alloc/src/rc.rs | 142 +++++++++++++++++++++++++++++++++++++++++- alloc/src/rc/tests.rs | 45 +++++++++++++ 2 files changed, 184 insertions(+), 3 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index 34d3acae5..0f91bc8ed 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -258,12 +258,12 @@ use core::iter; use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; -use core::mem::{self, align_of_val_raw, forget}; -use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; +use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; +use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; -use core::ptr::{self, NonNull}; +use core::ptr::{self, drop_in_place, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; @@ -2744,3 +2744,139 @@ fn data_offset_align(align: usize) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } + +/// A uniquely owned `Rc` +/// +/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong +/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong +/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. +/// +/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common +/// use case is to have an object be mutable during its initialization phase but then have it become +/// immutable and converted to a normal `Rc`. +/// +/// This can be used as a flexible way to create cyclic data structures, as in the example below. +/// +/// ``` +/// #![feature(unique_rc_arc)] +/// use std::rc::{Rc, Weak, UniqueRc}; +/// +/// struct Gadget { +/// #[allow(dead_code)] +/// me: Weak, +/// } +/// +/// fn create_gadget() -> Option> { +/// let mut rc = UniqueRc::new(Gadget { +/// me: Weak::new(), +/// }); +/// rc.me = UniqueRc::downgrade(&rc); +/// Some(UniqueRc::into_rc(rc)) +/// } +/// +/// create_gadget().unwrap(); +/// ``` +/// +/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that +/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the +/// 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 { + ptr: NonNull>, + phantom: PhantomData>, +} + +impl UniqueRc { + /// Creates a new `UniqueRc` + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new(value: T) -> Self { + Self { + ptr: Box::leak(Box::new(RcBox { + strong: Cell::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueRc still stays valid. + weak: Cell::new(1), + value, + })) + .into(), + phantom: PhantomData, + } + } + + /// Creates a new weak reference to the `UniqueRc` + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); + } + Weak { ptr: this.ptr } + } + + /// Converts the `UniqueRc` into a regular [`Rc`] + /// + /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that + /// is passed to `into_rc`. + /// + /// Any weak references created before this method is called can now be upgraded to strong + /// references. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn into_rc(this: Self) -> Rc { + let mut this = ManuallyDrop::new(this); + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { + // Convert our weak reference into a strong reference + this.ptr.as_mut().strong.set(1); + Rc::from_inner(this.ptr) + } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Deref for UniqueRc { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { &self.ptr.as_ref().value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl DerefMut for UniqueRc { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we + // have unique ownership and therefore it's safe to make a mutable reference because + // `UniqueRc` owns the only strong reference to itself. + unsafe { &mut (*self.ptr.as_ptr()).value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl<#[may_dangle] T> Drop for UniqueRc { + fn drop(&mut self) { + unsafe { + // destroy the contained object + drop_in_place(DerefMut::deref_mut(self)); + + // remove the implicit "strong weak" pointer now that we've destroyed the contents. + self.ptr.as_ref().dec_weak(); + + if self.ptr.as_ref().weak() == 0 { + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + } + } + } +} diff --git a/alloc/src/rc/tests.rs b/alloc/src/rc/tests.rs index 2784108e0..1f221b86f 100644 --- a/alloc/src/rc/tests.rs +++ b/alloc/src/rc/tests.rs @@ -574,3 +574,48 @@ fn test_rc_cyclic_with_two_ref() { assert_eq!(Rc::strong_count(&two_refs), 3); assert_eq!(Rc::weak_count(&two_refs), 2); } + +#[test] +fn test_unique_rc_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + assert!(weak.upgrade().is_none()); + + let _rc = UniqueRc::into_rc(rc); + assert_eq!(*weak.upgrade().unwrap(), 42); +} + +#[test] +fn test_unique_rc_drop_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + mem::drop(weak); + + let rc = UniqueRc::into_rc(rc); + assert_eq!(*rc, 42); +} + +#[test] +fn test_unique_rc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new(DropMe(&mut dropped)); + drop(rc); + } + assert!(dropped); +} + +#[test] +fn test_unique_rc_weak_clone_holding_ref() { + let mut v = UniqueRc::new(0u8); + let w = UniqueRc::downgrade(&v); + let r = &mut *v; + let _ = w.clone(); // touch weak count + *r = 123; +} From feeca3589a0d3cce58becdcb403c1bfb027ec2b8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Jun 2023 05:54:52 +0000 Subject: [PATCH 130/180] Add rustc_do_not_implement_via_object --- core/src/marker.rs | 4 ++++ core/src/mem/transmutability.rs | 1 + core/src/ptr/metadata.rs | 1 + 3 files changed, 6 insertions(+) diff --git a/core/src/marker.rs b/core/src/marker.rs index 9a541ccae..e1359aa09 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -174,6 +174,7 @@ pub trait Sized { #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Unsize { // Empty. } @@ -855,6 +856,7 @@ impl StructuralEq for PhantomData {} )] #[lang = "discriminant_kind"] #[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`. @@ -960,6 +962,7 @@ marker_impls! { #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] #[const_trait] pub trait Destruct {} @@ -971,6 +974,7 @@ pub trait Destruct {} #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Tuple {} /// A marker for pointer-like types. diff --git a/core/src/mem/transmutability.rs b/core/src/mem/transmutability.rs index a6f792ed0..8ba4313cc 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -7,6 +7,7 @@ use crate::marker::ConstParamTy; /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, diff --git a/core/src/ptr/metadata.rs b/core/src/ptr/metadata.rs index 2ea032d4a..34f31fb9f 100644 --- a/core/src/ptr/metadata.rs +++ b/core/src/ptr/metadata.rs @@ -51,6 +51,7 @@ use crate::hash::{Hash, Hasher}; /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] #[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 47690286274fc9e5a9de6f6faedeec014e9bade3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 16 Jun 2023 23:45:01 +0000 Subject: [PATCH 131/180] Merge attrs, better validation --- core/src/marker.rs | 22 ++++++++++++---------- core/src/mem/transmutability.rs | 3 ++- core/src/ptr/metadata.rs | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/src/marker.rs b/core/src/marker.rs index e1359aa09..760e58276 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -140,7 +140,8 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[rustc_coinductive] pub trait Sized { // Empty. @@ -173,8 +174,8 @@ pub trait Sized { /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Unsize { // Empty. } @@ -855,8 +856,8 @@ impl StructuralEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -961,8 +962,8 @@ marker_impls! { #[unstable(feature = "const_trait_impl", issue = "67792")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[const_trait] pub trait Destruct {} @@ -973,8 +974,8 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Tuple {} /// A marker for pointer-like types. @@ -1029,7 +1030,8 @@ impl ConstParamTy for () {} reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] 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 8ba4313cc..3805d149b 100644 --- a/core/src/mem/transmutability.rs +++ b/core/src/mem/transmutability.rs @@ -7,7 +7,8 @@ use crate::marker::ConstParamTy; /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, diff --git a/core/src/ptr/metadata.rs b/core/src/ptr/metadata.rs index 34f31fb9f..daaa44b1d 100644 --- a/core/src/ptr/metadata.rs +++ b/core/src/ptr/metadata.rs @@ -50,8 +50,8 @@ use crate::hash::{Hash, Hasher}; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] From 70016cb914387ed25695f8d4e7607a1280bcf073 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 18:43:12 +0800 Subject: [PATCH 132/180] Ignore `connect_timeout` unit test on SGX platform Co-authored-by: Chris Denton --- std/src/net/tcp/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/std/src/net/tcp/tests.rs b/std/src/net/tcp/tests.rs index 4209d4b63..12979db25 100644 --- a/std/src/net/tcp/tests.rs +++ b/std/src/net/tcp/tests.rs @@ -58,6 +58,7 @@ fn connect_timeout_to_unreachable_address() { } #[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn connect_timeout_error() { let socket_addr = next_test_ip4(); let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); From cec7f65ed16c54dee6ceb0c6cb92014ead149da6 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 18:47:31 +0800 Subject: [PATCH 133/180] Remove useless unit tests --- std/src/net/tcp/tests.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/std/src/net/tcp/tests.rs b/std/src/net/tcp/tests.rs index 12979db25..db367cfa0 100644 --- a/std/src/net/tcp/tests.rs +++ b/std/src/net/tcp/tests.rs @@ -46,17 +46,6 @@ fn connect_error() { } } -#[test] -fn connect_timeout_to_unreachable_address() { - let now = Instant::now(); - match TcpStream::connect_timeout(&format!("1.1.1.1:9999").parse().unwrap(), Duration::MAX) { - Ok(..) => panic!("connected to an unreachable address, this is impossible"), - Err(e) => assert_eq!(e.kind(), ErrorKind::TimedOut), - } - - assert!(now.elapsed() > Duration::from_secs(20)); -} - #[test] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn connect_timeout_error() { @@ -68,16 +57,6 @@ fn connect_timeout_error() { assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok()); } -#[test] -fn connect_timeout_ok_bind() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); // :0 picks some free port - let port = listener.local_addr().unwrap().port(); // obtain the port it picked - assert!( - TcpStream::connect_timeout(&format!("127.0.0.1:{port}").parse().unwrap(), Duration::MAX) - .is_ok() - ); -} - #[test] fn listen_localhost() { let socket_addr = next_test_ip4(); From bae491b9625ad4d384b3e3d57e88f5b6d378d421 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 14 May 2023 17:38:41 -0400 Subject: [PATCH 134/180] Remove `LineColumn`, `Span::start`, `Span::end` --- proc_macro/src/bridge/mod.rs | 6 +---- proc_macro/src/lib.rs | 51 ------------------------------------ 2 files changed, 1 insertion(+), 56 deletions(-) diff --git a/proc_macro/src/bridge/mod.rs b/proc_macro/src/bridge/mod.rs index caecda1bc..5c8e35590 100644 --- a/proc_macro/src/bridge/mod.rs +++ b/proc_macro/src/bridge/mod.rs @@ -8,7 +8,7 @@ #![deny(unsafe_code)] -use crate::{Delimiter, Level, LineColumn, Spacing}; +use crate::{Delimiter, Level, Spacing}; use std::fmt; use std::hash::Hash; use std::marker; @@ -95,8 +95,6 @@ macro_rules! with_api { fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; fn byte_range($self: $S::Span) -> Range; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; fn before($self: $S::Span) -> $S::Span; fn after($self: $S::Span) -> $S::Span; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; @@ -299,7 +297,6 @@ mark_noop! { Delimiter, LitKind, Level, - LineColumn, Spacing, } @@ -319,7 +316,6 @@ rpc_encode_decode!( Help, } ); -rpc_encode_decode!(struct LineColumn { line, column }); rpc_encode_decode!( enum Spacing { Alone, diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index c64665b6a..d23becfed 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -43,7 +43,6 @@ mod diagnostic; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; -use std::cmp::Ordering; use std::ops::{Range, RangeBounds}; use std::path::PathBuf; use std::str::FromStr; @@ -494,18 +493,6 @@ impl Span { self.0.byte_range() } - /// Gets the starting line/column in the source file for this span. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - /// Creates an empty span pointing to directly before this span. #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] pub fn before(&self) -> Span { @@ -586,44 +573,6 @@ impl fmt::Debug for Span { } } -/// A line-column pair representing the start or end of a `Span`. -#[unstable(feature = "proc_macro_span", issue = "54725")] -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl !Send for LineColumn {} -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl !Sync for LineColumn {} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - /// The source file of a given `Span`. #[unstable(feature = "proc_macro_span", issue = "54725")] #[derive(Clone)] From 42e1e7b81eaae69b67a2a3ab55a8a6ca2367f525 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 14 May 2023 18:11:27 -0400 Subject: [PATCH 135/180] =?UTF-8?q?`Span::{before,=20after}`=20=E2=86=92?= =?UTF-8?q?=20`Span::{start,=20end}`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- proc_macro/src/bridge/mod.rs | 4 ++-- proc_macro/src/lib.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/proc_macro/src/bridge/mod.rs b/proc_macro/src/bridge/mod.rs index 5c8e35590..c7c7e974a 100644 --- a/proc_macro/src/bridge/mod.rs +++ b/proc_macro/src/bridge/mod.rs @@ -95,8 +95,8 @@ macro_rules! with_api { fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; fn byte_range($self: $S::Span) -> Range; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; + fn start($self: $S::Span) -> $S::Span; + fn end($self: $S::Span) -> $S::Span; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn subspan($self: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index d23becfed..89b5aef1b 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -495,14 +495,14 @@ impl Span { /// Creates an empty span pointing to directly before this span. #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] - pub fn before(&self) -> Span { - Span(self.0.before()) + pub fn start(&self) -> Span { + Span(self.0.start()) } /// Creates an empty span pointing to directly after this span. #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] - pub fn after(&self) -> Span { - Span(self.0.after()) + pub fn end(&self) -> Span { + Span(self.0.end()) } /// Creates a new span encompassing `self` and `other`. From 8b76a5b60cca904a50aa5ad472af25f656489435 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 14 May 2023 18:30:18 -0400 Subject: [PATCH 136/180] Add `Span::{line, column}` --- proc_macro/src/bridge/mod.rs | 2 ++ proc_macro/src/lib.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/proc_macro/src/bridge/mod.rs b/proc_macro/src/bridge/mod.rs index c7c7e974a..86ce5d9c6 100644 --- a/proc_macro/src/bridge/mod.rs +++ b/proc_macro/src/bridge/mod.rs @@ -97,6 +97,8 @@ macro_rules! with_api { fn byte_range($self: $S::Span) -> Range; fn start($self: $S::Span) -> $S::Span; fn end($self: $S::Span) -> $S::Span; + fn line($self: $S::Span) -> usize; + fn column($self: $S::Span) -> usize; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn subspan($self: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index 89b5aef1b..cb8b7ec70 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -505,6 +505,22 @@ impl Span { Span(self.0.end()) } + /// The one-indexed line of the source file where the span starts. + /// + /// To obtain the line of the span's end, use `span.end().line()`. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn line(&self) -> usize { + self.0.line() + } + + /// The one-indexed column of the source file where the span starts. + /// + /// To obtain the column of the span's end, use `span.end().column()`. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn column(&self) -> usize { + self.0.column() + } + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. From eb498ef7a62bb9b54fe51cbb5975b1ec0a8e33ff Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 6 Jun 2023 15:02:34 -0400 Subject: [PATCH 137/180] Merge proc_macro_span_shrink and proc_macro_span --- proc_macro/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index cb8b7ec70..7fb0d989c 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -494,13 +494,13 @@ impl Span { } /// Creates an empty span pointing to directly before this span. - #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] + #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn start(&self) -> Span { Span(self.0.start()) } /// Creates an empty span pointing to directly after this span. - #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] + #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn end(&self) -> Span { Span(self.0.end()) } From d5035524c06067586b9d12586999bff2a2b78008 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 20 Jun 2023 20:05:31 -0400 Subject: [PATCH 138/180] relaxed orderings in `thread::park` example --- std/src/thread/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 0f8b9c766..e9d94ba42 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -893,7 +893,8 @@ pub fn sleep(dur: Duration) { /// /// Note that being unblocked does not imply a call was made to `unpark`, because /// wakeups can also be spurious. For example, a valid, but inefficient, -/// implementation could have `park` and `unpark` return immediately without doing anything. +/// implementation could have `park` and `unpark` return immediately without doing anything, +/// making *all* wakeups spurious. /// /// # Examples /// @@ -908,7 +909,7 @@ pub fn sleep(dur: Duration) { /// let parked_thread = thread::spawn(move || { /// // We want to wait until the flag is set. We *could* just spin, but using /// // park/unpark is more efficient. -/// while !flag2.load(Ordering::Acquire) { +/// while !flag2.load(Ordering::Relaxed) { /// println!("Parking thread"); /// thread::park(); /// // We *could* get here spuriously, i.e., way before the 10ms below are over! @@ -925,7 +926,7 @@ pub fn sleep(dur: Duration) { /// // There is no race condition here, if `unpark` /// // happens first, `park` will return immediately. /// // Hence there is no risk of a deadlock. -/// flag.store(true, Ordering::Release); +/// flag.store(true, Ordering::Relaxed); /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// From cee2ecaa29f357e4dc61f5e2f1d76d36c7aaa45a Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 21 Jun 2023 01:06:48 +0100 Subject: [PATCH 139/180] Fix typo in `eprintln` docs --- std/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/src/macros.rs b/std/src/macros.rs index fcc5cfafd..ba1b8cbfa 100644 --- a/std/src/macros.rs +++ b/std/src/macros.rs @@ -154,7 +154,7 @@ macro_rules! println { /// /// Panics if writing to `io::stderr` fails. /// -/// Writing to non-blocking stdout can cause an error, which will lead +/// Writing to non-blocking stderr can cause an error, which will lead /// this macro to panic. /// /// # Examples @@ -189,7 +189,7 @@ macro_rules! eprint { /// /// Panics if writing to `io::stderr` fails. /// -/// Writing to non-blocking stdout can cause an error, which will lead +/// Writing to non-blocking stderr can cause an error, which will lead /// this macro to panic. /// /// # Examples From 7258c898397b137d7bdb6eef30d64d24d0fbaebe Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 8 Jun 2023 15:11:31 +0300 Subject: [PATCH 140/180] Warn on unused offset_of!() result --- core/src/mem/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 39c9a04ee..2fff3f0ef 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -1317,7 +1317,8 @@ impl SizedTypeProperties for T {} /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` #[unstable(feature = "offset_of", issue = "106655")] -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(builtin_syntax, hint_must_use)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - builtin # offset_of($Container, $($fields).+) + // The `{}` is for better error messages + crate::hint::must_use({builtin # offset_of($Container, $($fields).+)}) } From c916185b5d5fba245503e9dc82d36bcb14216d0c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 21 Jun 2023 12:43:22 +0200 Subject: [PATCH 141/180] "Memory Orderings" -> "Memory Ordering" Co-authored-by: yvt --- std/src/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index e9d94ba42..b9b14b2dc 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -879,7 +879,7 @@ pub fn sleep(dur: Duration) { /// /// * It can be implemented very efficiently on many platforms. /// -/// # Memory Orderings +/// # Memory Ordering /// /// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory /// operations performed before a call to `unpark` are made visible to the thread that From 815e9b4648b7d8b3de23ba0058dc943cef2fbd4f Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 11 Oct 2022 17:22:12 -0700 Subject: [PATCH 142/180] wip: Support Apple tvOS in libstd --- std/build.rs | 2 +- std/src/os/ios/fs.rs | 2 +- std/src/os/mod.rs | 3 ++ std/src/os/unix/mod.rs | 3 ++ std/src/os/unix/net/stream.rs | 3 ++ std/src/os/unix/ucred.rs | 4 +-- std/src/os/unix/ucred/tests.rs | 1 + std/src/personality/gcc.rs | 2 +- std/src/sys/unix/args.rs | 4 +-- std/src/sys/unix/env.rs | 11 ++++++++ std/src/sys/unix/fs.rs | 32 +++++++++++++++++++--- std/src/sys/unix/locks/pthread_condvar.rs | 2 ++ std/src/sys/unix/mod.rs | 2 +- std/src/sys/unix/os.rs | 12 ++++++-- std/src/sys/unix/rand.rs | 3 +- std/src/sys/unix/thread.rs | 3 +- std/src/sys/unix/thread_parking/pthread.rs | 3 ++ std/src/sys/unix/time.rs | 6 ++-- std/src/sys/unix/weak.rs | 4 +-- std/src/sys_common/net.rs | 2 +- unwind/src/libunwind.rs | 2 +- 21 files changed, 84 insertions(+), 22 deletions(-) diff --git a/std/build.rs b/std/build.rs index d0b379409..ddf6e84d8 100644 --- a/std/build.rs +++ b/std/build.rs @@ -18,6 +18,7 @@ fn main() { || target.contains("illumos") || target.contains("apple-darwin") || target.contains("apple-ios") + || target.contains("apple-tvos") || target.contains("apple-watchos") || target.contains("uwp") || target.contains("windows") @@ -48,7 +49,6 @@ fn main() { // - mipsel-sony-psp // - nvptx64-nvidia-cuda // - arch=avr - // - tvos (aarch64-apple-tvos, x86_64-apple-tvos) // - uefi (x86_64-unknown-uefi, i686-unknown-uefi) // - JSON targets // - Any new targets that have not been explicitly added above. diff --git a/std/src/os/ios/fs.rs b/std/src/os/ios/fs.rs index 6d4d54b7c..b319527a5 100644 --- a/std/src/os/ios/fs.rs +++ b/std/src/os/ios/fs.rs @@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; use crate::time::SystemTime; #[allow(deprecated)] -use crate::os::ios::raw; +use super::raw; /// OS-specific extensions to [`fs::Metadata`]. /// diff --git a/std/src/os/mod.rs b/std/src/os/mod.rs index 5b54cc5f2..634c3cc4a 100644 --- a/std/src/os/mod.rs +++ b/std/src/os/mod.rs @@ -137,6 +137,9 @@ pub mod redox; pub mod solaris; #[cfg(target_os = "solid_asp3")] pub mod solid; +#[cfg(target_os = "tvos")] +#[path = "ios/mod.rs"] +pub(crate) mod tvos; #[cfg(target_os = "vita")] pub mod vita; #[cfg(target_os = "vxworks")] diff --git a/std/src/os/unix/mod.rs b/std/src/os/unix/mod.rs index 6fe111118..401ec1e7a 100644 --- a/std/src/os/unix/mod.rs +++ b/std/src/os/unix/mod.rs @@ -73,6 +73,8 @@ mod platform { pub use crate::os::redox::*; #[cfg(target_os = "solaris")] pub use crate::os::solaris::*; + #[cfg(target_os = "tvos")] + pub use crate::os::tvos::*; #[cfg(target_os = "vita")] pub use crate::os::vita::*; #[cfg(target_os = "vxworks")] @@ -96,6 +98,7 @@ pub mod thread; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "macos", target_os = "netbsd", diff --git a/std/src/os/unix/net/stream.rs b/std/src/os/unix/net/stream.rs index bf2a51b5e..e20170873 100644 --- a/std/src/os/unix/net/stream.rs +++ b/std/src/os/unix/net/stream.rs @@ -11,6 +11,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", @@ -30,6 +31,7 @@ use crate::time::Duration; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", @@ -238,6 +240,7 @@ impl UnixStream { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", diff --git a/std/src/os/unix/ucred.rs b/std/src/os/unix/ucred.rs index 95967eac2..6a0cc2d2c 100644 --- a/std/src/os/unix/ucred.rs +++ b/std/src/os/unix/ucred.rs @@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred; ))] pub use self::impl_bsd::peer_cred; -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub use self::impl_mac::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -98,7 +98,7 @@ pub mod impl_bsd { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub mod impl_mac { use super::UCred; use crate::os::unix::io::AsRawFd; diff --git a/std/src/os/unix/ucred/tests.rs b/std/src/os/unix/ucred/tests.rs index e63a2fc24..7c3a646ed 100644 --- a/std/src/os/unix/ucred/tests.rs +++ b/std/src/os/unix/ucred/tests.rs @@ -8,6 +8,7 @@ use libc::{getegid, geteuid, getpid}; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "openbsd" diff --git a/std/src/personality/gcc.rs b/std/src/personality/gcc.rs index 82edb11cb..6552d96ca 100644 --- a/std/src/personality/gcc.rs +++ b/std/src/personality/gcc.rs @@ -85,7 +85,7 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c cfg_if::cfg_if! { - if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] { + if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "netbsd")))] { // ARM EHABI personality routine. // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // diff --git a/std/src/sys/unix/args.rs b/std/src/sys/unix/args.rs index 0efe2570d..f8fa81e6e 100644 --- a/std/src/sys/unix/args.rs +++ b/std/src/sys/unix/args.rs @@ -168,7 +168,7 @@ mod imp { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] mod imp { use super::Args; use crate::ffi::CStr; @@ -209,7 +209,7 @@ mod imp { // for i in (0..[args count]) // res.push([args objectAtIndex:i]) // res - #[cfg(any(target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn args() -> Args { use crate::ffi::OsString; use crate::mem; diff --git a/std/src/sys/unix/env.rs b/std/src/sys/unix/env.rs index 8c3ef88d8..929e9dae7 100644 --- a/std/src/sys/unix/env.rs +++ b/std/src/sys/unix/env.rs @@ -31,6 +31,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "tvos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "tvos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "watchos")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/std/src/sys/unix/fs.rs b/std/src/sys/unix/fs.rs index d2fb62383..f05ece17c 100644 --- a/std/src/sys/unix/fs.rs +++ b/std/src/sys/unix/fs.rs @@ -32,6 +32,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", ))] use crate::sys::weak::syscall; @@ -43,6 +44,7 @@ use libc::{c_int, mode_t}; #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "solaris", all(target_os = "linux", target_env = "gnu") @@ -519,6 +521,7 @@ impl FileAttr { target_os = "openbsd", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", ))] pub fn created(&self) -> io::Result { @@ -530,6 +533,7 @@ impl FileAttr { target_os = "openbsd", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "vita", )))] @@ -895,6 +899,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "linux", target_os = "emscripten", @@ -928,6 +933,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "netbsd", target_os = "openbsd", @@ -946,6 +952,7 @@ impl DirEntry { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "netbsd", target_os = "openbsd", @@ -1107,11 +1114,21 @@ impl File { cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + ))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))] + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + )))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -1121,7 +1138,12 @@ impl File { cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } @@ -1140,6 +1162,7 @@ impl File { target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -1709,6 +1732,7 @@ fn open_to_and_set_permissions( target_os = "android", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", )))] pub fn copy(from: &Path, to: &Path) -> io::Result { @@ -1736,7 +1760,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use crate::sync::atomic::{AtomicBool, Ordering}; diff --git a/std/src/sys/unix/locks/pthread_condvar.rs b/std/src/sys/unix/locks/pthread_condvar.rs index 192fa216d..330b4affa 100644 --- a/std/src/sys/unix/locks/pthread_condvar.rs +++ b/std/src/sys/unix/locks/pthread_condvar.rs @@ -124,6 +124,7 @@ impl Condvar { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "android", target_os = "espidf", @@ -158,6 +159,7 @@ impl Condvar { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "android", target_os = "espidf", diff --git a/std/src/sys/unix/mod.rs b/std/src/sys/unix/mod.rs index 24566d96b..0247b5693 100644 --- a/std/src/sys/unix/mod.rs +++ b/std/src/sys/unix/mod.rs @@ -387,7 +387,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "macos")] { #[link(name = "System")] extern "C" {} - } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Security", kind = "framework")] diff --git a/std/src/sys/unix/os.rs b/std/src/sys/unix/os.rs index 8edfd3313..a68c14758 100644 --- a/std/src/sys/unix/os.rs +++ b/std/src/sys/unix/os.rs @@ -63,7 +63,13 @@ extern "C" { #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] #[cfg_attr( - any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"), + any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "freebsd", + target_os = "watchos" + ), link_name = "__error" )] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] @@ -375,7 +381,7 @@ pub fn current_exe() -> io::Result { Ok(PathBuf::from(OsString::from_vec(e))) } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn current_exe() -> io::Result { unsafe { let mut sz: u32 = 0; @@ -609,6 +615,7 @@ pub fn home_dir() -> Option { #[cfg(any( target_os = "android", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "emscripten", target_os = "redox", @@ -623,6 +630,7 @@ pub fn home_dir() -> Option { #[cfg(not(any( target_os = "android", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "emscripten", target_os = "redox", diff --git a/std/src/sys/unix/rand.rs b/std/src/sys/unix/rand.rs index d8b63546b..d471be33e 100644 --- a/std/src/sys/unix/rand.rs +++ b/std/src/sys/unix/rand.rs @@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { unix, not(target_os = "macos"), not(target_os = "ios"), + not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "openbsd"), not(target_os = "freebsd"), @@ -198,7 +199,7 @@ mod imp { // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // only used on iOS where direct access to `/dev/urandom` is blocked by the // sandbox. -#[cfg(any(target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] mod imp { use crate::io; use crate::ptr; diff --git a/std/src/sys/unix/thread.rs b/std/src/sys/unix/thread.rs index 010015667..916390f3a 100644 --- a/std/src/sys/unix/thread.rs +++ b/std/src/sys/unix/thread.rs @@ -150,7 +150,7 @@ impl Thread { } } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); @@ -299,6 +299,7 @@ pub fn available_parallelism() -> io::Result { target_os = "emscripten", target_os = "fuchsia", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "solaris", diff --git a/std/src/sys/unix/thread_parking/pthread.rs b/std/src/sys/unix/thread_parking/pthread.rs index 8bf4bae7a..ae805d843 100644 --- a/std/src/sys/unix/thread_parking/pthread.rs +++ b/std/src/sys/unix/thread_parking/pthread.rs @@ -46,6 +46,7 @@ unsafe fn wait_timeout( #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "espidf", target_os = "horizon", @@ -73,6 +74,7 @@ unsafe fn wait_timeout( #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "espidf", target_os = "horizon", @@ -120,6 +122,7 @@ impl Parker { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "l4re", target_os = "android", diff --git a/std/src/sys/unix/time.rs b/std/src/sys/unix/time.rs index a9fbc7ab1..17b4130c2 100644 --- a/std/src/sys/unix/time.rs +++ b/std/src/sys/unix/time.rs @@ -219,7 +219,8 @@ impl From<__timespec64> for Timespec { #[cfg(any( all(target_os = "macos", any(not(target_arch = "aarch64"))), target_os = "ios", - target_os = "watchos" + target_os = "watchos", + target_os = "tvos" ))] mod inner { use crate::sync::atomic::{AtomicU64, Ordering}; @@ -339,7 +340,8 @@ mod inner { #[cfg(not(any( all(target_os = "macos", any(not(target_arch = "aarch64"))), target_os = "ios", - target_os = "watchos" + target_os = "watchos", + target_os = "tvos" )))] mod inner { use crate::fmt; diff --git a/std/src/sys/unix/weak.rs b/std/src/sys/unix/weak.rs index 62ffee70b..61088ff16 100644 --- a/std/src/sys/unix/weak.rs +++ b/std/src/sys/unix/weak.rs @@ -28,7 +28,7 @@ use crate::ptr; use crate::sync::atomic::{self, AtomicPtr, Ordering}; // We can use true weak linkage on ELF targets. -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "tvos")))] pub(crate) macro weak { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( let ref $name: ExternWeak $ret> = { @@ -43,7 +43,7 @@ pub(crate) macro weak { } // On non-ELF targets, use the dlsym approximation of weak linkage. -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))] pub(crate) use self::dlsym as weak; pub(crate) struct ExternWeak { diff --git a/std/src/sys_common/net.rs b/std/src/sys_common/net.rs index 652c695fc..2976a9f57 100644 --- a/std/src/sys_common/net.rs +++ b/std/src/sys_common/net.rs @@ -18,7 +18,7 @@ use crate::ffi::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", target_os = "watchos", + target_os = "ios", target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos", target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; diff --git a/unwind/src/libunwind.rs b/unwind/src/libunwind.rs index f6a68073b..ec24e1375 100644 --- a/unwind/src/libunwind.rs +++ b/unwind/src/libunwind.rs @@ -117,7 +117,7 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { +if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI #[repr(C)] #[derive(Copy, Clone, PartialEq)] From cbe79a44e3527db45963af877244cb0867994e54 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Mar 2023 20:02:42 -0700 Subject: [PATCH 143/180] Finish up preliminary tvos support in libstd --- core/src/ffi/mod.rs | 23 ++++++++++++++++------- std/src/sys/unix/fd.rs | 6 ++++++ std/src/sys/unix/locks/pthread_condvar.rs | 1 + std/src/sys/unix/mod.rs | 1 + std/src/sys/unix/thread.rs | 8 +++++++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 86ea154a8..7437722fd 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -238,7 +238,7 @@ impl fmt::Debug for c_void { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -267,7 +267,7 @@ pub struct VaListImpl<'f> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -292,7 +292,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> { /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[cfg(all( target_arch = "aarch64", - not(any(target_os = "macos", target_os = "ios")), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")), not(target_os = "uefi"), not(windows), ))] @@ -389,7 +389,10 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all( + target_arch = "aarch64", + any(target_os = "macos", target_os = "ios", target_os = "tvos") + ), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -404,7 +407,10 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), @@ -422,7 +428,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -449,7 +455,10 @@ impl<'f> VaListImpl<'f> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), diff --git a/std/src/sys/unix/fd.rs b/std/src/sys/unix/fd.rs index 69c93c920..85e020ae4 100644 --- a/std/src/sys/unix/fd.rs +++ b/std/src/sys/unix/fd.rs @@ -44,6 +44,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -69,6 +70,7 @@ const fn max_iov() -> usize { target_os = "emscripten", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -181,6 +183,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -222,6 +225,7 @@ impl FileDesc { #[cfg(any( all(target_os = "android", target_pointer_width = "32"), target_os = "ios", + target_os = "tvos", target_os = "macos", ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { @@ -320,6 +324,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -361,6 +366,7 @@ impl FileDesc { #[cfg(any( all(target_os = "android", target_pointer_width = "32"), target_os = "ios", + target_os = "tvos", target_os = "macos", ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { diff --git a/std/src/sys/unix/locks/pthread_condvar.rs b/std/src/sys/unix/locks/pthread_condvar.rs index 330b4affa..2dc1b0c60 100644 --- a/std/src/sys/unix/locks/pthread_condvar.rs +++ b/std/src/sys/unix/locks/pthread_condvar.rs @@ -32,6 +32,7 @@ impl LazyInit for AllocatedCondvar { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "l4re", target_os = "android", diff --git a/std/src/sys/unix/mod.rs b/std/src/sys/unix/mod.rs index 0247b5693..1b72e21a8 100644 --- a/std/src/sys/unix/mod.rs +++ b/std/src/sys/unix/mod.rs @@ -87,6 +87,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The poll on Darwin doesn't set POLLNVAL for closed fds. target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "redox", target_os = "l4re", diff --git a/std/src/sys/unix/thread.rs b/std/src/sys/unix/thread.rs index 916390f3a..893f8b8df 100644 --- a/std/src/sys/unix/thread.rs +++ b/std/src/sys/unix/thread.rs @@ -283,7 +283,13 @@ impl Drop for Thread { } } -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", +))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) { From fdfaa943d475b544bb56d0290189f2040e5a0db2 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 09:46:18 -0700 Subject: [PATCH 144/180] Avoid fork/exec spawning on tvOS/watchOS, as those functions are marked as prohibited --- std/src/sys/unix/process/process_unix.rs | 52 ++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/std/src/sys/unix/process/process_unix.rs b/std/src/sys/unix/process/process_unix.rs index 22d9d6141..98564c116 100644 --- a/std/src/sys/unix/process/process_unix.rs +++ b/std/src/sys/unix/process/process_unix.rs @@ -15,6 +15,8 @@ use crate::sys::weak::raw_syscall; #[cfg(any( target_os = "macos", + target_os = "watchos", + target_os = "tvos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -28,7 +30,12 @@ use libc::RTP_ID as pid_t; #[cfg(not(target_os = "vxworks"))] use libc::{c_int, pid_t}; -#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))] +#[cfg(not(any( + target_os = "vxworks", + target_os = "l4re", + target_os = "tvos", + target_os = "watchos", +)))] use libc::{gid_t, uid_t}; cfg_if::cfg_if! { @@ -84,7 +91,6 @@ impl Command { if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { return Ok((ret, ours)); } - let (input, output) = sys::pipe::anon_pipe()?; // Whatever happens after the fork is almost for sure going to touch or @@ -166,9 +172,32 @@ impl Command { crate::sys_common::process::wait_with_output(proc, pipes) } + // WatchOS and TVOS can theoretically spawn processes using `posix_spawn*` + // (although it just fails with a runtime error AFAICT, so we don't yet + // support it in `std`), but forbid use of `fork`/`exec*`. It's unclear the + // extent to which these is restricted, but the headers say + // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, so we go out of our way to + // avoid containing any calls to them at all, to avoid linking against their + // symbols on those targets. + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!( + ErrorKind::Unsupported, + "`fork`+`exec`-based process spawning is not supported on this target", + ); + + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); + } + // 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 = "linux", all(target_os = "nto", target_env = "nto71"))))] + #[cfg(not(any( + target_os = "linux", + target_os = "watchos", + target_os = "tvos", + all(target_os = "nto", target_env = "nto71"), + )))] unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { cvt(libc::fork()).map(|res| (res, -1)) } @@ -339,6 +368,7 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) + #[cfg(not(any(target_os = "tvos", target_os = "watchos")))] unsafe fn do_exec( &mut self, stdio: ChildPipes, @@ -445,8 +475,19 @@ impl Command { Err(io::Error::last_os_error()) } + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + unsafe fn do_exec( + &mut self, + _stdio: ChildPipes, + _maybe_envp: Option<&CStringArray>, + ) -> Result { + return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); + } + #[cfg(not(any( target_os = "macos", + target_os = "tvos", + target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -464,6 +505,9 @@ impl Command { // directly. #[cfg(any( target_os = "macos", + // FIXME: `target_os = "ios"`? + target_os = "tvos", + target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -550,7 +594,7 @@ impl Command { } let addchdir = match self.get_cwd() { Some(cwd) => { - if cfg!(target_os = "macos") { + if cfg!(any(target_os = "macos", target_os = "tvos", target_os = "watchos")) { // There is a bug in macOS where a relative executable // path like "../myprogram" will cause `posix_spawn` to // successfully launch the program, but erroneously return From 77d55024fbfa16a6c87d6a521464e8733dd591dc Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 09:46:43 -0700 Subject: [PATCH 145/180] Update tvOS support elsewhere in the stdlib --- std/src/fs/tests.rs | 28 +++++++++++++++++++++++++--- std/src/os/unix/ucred/tests.rs | 8 +++++++- std/src/sys/unix/fs.rs | 6 +++--- std/src/thread/tests.rs | 1 + 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/std/src/fs/tests.rs b/std/src/fs/tests.rs index e2480bcbb..9ff01b9c3 100644 --- a/std/src/fs/tests.rs +++ b/std/src/fs/tests.rs @@ -1640,6 +1640,10 @@ fn test_file_times() { use crate::os::ios::fs::FileTimesExt; #[cfg(target_os = "macos")] use crate::os::macos::fs::FileTimesExt; + #[cfg(target_os = "tvos")] + use crate::os::tvos::fs::FileTimesExt; + #[cfg(target_os = "tvos")] + use crate::os::tvos::fs::FileTimesExt; #[cfg(target_os = "watchos")] use crate::os::watchos::fs::FileTimesExt; #[cfg(windows)] @@ -1651,9 +1655,21 @@ fn test_file_times() { let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345); let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321); times = times.set_accessed(accessed).set_modified(modified); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { times = times.set_created(created); } @@ -1678,7 +1694,13 @@ fn test_file_times() { let metadata = file.metadata().unwrap(); assert_eq!(metadata.accessed().unwrap(), accessed); assert_eq!(metadata.modified().unwrap(), modified); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { assert_eq!(metadata.created().unwrap(), created); } diff --git a/std/src/os/unix/ucred/tests.rs b/std/src/os/unix/ucred/tests.rs index 7c3a646ed..dd99ecdd8 100644 --- a/std/src/os/unix/ucred/tests.rs +++ b/std/src/os/unix/ucred/tests.rs @@ -27,7 +27,13 @@ fn test_socket_pair() { } #[test] -#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))] +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "watchos", + target_os = "tvos", +))] fn test_socket_pair_pids(arg: Type) -> RetType { // Create two connected sockets and get their peer credentials. let (sock_a, sock_b) = UnixStream::pair().unwrap(); diff --git a/std/src/sys/unix/fs.rs b/std/src/sys/unix/fs.rs index f05ece17c..9cf5cfcc8 100644 --- a/std/src/sys/unix/fs.rs +++ b/std/src/sys/unix/fs.rs @@ -362,7 +362,7 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option, modified: Option, - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] created: Option, } @@ -615,7 +615,7 @@ impl FileTimes { self.modified = Some(t); } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] pub fn set_created(&mut self, t: SystemTime) { self.created = Some(t); } @@ -1272,7 +1272,7 @@ impl File { io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] { let mut buf = [mem::MaybeUninit::::uninit(); 3]; let mut num_times = 0; let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; diff --git a/std/src/thread/tests.rs b/std/src/thread/tests.rs index b65e2572c..5d6b9e94e 100644 --- a/std/src/thread/tests.rs +++ b/std/src/thread/tests.rs @@ -42,6 +42,7 @@ fn test_named_thread() { all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos" ))] #[test] From 2f15b3456ac0a32f2026300936169da34475632c Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 10:13:16 -0700 Subject: [PATCH 146/180] Actually save all the files --- std/src/sys/unix/process/process_unix.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/std/src/sys/unix/process/process_unix.rs b/std/src/sys/unix/process/process_unix.rs index 98564c116..129e76436 100644 --- a/std/src/sys/unix/process/process_unix.rs +++ b/std/src/sys/unix/process/process_unix.rs @@ -172,13 +172,12 @@ impl Command { crate::sys_common::process::wait_with_output(proc, pipes) } - // WatchOS and TVOS can theoretically spawn processes using `posix_spawn*` - // (although it just fails with a runtime error AFAICT, so we don't yet - // support it in `std`), but forbid use of `fork`/`exec*`. It's unclear the - // extent to which these is restricted, but the headers say - // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, so we go out of our way to - // avoid containing any calls to them at all, to avoid linking against their - // symbols on those targets. + // WatchOS and TVOS headers mark the `fork`/`exec*` functions with + // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the + // `posix_spawn*` functions should be used instead. It isn't entirely clear + // what `PROHIBITED` means here (e.g. if calls to these functions are + // 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!( ErrorKind::Unsupported, From 535e157a76714ed02898b1591066861a8cb9882a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 22 May 2023 16:14:19 +0200 Subject: [PATCH 147/180] Specialize StepBy> For ranges < usize we determine the number of items StepBy would yield and then store that in the range.end instead of the actual end. This significantly simplifies calculation of the loop induction variable especially in cases where StepBy::step (an usize) could overflow the Range's item type --- core/benches/iter.rs | 52 ++++ core/src/iter/adapters/step_by.rs | 357 +++++++++++++++++++++++++--- core/tests/iter/adapters/step_by.rs | 55 +++++ 3 files changed, 428 insertions(+), 36 deletions(-) diff --git a/core/benches/iter.rs b/core/benches/iter.rs index 60ef83223..5ec22e514 100644 --- a/core/benches/iter.rs +++ b/core/benches/iter.rs @@ -2,6 +2,7 @@ use core::borrow::Borrow; use core::iter::*; use core::mem; use core::num::Wrapping; +use core::ops::Range; use test::{black_box, Bencher}; #[bench] @@ -69,6 +70,57 @@ fn bench_max(b: &mut Bencher) { }) } +#[bench] +fn bench_range_step_by_sum_reducible(b: &mut Bencher) { + let r = 0u32..1024; + b.iter(|| { + let r = black_box(r.clone()).step_by(8); + + let mut sum: u32 = 0; + for i in r { + sum += i; + } + + sum + }) +} + +#[bench] +fn bench_range_step_by_loop_u32(b: &mut Bencher) { + let r = 0..(u16::MAX as u32); + b.iter(|| { + let r = black_box(r.clone()).step_by(64); + + let mut sum: u32 = 0; + for i in r { + let i = i ^ i.wrapping_sub(1); + sum = sum.wrapping_add(i); + } + + sum + }) +} + +#[bench] +fn bench_range_step_by_fold_usize(b: &mut Bencher) { + let r: Range = 0..(u16::MAX as usize); + b.iter(|| { + let r = black_box(r.clone()); + r.step_by(64) + .map(|x: usize| x ^ (x.wrapping_sub(1))) + .fold(0usize, |acc, i| acc.wrapping_add(i)) + }) +} + +#[bench] +fn bench_range_step_by_fold_u16(b: &mut Bencher) { + let r: Range = 0..u16::MAX; + b.iter(|| { + let r = black_box(r.clone()); + r.step_by(64).map(|x: u16| x ^ (x.wrapping_sub(1))).fold(0u16, |acc, i| acc.wrapping_add(i)) + }) +} + pub fn copy_zip(xs: &[u8], ys: &mut [u8]) { for (a, b) in ys.iter_mut().zip(xs) { *a = *b; diff --git a/core/src/iter/adapters/step_by.rs b/core/src/iter/adapters/step_by.rs index 4252c34a0..2f7e66e8c 100644 --- a/core/src/iter/adapters/step_by.rs +++ b/core/src/iter/adapters/step_by.rs @@ -1,4 +1,9 @@ -use crate::{intrinsics, iter::from_fn, ops::Try}; +use crate::convert::TryFrom; +use crate::{ + intrinsics, + iter::from_fn, + ops::{Range, Try}, +}; /// An iterator for stepping iterators by a custom amount. /// @@ -17,8 +22,10 @@ pub struct StepBy { } impl StepBy { + #[inline] pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy { assert!(step != 0); + let iter = >::setup(iter, step); StepBy { iter, step: step - 1, first_take: true } } } @@ -32,16 +39,154 @@ where #[inline] fn next(&mut self) -> Option { + self.spec_next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.spec_size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.spec_nth(n) + } + + fn try_fold(&mut self, acc: Acc, f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.spec_try_fold(acc, f) + } + + #[inline] + fn fold(self, acc: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.spec_fold(acc, f) + } +} + +impl StepBy +where + I: ExactSizeIterator, +{ + // The zero-based index starting from the end of the iterator of the + // last element. Used in the `DoubleEndedIterator` implementation. + fn next_back_index(&self) -> usize { + let rem = self.iter.len() % (self.step + 1); if self.first_take { - self.first_take = false; - self.iter.next() + if rem == 0 { self.step } else { rem - 1 } } else { - self.iter.nth(self.step) + rem } } +} +#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] +impl DoubleEndedIterator for StepBy +where + I: DoubleEndedIterator + ExactSizeIterator, +{ #[inline] - fn size_hint(&self) -> (usize, Option) { + fn next_back(&mut self) -> Option { + self.spec_next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.spec_nth_back(n) + } + + fn try_rfold(&mut self, init: Acc, f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.spec_try_rfold(init, f) + } + + #[inline] + fn rfold(self, init: Acc, f: F) -> Acc + where + Self: Sized, + F: FnMut(Acc, Self::Item) -> Acc, + { + self.spec_rfold(init, f) + } +} + +// StepBy can only make the iterator shorter, so the len will still fit. +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} + +trait SpecRangeSetup { + fn setup(inner: T, step: usize) -> T; +} + +impl SpecRangeSetup for T { + #[inline] + default fn setup(inner: T, _step: usize) -> T { + inner + } +} + +trait StepByImpl { + type Item; + + fn spec_next(&mut self) -> Option; + + fn spec_size_hint(&self) -> (usize, Option); + + fn spec_nth(&mut self, n: usize) -> Option; + + fn spec_try_fold(&mut self, acc: Acc, f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try; + + fn spec_fold(self, acc: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc; +} + +trait StepByBackImpl { + type Item; + + fn spec_next_back(&mut self) -> Option + where + I: DoubleEndedIterator + ExactSizeIterator; + + fn spec_nth_back(&mut self, n: usize) -> Option + where + I: DoubleEndedIterator + ExactSizeIterator; + + fn spec_try_rfold(&mut self, init: Acc, f: F) -> R + where + I: DoubleEndedIterator + ExactSizeIterator, + F: FnMut(Acc, Self::Item) -> R, + R: Try; + + fn spec_rfold(self, init: Acc, f: F) -> Acc + where + I: DoubleEndedIterator + ExactSizeIterator, + F: FnMut(Acc, Self::Item) -> Acc; +} + +impl StepByImpl for StepBy { + type Item = I::Item; + + #[inline] + default fn spec_next(&mut self) -> Option { + let step_size = if self.first_take { 0 } else { self.step }; + self.first_take = false; + self.iter.nth(step_size) + } + + #[inline] + default fn spec_size_hint(&self) -> (usize, Option) { #[inline] fn first_size(step: usize) -> impl Fn(usize) -> usize { move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } @@ -64,7 +209,7 @@ where } #[inline] - fn nth(&mut self, mut n: usize) -> Option { + default fn spec_nth(&mut self, mut n: usize) -> Option { if self.first_take { self.first_take = false; let first = self.iter.next(); @@ -108,7 +253,7 @@ where } } - fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + default fn spec_try_fold(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, R: Try, @@ -128,7 +273,7 @@ where from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) } - fn fold(mut self, mut acc: Acc, mut f: F) -> Acc + default fn spec_fold(mut self, mut acc: Acc, mut f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { @@ -148,34 +293,16 @@ where } } -impl StepBy -where - I: ExactSizeIterator, -{ - // The zero-based index starting from the end of the iterator of the - // last element. Used in the `DoubleEndedIterator` implementation. - fn next_back_index(&self) -> usize { - let rem = self.iter.len() % (self.step + 1); - if self.first_take { - if rem == 0 { self.step } else { rem - 1 } - } else { - rem - } - } -} +impl StepByBackImpl for StepBy { + type Item = I::Item; -#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] -impl DoubleEndedIterator for StepBy -where - I: DoubleEndedIterator + ExactSizeIterator, -{ #[inline] - fn next_back(&mut self) -> Option { + default fn spec_next_back(&mut self) -> Option { self.iter.nth_back(self.next_back_index()) } #[inline] - fn nth_back(&mut self, n: usize) -> Option { + default fn spec_nth_back(&mut self, n: usize) -> Option { // `self.iter.nth_back(usize::MAX)` does the right thing here when `n` // is out of bounds because the length of `self.iter` does not exceed // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is @@ -184,7 +311,7 @@ where self.iter.nth_back(n) } - fn try_rfold(&mut self, init: Acc, mut f: F) -> R + default fn spec_try_rfold(&mut self, init: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, R: Try, @@ -207,10 +334,10 @@ where } #[inline] - fn rfold(mut self, init: Acc, mut f: F) -> Acc + default fn spec_rfold(mut self, init: Acc, mut f: F) -> Acc where Self: Sized, - F: FnMut(Acc, Self::Item) -> Acc, + F: FnMut(Acc, I::Item) -> Acc, { #[inline] fn nth_back( @@ -230,6 +357,164 @@ where } } -// StepBy can only make the iterator shorter, so the len will still fit. -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} +macro_rules! spec_int_ranges { + ($($t:ty)*) => ($( + + const _: () = assert!(usize::BITS >= <$t>::BITS); + + impl SpecRangeSetup> for Range<$t> { + #[inline] + fn setup(mut r: Range<$t>, step: usize) -> Range<$t> { + let inner_len = r.size_hint().0; + // If step exceeds $t::MAX, then the count will be at most 1 and + // thus always fit into $t. + let yield_count = inner_len.div_ceil(step); + // Turn the range end into an iteration counter + r.end = yield_count as $t; + r + } + } + + impl StepByImpl> for StepBy> { + #[inline] + fn spec_next(&mut self) -> Option<$t> { + // if a step size larger than the type has been specified fall back to + // t::MAX, in which case remaining will be at most 1. + // The `+ 1` can't overflow since the constructor substracted 1 from the original value. + let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let remaining = self.iter.end; + if remaining > 0 { + let val = self.iter.start; + // this can only overflow during the last step, after which the value + // will not be used + self.iter.start = val.wrapping_add(step); + self.iter.end = remaining - 1; + Some(val) + } else { + None + } + } + + fn spec_size_hint(&self) -> (usize, Option) { + let remaining = self.iter.end as usize; + (remaining, Some(remaining)) + } + + // The methods below are all copied from the Iterator trait default impls. + // We have to repeat them here so that the specialization overrides the StepByImpl defaults + + fn spec_nth(&mut self, n: usize) -> Option { + self.advance_by(n).ok()?; + self.next() + } + + fn spec_try_fold(&mut self, init: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x)?; + } + try { accum } + } + + #[inline] + fn spec_fold(self, init: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc + { + // if a step size larger than the type has been specified fall back to + // t::MAX, in which case remaining will be at most 1. + let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let remaining = self.iter.end; + let mut acc = init; + let mut val = self.iter.start; + for _ in 0..remaining { + acc = f(acc, val); + // this can only overflow during the last step, after which the value + // will no longer be used + val = val.wrapping_add(step); + } + acc + } + } + )*) +} + +macro_rules! spec_int_ranges_r { + ($($t:ty)*) => ($( + const _: () = assert!(usize::BITS >= <$t>::BITS); + + impl StepByBackImpl> for StepBy> { + + fn spec_next_back(&mut self) -> Option + where Range<$t>: DoubleEndedIterator + ExactSizeIterator, + { + let step = (self.step + 1) as $t; + let remaining = self.iter.end; + if remaining > 0 { + let start = self.iter.start; + self.iter.end = remaining - 1; + Some(start + step * (remaining - 1)) + } else { + None + } + } + + // The methods below are all copied from the Iterator trait default impls. + // We have to repeat them here so that the specialization overrides the StepByImplBack defaults + + fn spec_nth_back(&mut self, n: usize) -> Option + where Self: DoubleEndedIterator, + { + if self.advance_back_by(n).is_err() { + return None; + } + self.next_back() + } + + fn spec_try_rfold(&mut self, init: Acc, mut f: F) -> R + where + Self: DoubleEndedIterator, + F: FnMut(Acc, Self::Item) -> R, + R: Try + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x)?; + } + try { accum } + } + + fn spec_rfold(mut self, init: Acc, mut f: F) -> Acc + where + Self: DoubleEndedIterator, + F: FnMut(Acc, Self::Item) -> Acc + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x); + } + accum + } + } + )*) +} + +#[cfg(target_pointer_width = "64")] +spec_int_ranges!(u8 u16 u32 u64 usize); +// DoubleEndedIterator requires ExactSizeIterator, which isn't implemented for Range +#[cfg(target_pointer_width = "64")] +spec_int_ranges_r!(u8 u16 u32 usize); + +#[cfg(target_pointer_width = "32")] +spec_int_ranges!(u8 u16 u32 usize); +#[cfg(target_pointer_width = "32")] +spec_int_ranges_r!(u8 u16 u32 usize); + +#[cfg(target_pointer_width = "16")] +spec_int_ranges!(u8 u16 usize); +#[cfg(target_pointer_width = "16")] +spec_int_ranges_r!(u8 u16 usize); diff --git a/core/tests/iter/adapters/step_by.rs b/core/tests/iter/adapters/step_by.rs index 94f2fa8c2..4c5b1dd9a 100644 --- a/core/tests/iter/adapters/step_by.rs +++ b/core/tests/iter/adapters/step_by.rs @@ -244,3 +244,58 @@ fn test_step_by_skip() { assert_eq!((0..=50).step_by(10).nth(3), Some(30)); assert_eq!((200..=255u8).step_by(10).nth(3), Some(230)); } + + +struct DeOpt(I); + +impl Iterator for DeOpt { + type Item = I::Item; + + fn next(&mut self) -> core::option::Option { + self.0.next() + } +} + +impl DoubleEndedIterator for DeOpt { + fn next_back(&mut self) -> core::option::Option { + self.0.next_back() + } +} + +#[test] +fn test_step_by_fold_range_specialization() { + macro_rules! t { + ($range:expr, $var: ident, $body:tt) => { + { + // run the same tests for the non-optimized version + let mut $var = DeOpt($range); + $body + } + { + let mut $var = $range; + $body + } + } + } + + t!((1usize..5).step_by(1), r, { + assert_eq!(r.next_back(), Some(4)); + assert_eq!(r.sum::(), 6); + }); + + t!((0usize..4).step_by(2), r, { + assert_eq!(r.next(), Some(0)); + assert_eq!(r.sum::(), 2); + }); + + + t!((0usize..5).step_by(2), r, { + assert_eq!(r.next(), Some(0)); + assert_eq!(r.sum::(), 6); + }); + + t!((usize::MAX - 6 .. usize::MAX).step_by(5), r, { + assert_eq!(r.next(), Some(usize::MAX - 6)); + assert_eq!(r.sum::(), usize::MAX - 1); + }); +} From 3ee1a28ce9c9898d347c0b855ffb27019e597cc7 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 22 Jun 2023 22:57:46 +0200 Subject: [PATCH 148/180] add inline annotation to concrete impls otherwise they wouldn't be eligible for cross-crate inlining --- core/src/iter/adapters/step_by.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/iter/adapters/step_by.rs b/core/src/iter/adapters/step_by.rs index 2f7e66e8c..ce7bd3b5c 100644 --- a/core/src/iter/adapters/step_by.rs +++ b/core/src/iter/adapters/step_by.rs @@ -395,6 +395,7 @@ macro_rules! spec_int_ranges { } } + #[inline] fn spec_size_hint(&self) -> (usize, Option) { let remaining = self.iter.end as usize; (remaining, Some(remaining)) @@ -403,11 +404,13 @@ macro_rules! spec_int_ranges { // The methods below are all copied from the Iterator trait default impls. // We have to repeat them here so that the specialization overrides the StepByImpl defaults + #[inline] fn spec_nth(&mut self, n: usize) -> Option { self.advance_by(n).ok()?; self.next() } + #[inline] fn spec_try_fold(&mut self, init: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, @@ -449,6 +452,7 @@ macro_rules! spec_int_ranges_r { impl StepByBackImpl> for StepBy> { + #[inline] fn spec_next_back(&mut self) -> Option where Range<$t>: DoubleEndedIterator + ExactSizeIterator, { @@ -466,6 +470,7 @@ macro_rules! spec_int_ranges_r { // The methods below are all copied from the Iterator trait default impls. // We have to repeat them here so that the specialization overrides the StepByImplBack defaults + #[inline] fn spec_nth_back(&mut self, n: usize) -> Option where Self: DoubleEndedIterator, { @@ -475,6 +480,7 @@ macro_rules! spec_int_ranges_r { self.next_back() } + #[inline] fn spec_try_rfold(&mut self, init: Acc, mut f: F) -> R where Self: DoubleEndedIterator, @@ -488,6 +494,7 @@ macro_rules! spec_int_ranges_r { try { accum } } + #[inline] fn spec_rfold(mut self, init: Acc, mut f: F) -> Acc where Self: DoubleEndedIterator, From 481300fb0ab3af7bc5f3eb11876a3655dd2b0419 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 23 Jun 2023 04:47:30 +0200 Subject: [PATCH 149/180] DirEntry::file_name: improve explanation --- std/src/fs.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 89dfdfafd..c2d82169d 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -1755,8 +1755,14 @@ impl DirEntry { self.0.file_type().map(FileType) } - /// Returns the bare file name of this directory entry without any other - /// leading path component. + /// Returns the file name of this directory entry without any + /// leading path component(s). + /// + /// As an example, + /// the output of the function will result in "foo" for all the following paths: + /// - "./foo" + /// - "/the/foo" + /// - "../../foo" /// /// # Examples /// From 69970efef81146209f76b231ed478b095a9fa971 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 23 Jun 2023 11:15:34 +0100 Subject: [PATCH 150/180] Expose `compiler-builtins-weak-intrinsics` feature for `-Zbuild-std` This was added in rust-lang/compiler-builtins#526 to force all compiler-builtins intrinsics to use weak linkage. --- alloc/Cargo.toml | 1 + std/Cargo.toml | 1 + sysroot/Cargo.toml | 1 + 3 files changed, 3 insertions(+) diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index 95c07abf7..e5f828c4c 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -35,3 +35,4 @@ compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] compiler-builtins-no-asm = ["compiler_builtins/no-asm"] compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"] +compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"] diff --git a/std/Cargo.toml b/std/Cargo.toml index af74efa6b..c3447b4cc 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -65,6 +65,7 @@ compiler-builtins-c = ["alloc/compiler-builtins-c"] compiler-builtins-mem = ["alloc/compiler-builtins-mem"] compiler-builtins-no-asm = ["alloc/compiler-builtins-no-asm"] compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"] +compiler-builtins-weak-intrinsics = ["alloc/compiler-builtins-weak-intrinsics"] llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] diff --git a/sysroot/Cargo.toml b/sysroot/Cargo.toml index 5356ee277..6ff24a8db 100644 --- a/sysroot/Cargo.toml +++ b/sysroot/Cargo.toml @@ -17,6 +17,7 @@ compiler-builtins-c = ["std/compiler-builtins-c"] compiler-builtins-mem = ["std/compiler-builtins-mem"] compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] +compiler-builtins-weak-intrinsics = ["std/compiler-builtins-weak-intrinsics"] llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] panic-unwind = ["std/panic_unwind"] From 92c2097776802c240b3f4fcee32e1c5c0bdda066 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 24 Jun 2023 17:30:27 +0100 Subject: [PATCH 151/180] Move arm32 shim to c.rs --- std/src/sys/windows/c.rs | 44 ++++++++++++++++++++++++++ std/src/sys/windows/c/windows_sys.lst | 4 --- std/src/sys/windows/c/windows_sys.rs | 45 --------------------------- 3 files changed, 44 insertions(+), 49 deletions(-) diff --git a/std/src/sys/windows/c.rs b/std/src/sys/windows/c.rs index 5fc6136ba..31c0e1b49 100644 --- a/std/src/sys/windows/c.rs +++ b/std/src/sys/windows/c.rs @@ -432,3 +432,47 @@ compat_fn_with_fallback! { Status as u32 } } + +// # Arm32 shim +// +// AddVectoredExceptionHandler and WSAStartup use platform-specific types. +// However, Microsoft no longer supports thumbv7a so definitions for those targets +// are not included in the win32 metadata. We work around that by defining them here. +// +// Where possible, these definitions should be kept in sync with https://docs.rs/windows-sys +cfg_if::cfg_if! { +if #[cfg(not(target_vendor = "uwp"))] { + #[link(name = "kernel32")] + extern "system" { + pub fn AddVectoredExceptionHandler( + first: u32, + handler: PVECTORED_EXCEPTION_HANDLER, + ) -> *mut c_void; + } + pub type PVECTORED_EXCEPTION_HANDLER = Option< + unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32, + >; + #[repr(C)] + pub struct EXCEPTION_POINTERS { + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ContextRecord: *mut CONTEXT, + } + #[cfg(target_arch = "arm")] + pub enum CONTEXT {} +}} + +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32; +} +#[cfg(target_arch = "arm")] +#[repr(C)] +pub struct WSADATA { + pub wVersion: u16, + pub wHighVersion: u16, + pub szDescription: [u8; 257], + pub szSystemStatus: [u8; 129], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: PSTR, +} diff --git a/std/src/sys/windows/c/windows_sys.lst b/std/src/sys/windows/c/windows_sys.lst index 2cf1ade99..631aedd26 100644 --- a/std/src/sys/windows/c/windows_sys.lst +++ b/std/src/sys/windows/c/windows_sys.lst @@ -2171,7 +2171,6 @@ Windows.Win32.Networking.WinSock.WSARecv Windows.Win32.Networking.WinSock.WSASend Windows.Win32.Networking.WinSock.WSASERVICE_NOT_FOUND Windows.Win32.Networking.WinSock.WSASocketW -Windows.Win32.Networking.WinSock.WSAStartup Windows.Win32.Networking.WinSock.WSASYSCALLFAILURE Windows.Win32.Networking.WinSock.WSASYSNOTREADY Windows.Win32.Networking.WinSock.WSATRY_AGAIN @@ -2419,12 +2418,10 @@ Windows.Win32.System.Console.STD_HANDLE Windows.Win32.System.Console.STD_INPUT_HANDLE Windows.Win32.System.Console.STD_OUTPUT_HANDLE Windows.Win32.System.Console.WriteConsoleW -Windows.Win32.System.Diagnostics.Debug.AddVectoredExceptionHandler Windows.Win32.System.Diagnostics.Debug.ARM64_NT_NEON128 Windows.Win32.System.Diagnostics.Debug.CONTEXT Windows.Win32.System.Diagnostics.Debug.CONTEXT Windows.Win32.System.Diagnostics.Debug.CONTEXT -Windows.Win32.System.Diagnostics.Debug.EXCEPTION_POINTERS Windows.Win32.System.Diagnostics.Debug.EXCEPTION_RECORD Windows.Win32.System.Diagnostics.Debug.FACILITY_CODE Windows.Win32.System.Diagnostics.Debug.FACILITY_NT_BIT @@ -2437,7 +2434,6 @@ Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_IGNORE_INSERTS Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_OPTIONS Windows.Win32.System.Diagnostics.Debug.FormatMessageW Windows.Win32.System.Diagnostics.Debug.M128A -Windows.Win32.System.Diagnostics.Debug.PVECTORED_EXCEPTION_HANDLER Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT Windows.Win32.System.Environment.FreeEnvironmentStringsW diff --git a/std/src/sys/windows/c/windows_sys.rs b/std/src/sys/windows/c/windows_sys.rs index a4294f336..023770871 100644 --- a/std/src/sys/windows/c/windows_sys.rs +++ b/std/src/sys/windows/c/windows_sys.rs @@ -39,13 +39,6 @@ extern "system" { pub fn AcquireSRWLockShared(srwlock: *mut RTL_SRWLOCK) -> (); } #[link(name = "kernel32")] -extern "system" { - pub fn AddVectoredExceptionHandler( - first: u32, - handler: PVECTORED_EXCEPTION_HANDLER, - ) -> *mut ::core::ffi::c_void; -} -#[link(name = "kernel32")] extern "system" { pub fn CancelIo(hfile: HANDLE) -> BOOL; } @@ -711,10 +704,6 @@ extern "system" { ) -> SOCKET; } #[link(name = "ws2_32")] -extern "system" { - pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32; -} -#[link(name = "ws2_32")] extern "system" { pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut i32) -> SOCKET; } @@ -3029,17 +3018,6 @@ pub const ERROR_XML_PARSE_ERROR: WIN32_ERROR = 1465u32; pub type EXCEPTION_DISPOSITION = i32; pub const EXCEPTION_MAXIMUM_PARAMETERS: u32 = 15u32; #[repr(C)] -pub struct EXCEPTION_POINTERS { - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ContextRecord: *mut CONTEXT, -} -impl ::core::marker::Copy for EXCEPTION_POINTERS {} -impl ::core::clone::Clone for EXCEPTION_POINTERS { - fn clone(&self) -> Self { - *self - } -} -#[repr(C)] pub struct EXCEPTION_RECORD { pub ExceptionCode: NTSTATUS, pub ExceptionFlags: u32, @@ -3748,9 +3726,6 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32; pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32; pub const PROGRESS_CONTINUE: u32 = 0u32; pub type PSTR = *mut u8; -pub type PVECTORED_EXCEPTION_HANDLER = ::core::option::Option< - unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32, ->; pub type PWSTR = *mut u16; pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32; pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32; @@ -4275,23 +4250,3 @@ impl ::core::clone::Clone for XSAVE_FORMAT { *self } } -// Begin of ARM32 shim -// The raw content of this file should be processed by `generate-windows-sys` -// to be merged with the generated binding. It is not supposed to be used as -// a normal Rust module. -cfg_if::cfg_if! { -if #[cfg(target_arch = "arm")] { -#[repr(C)] -pub struct WSADATA { - pub wVersion: u16, - pub wHighVersion: u16, - pub szDescription: [u8; 257], - pub szSystemStatus: [u8; 129], - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: PSTR, -} -pub enum CONTEXT {} -} -} -// End of ARM32 shim From 624560d7c20347aa00076e8994ffccd074d2b4e9 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 24 Jun 2023 19:56:29 +0100 Subject: [PATCH 152/180] Remove unnecessary `path` attribute --- std/src/sys/windows/c.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/std/src/sys/windows/c.rs b/std/src/sys/windows/c.rs index 5fc6136ba..54e1efb5c 100644 --- a/std/src/sys/windows/c.rs +++ b/std/src/sys/windows/c.rs @@ -12,7 +12,6 @@ use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; use core::ffi::NonZero_c_ulong; -#[path = "c/windows_sys.rs"] // c.rs is included from two places so we need to specify this mod windows_sys; pub use windows_sys::*; From 20ae416e4885b26f72cae5c6adccf88d47f85649 Mon Sep 17 00:00:00 2001 From: George Date: Sun, 25 Jun 2023 12:36:21 +0300 Subject: [PATCH 153/180] Always inline primitive data types. --- core/src/default.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/default.rs b/core/src/default.rs index 09dbc9581..1f7be85d3 100644 --- a/core/src/default.rs +++ b/core/src/default.rs @@ -190,7 +190,7 @@ macro_rules! default_impl { ($t:ty, $v:expr, $doc:tt) => { #[stable(feature = "rust1", since = "1.0.0")] impl Default for $t { - #[inline] + #[inline(always)] #[doc = $doc] fn default() -> $t { $v From 36278d1f84e6b83ccdc7c5c0dce2cefa19e2fdb6 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 23 Jun 2023 00:11:58 +0200 Subject: [PATCH 154/180] doccomments for StepBy specializations --- core/src/iter/adapters/step_by.rs | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/core/src/iter/adapters/step_by.rs b/core/src/iter/adapters/step_by.rs index ce7bd3b5c..4e11ee87f 100644 --- a/core/src/iter/adapters/step_by.rs +++ b/core/src/iter/adapters/step_by.rs @@ -16,6 +16,12 @@ use crate::{ #[stable(feature = "iterator_step_by", since = "1.28.0")] #[derive(Clone, Debug)] pub struct StepBy { + /// This field is guaranteed to be preprocessed by the specialized `SpecRangeSetup::setup` + /// in the constructor. + /// For most iterators that processing is a no-op, but for Range<{integer}> types it is lossy + /// which means the inner iterator cannot be returned to user code. + /// Additionally this type-dependent preprocessing means specialized implementations + /// cannot be used interchangeably. iter: I, step: usize, first_take: bool, @@ -133,6 +139,16 @@ impl SpecRangeSetup for T { } } +/// Specialization trait to optimize `StepBy>` iteration. +/// +/// # Correctness +/// +/// Technically this is safe to implement (look ma, no unsafe!), but in reality +/// a lot of unsafe code relies on ranges over integers being correct. +/// +/// For correctness *all* public StepBy methods must be specialized +/// because `setup` drastically alters the meaning of the struct fields so that mixing +/// different implementations would lead to incorrect results. trait StepByImpl { type Item; @@ -152,6 +168,16 @@ trait StepByImpl { F: FnMut(Acc, Self::Item) -> Acc; } +/// Specialization trait for double-ended iteration. +/// +/// See also: `StepByImpl` +/// +/// # Correctness +/// +/// The specializations must be implemented together with `StepByImpl` +/// where applicable. I.e. if `StepBy` does support backwards iteration +/// for a given iterator and that is specialized for forward iteration then +/// it must also be specialized for backwards iteration. trait StepByBackImpl { type Item; @@ -357,6 +383,21 @@ impl StepByBackImpl for StepBy } } +/// For these implementations, `SpecRangeSetup` calculates the number +/// of iterations that will be needed and stores that in `iter.end`. +/// +/// The various iterator implementations then rely on that to not need +/// overflow checking, letting loops just be counted instead. +/// +/// These only work for unsigned types, and will need to be reworked +/// if you want to use it to specialize on signed types. +/// +/// Currently these are only implemented for integers up to usize due to +/// correctness issues around ExactSizeIterator impls on 16bit platforms. +/// And since ExactSizeIterator is a prerequisite for backwards iteration +/// and we must consistently specialize backwards and forwards iteration +/// that makes the situation complicated enough that it's not covered +/// for now. macro_rules! spec_int_ranges { ($($t:ty)*) => ($( From ee0d7ad1a3111404ccccf6cf5129921f4cc000f5 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 25 Jun 2023 16:05:44 +0200 Subject: [PATCH 155/180] StepBy> can be TrustedLen --- core/src/iter/adapters/step_by.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/iter/adapters/step_by.rs b/core/src/iter/adapters/step_by.rs index 4e11ee87f..2458a13d9 100644 --- a/core/src/iter/adapters/step_by.rs +++ b/core/src/iter/adapters/step_by.rs @@ -1,7 +1,7 @@ use crate::convert::TryFrom; use crate::{ intrinsics, - iter::from_fn, + iter::{from_fn, TrustedLen}, ops::{Range, Try}, }; @@ -484,6 +484,12 @@ macro_rules! spec_int_ranges { acc } } + + /// Safety: This macro is only applied to ranges over types <= usize + /// which means the inner length is guaranteed to fit into a usize and so + /// the outer length calculation won't encounter clamped values + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for StepBy> {} )*) } From c053ee32152dae1d384d08447e4ab6c3346e4942 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 25 Jun 2023 18:09:47 +0200 Subject: [PATCH 156/180] Mark the StepBy specialization as unsafe --- core/src/iter/adapters/step_by.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/iter/adapters/step_by.rs b/core/src/iter/adapters/step_by.rs index 2458a13d9..7f58f7d17 100644 --- a/core/src/iter/adapters/step_by.rs +++ b/core/src/iter/adapters/step_by.rs @@ -141,7 +141,7 @@ impl SpecRangeSetup for T { /// Specialization trait to optimize `StepBy>` iteration. /// -/// # Correctness +/// # Safety /// /// Technically this is safe to implement (look ma, no unsafe!), but in reality /// a lot of unsafe code relies on ranges over integers being correct. @@ -149,7 +149,7 @@ impl SpecRangeSetup for T { /// For correctness *all* public StepBy methods must be specialized /// because `setup` drastically alters the meaning of the struct fields so that mixing /// different implementations would lead to incorrect results. -trait StepByImpl { +unsafe trait StepByImpl { type Item; fn spec_next(&mut self) -> Option; @@ -172,13 +172,13 @@ trait StepByImpl { /// /// See also: `StepByImpl` /// -/// # Correctness +/// # Safety /// /// The specializations must be implemented together with `StepByImpl` /// where applicable. I.e. if `StepBy` does support backwards iteration /// for a given iterator and that is specialized for forward iteration then /// it must also be specialized for backwards iteration. -trait StepByBackImpl { +unsafe trait StepByBackImpl { type Item; fn spec_next_back(&mut self) -> Option @@ -201,7 +201,7 @@ trait StepByBackImpl { F: FnMut(Acc, Self::Item) -> Acc; } -impl StepByImpl for StepBy { +unsafe impl StepByImpl for StepBy { type Item = I::Item; #[inline] @@ -319,7 +319,7 @@ impl StepByImpl for StepBy { } } -impl StepByBackImpl for StepBy { +unsafe impl StepByBackImpl for StepBy { type Item = I::Item; #[inline] @@ -416,7 +416,7 @@ macro_rules! spec_int_ranges { } } - impl StepByImpl> for StepBy> { + unsafe impl StepByImpl> for StepBy> { #[inline] fn spec_next(&mut self) -> Option<$t> { // if a step size larger than the type has been specified fall back to @@ -497,7 +497,7 @@ macro_rules! spec_int_ranges_r { ($($t:ty)*) => ($( const _: () = assert!(usize::BITS >= <$t>::BITS); - impl StepByBackImpl> for StepBy> { + unsafe impl StepByBackImpl> for StepBy> { #[inline] fn spec_next_back(&mut self) -> Option From 6419fe0b4d469890450afd2195f5baa854adb37d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 26 Jun 2023 22:11:13 +0200 Subject: [PATCH 157/180] str docs: remove "Basic usage" text where not useful Not "useful" in that there is only one example given --- core/src/str/mod.rs | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index ef05b25fd..9a93bb729 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -144,8 +144,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let len = "foo".len(); /// assert_eq!(3, len); @@ -165,8 +163,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = ""; /// assert!(s.is_empty()); @@ -311,8 +307,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bytes = "bors".as_bytes(); /// assert_eq!(b"bors", bytes); @@ -387,8 +381,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "Hello"; /// let ptr = s.as_ptr(); @@ -570,8 +562,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "Löwe 老虎 Léopard"; /// @@ -649,8 +639,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "Per Martin-Löf"; /// @@ -691,8 +679,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = "Per Martin-Löf".to_string(); /// { @@ -840,8 +826,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut bytes = "bors".bytes(); /// @@ -1020,8 +1004,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let text = "Zażółć gęślą jaźń"; /// @@ -1050,8 +1032,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bananas = "bananas"; /// @@ -1077,8 +1057,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bananas = "bananas"; /// @@ -1103,8 +1081,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bananas = "bananas"; /// @@ -1463,8 +1439,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); /// assert_eq!(v, ["A", "B"]); @@ -1696,8 +1670,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); /// assert_eq!(v, ["abc", "abc", "abc"]); @@ -1732,8 +1704,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); /// assert_eq!(v, ["abc", "abc", "abc"]); @@ -1775,8 +1745,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); @@ -1817,8 +1785,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); @@ -1845,8 +1811,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "\n Hello\tworld\t\n"; /// @@ -2085,8 +2049,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11"); /// assert_eq!("123foo1bar123".trim_start_matches(char::is_numeric), "foo1bar123"); @@ -2232,8 +2194,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); From 70c720234e161cb9bc4d2f1b600ed9cdcb65e436 Mon Sep 17 00:00:00 2001 From: Rageking8 Date: Mon, 26 Jun 2023 20:40:06 +0800 Subject: [PATCH 158/180] Make `rustc_on_unimplemented` std-agnostic --- core/src/convert/mod.rs | 2 +- core/src/iter/traits/iterator.rs | 8 +++--- core/src/marker.rs | 28 ++++++++++---------- core/src/ops/index.rs | 2 +- core/src/ops/try_trait.rs | 45 +++++++++++++++++++++++++------- core/src/slice/index.rs | 5 +++- 6 files changed, 60 insertions(+), 30 deletions(-) diff --git a/core/src/convert/mod.rs b/core/src/convert/mod.rs index 799085e9a..ff5a4c913 100644 --- a/core/src/convert/mod.rs +++ b/core/src/convert/mod.rs @@ -532,7 +532,7 @@ pub trait Into: Sized { #[rustc_diagnostic_item = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( - all(_Self = "&str", T = "std::string::String"), + all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")), note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] pub trait From: Sized { diff --git a/core/src/iter/traits/iterator.rs b/core/src/iter/traits/iterator.rs index dabfce144..988352283 100644 --- a/core/src/iter/traits/iterator.rs +++ b/core/src/iter/traits/iterator.rs @@ -26,13 +26,13 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - _Self = "std::ops::RangeTo", + any(_Self = "core::ops::RangeTo", _Self = "std::ops::RangeTo"), label = "if you meant to iterate until a value, add a starting value", note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ bounded `Range`: `0..end`" ), on( - _Self = "std::ops::RangeToInclusive", + any(_Self = "core::ops::RangeToInclusive", _Self = "std::ops::RangeToInclusive"), label = "if you meant to iterate until a value (including it), add a starting value", note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ to have a bounded `RangeInclusive`: `0..=end`" @@ -43,7 +43,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} ), on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), on( - _Self = "std::vec::Vec", + any(_Self = "alloc::vec::Vec", _Self = "std::vec::Vec"), label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" ), on( @@ -51,7 +51,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( - _Self = "std::string::String", + any(_Self = "alloc::string::String", _Self = "std::string::String"), label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( diff --git a/core/src/marker.rs b/core/src/marker.rs index 760e58276..e251015dd 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -575,59 +575,59 @@ impl Copy for &T {} #[lang = "sync"] #[rustc_on_unimplemented( on( - _Self = "std::cell::OnceCell", + any(_Self = "core::cell:OnceCell", _Self = "std::cell::OnceCell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", ), on( - _Self = "std::cell::Cell", + any(_Self = "core::cell::Cell", _Self = "std::cell::Cell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", ), on( - _Self = "std::cell::RefCell", + any(_Self = "core::cell::RefCell", _Self = "std::cell::RefCell"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", ), message = "`{Self}` cannot be shared between threads safely", diff --git a/core/src/ops/index.rs b/core/src/ops/index.rs index 1f1784ec9..f4649be54 100644 --- a/core/src/ops/index.rs +++ b/core/src/ops/index.rs @@ -153,7 +153,7 @@ see chapter in The Book " ), on( - _Self = "std::string::String", + any(_Self = "alloc::string::String", _Self = "std::string::String"), note = "you can use `.chars().nth()` or `.bytes().nth()` see chapter in The Book " ), diff --git a/core/src/ops/try_trait.rs b/core/src/ops/try_trait.rs index b4f69d0b2..17625dacc 100644 --- a/core/src/ops/try_trait.rs +++ b/core/src/ops/try_trait.rs @@ -226,8 +226,14 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::result::Result", - R = "std::option::Option" + any( + _Self = "core::result::Result", + _Self = "std::result::Result", + ), + any( + R = "core::option::Option", + R = "std::option::Option", + ) ), message = "the `?` operator can only be used on `Result`s, not `Option`s, \ in {ItemContext} that returns `Result`", @@ -237,7 +243,10 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::result::Result", + any( + _Self = "core::result::Result", + _Self = "std::result::Result", + ) ), // There's a special error message in the trait selection code for // `From` in `?`, so this is not shown for result-in-result errors, @@ -250,8 +259,14 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::option::Option", - R = "std::result::Result", + any( + _Self = "core::option::Option", + _Self = "std::option::Option", + ), + any( + R = "core::result::Result", + R = "std::result::Result", + ) ), message = "the `?` operator can only be used on `Option`s, not `Result`s, \ in {ItemContext} that returns `Option`", @@ -261,7 +276,10 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::option::Option", + any( + _Self = "core::option::Option", + _Self = "std::option::Option", + ) ), // `Option`-in-`Option` always works, as there's only one possible // residual, so this can also be phrased strongly. @@ -273,8 +291,14 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::ops::ControlFlow", - R = "std::ops::ControlFlow", + any( + _Self = "core::ops::ControlFlow", + _Self = "std::ops::ControlFlow", + ), + any( + R = "core::ops::ControlFlow", + R = "std::ops::ControlFlow", + ) ), message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ can only be used on other `ControlFlow`s (with the same Break type)", @@ -285,7 +309,10 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::ops::ControlFlow", + any( + _Self = "core::ops::ControlFlow", + _Self = "std::ops::ControlFlow", + ) // `R` is not a `ControlFlow`, as that case was matched previously ), message = "the `?` operator can only be used on `ControlFlow`s \ diff --git a/core/src/slice/index.rs b/core/src/slice/index.rs index 6ef9f9c95..e1e3bcc05 100644 --- a/core/src/slice/index.rs +++ b/core/src/slice/index.rs @@ -152,7 +152,10 @@ mod private_slice_index { #[rustc_on_unimplemented( on(T = "str", label = "string indices are ranges of `usize`",), on( - all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), + all( + any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"), + _Self = "{integer}" + ), note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ for more information, see chapter 8 in The Book: \ " From 6d51c2caaed9b64bb34446acdb4a21a312d8676a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20M=2E=20Bezerra?= Date: Mon, 26 Jun 2023 13:33:53 -0300 Subject: [PATCH 159/180] std: edit [T]::swap docs Add a note telling that no elements change when arguments are equal --- core/src/slice/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 5d6e7dcfc..e2a2428fb 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -851,6 +851,8 @@ impl [T] { /// Swaps two elements in the slice. /// + /// If `a` equals to `b`, it's guaranteed that elements won't change value. + /// /// # Arguments /// /// * a - The index of the first element From 6cb2299b9b0e7267d1646def38dc45c553038a53 Mon Sep 17 00:00:00 2001 From: Li Zhanhui Date: Thu, 29 Jun 2023 04:21:00 +0000 Subject: [PATCH 160/180] Fix document examples of Vec::from_raw_parts and Vec::from_raw_parts_in Signed-off-by: Li Zhanhui --- alloc/src/vec/mod.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index ef4f8be6f..598ecf05e 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -560,22 +560,20 @@ impl Vec { /// Using memory that was allocated elsewhere: /// /// ```rust - /// #![feature(allocator_api)] - /// - /// use std::alloc::{AllocError, Allocator, Global, Layout}; + /// use std::alloc::{alloc, Layout}; /// /// fn main() { /// let layout = Layout::array::(16).expect("overflow cannot happen"); /// /// let vec = unsafe { - /// let mem = match Global.allocate(layout) { - /// Ok(mem) => mem.cast::().as_ptr(), - /// Err(AllocError) => return, - /// }; + /// let mem = alloc(layout).cast::(); + /// if mem.is_null() { + /// return; + /// } /// /// mem.write(1_000_000); /// - /// Vec::from_raw_parts_in(mem, 1, 16, Global) + /// Vec::from_raw_parts(mem, 1, 16) /// }; /// /// assert_eq!(vec, &[1_000_000]); @@ -758,19 +756,22 @@ impl Vec { /// Using memory that was allocated elsewhere: /// /// ```rust - /// use std::alloc::{alloc, Layout}; + /// #![feature(allocator_api)] + /// + /// use std::alloc::{AllocError, Allocator, Global, Layout}; /// /// fn main() { /// let layout = Layout::array::(16).expect("overflow cannot happen"); + /// /// let vec = unsafe { - /// let mem = alloc(layout).cast::(); - /// if mem.is_null() { - /// return; - /// } + /// let mem = match Global.allocate(layout) { + /// Ok(mem) => mem.cast::().as_ptr(), + /// Err(AllocError) => return, + /// }; /// /// mem.write(1_000_000); /// - /// Vec::from_raw_parts(mem, 1, 16) + /// Vec::from_raw_parts_in(mem, 1, 16, Global) /// }; /// /// assert_eq!(vec, &[1_000_000]); From 7ebb6dfa2a2cd3221e490ae332778be6471ea4b7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 29 Jun 2023 09:33:15 +0200 Subject: [PATCH 161/180] make HashMap::or_insert_with example more simple --- std/src/collections/hash/map.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index f3316d97c..a083b6560 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -2543,12 +2543,12 @@ impl<'a, K, V> Entry<'a, K, V> { /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap<&str, String> = HashMap::new(); - /// let s = "hoho".to_string(); + /// let mut map = HashMap::new(); + /// let value = "hoho"; /// - /// map.entry("poneyland").or_insert_with(|| s); + /// map.entry("poneyland").or_insert_with(|| value); /// - /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// assert_eq!(map["poneyland"], "hoho"); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 367a7dc727a70e11c7898b14f4d9b68b2f4f64b7 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Fri, 30 Jun 2023 12:07:21 +0200 Subject: [PATCH 162/180] Mark wrapped intrinsics as inline(always) This should mitigate having the inliner decide not to inline when the architecture is lacking an implementation of TargetTransformInfo::areInlineCompatible aware of the target features (e.g. PowerPC as today). --- core/src/intrinsics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs index 9b8612485..5a9a7013a 100644 --- a/core/src/intrinsics.rs +++ b/core/src/intrinsics.rs @@ -2657,7 +2657,7 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] +#[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { @@ -2748,7 +2748,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] +#[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { @@ -2821,7 +2821,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] -#[inline] +#[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { From 952a07466f8d1ef000c96d64b701c79df35b5c01 Mon Sep 17 00:00:00 2001 From: Guilliam Xavier Date: Fri, 30 Jun 2023 16:11:30 +0200 Subject: [PATCH 163/180] std docs: factorize literal in Barrier example --- std/src/sync/barrier.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/std/src/sync/barrier.rs b/std/src/sync/barrier.rs index 11836b7b6..e39254aa4 100644 --- a/std/src/sync/barrier.rs +++ b/std/src/sync/barrier.rs @@ -13,9 +13,10 @@ use crate::sync::{Condvar, Mutex}; /// use std::sync::{Arc, Barrier}; /// use std::thread; /// -/// let mut handles = Vec::with_capacity(10); -/// let barrier = Arc::new(Barrier::new(10)); -/// for _ in 0..10 { +/// 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. @@ -105,9 +106,10 @@ impl Barrier { /// use std::sync::{Arc, Barrier}; /// use std::thread; /// - /// let mut handles = Vec::with_capacity(10); - /// let barrier = Arc::new(Barrier::new(10)); - /// for _ in 0..10 { + /// 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. From 9b1b9fa5e340a3820cbae068b186e475707349ba Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 13 Jun 2023 20:32:31 +0100 Subject: [PATCH 164/180] Return `Ok` on kill if process has already exited --- std/src/process.rs | 6 +++--- std/src/sys/unix/process/process_unix.rs | 7 ++----- std/src/sys/unix/process/process_vxworks.rs | 7 ++----- std/src/sys/windows/process.rs | 11 ++++++++++- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/std/src/process.rs b/std/src/process.rs index 9da74a5dd..8f3201b00 100644 --- a/std/src/process.rs +++ b/std/src/process.rs @@ -1904,8 +1904,8 @@ impl FromInner for ExitCode { } impl Child { - /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] - /// error is returned. + /// Forces the child process to exit. If the child has already exited, `Ok(())` + /// is returned. /// /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function. /// @@ -1920,7 +1920,7 @@ impl Child { /// /// let mut command = Command::new("yes"); /// if let Ok(mut child) = command.spawn() { - /// child.kill().expect("command wasn't running"); + /// child.kill().expect("command couldn't be killed"); /// } else { /// println!("yes command didn't start"); /// } diff --git a/std/src/sys/unix/process/process_unix.rs b/std/src/sys/unix/process/process_unix.rs index 3721988b4..d527e1d7e 100644 --- a/std/src/sys/unix/process/process_unix.rs +++ b/std/src/sys/unix/process/process_unix.rs @@ -719,12 +719,9 @@ impl Process { pub fn kill(&mut self) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. + // random processes, so return Ok because the process has exited already. if self.status.is_some() { - Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process", - )) + Ok(()) } else { cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } diff --git a/std/src/sys/unix/process/process_vxworks.rs b/std/src/sys/unix/process/process_vxworks.rs index c40e7ada0..f70d3cb39 100644 --- a/std/src/sys/unix/process/process_vxworks.rs +++ b/std/src/sys/unix/process/process_vxworks.rs @@ -144,12 +144,9 @@ impl Process { pub fn kill(&mut self) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. + // random processes, so return Ok because the process has exited already. if self.status.is_some() { - Err(io::const_io_error!( - ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process", - )) + Ok(()) } else { cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } diff --git a/std/src/sys/windows/process.rs b/std/src/sys/windows/process.rs index a573a05c3..e3493cbb8 100644 --- a/std/src/sys/windows/process.rs +++ b/std/src/sys/windows/process.rs @@ -595,7 +595,16 @@ pub struct Process { impl Process { pub fn kill(&mut self) -> io::Result<()> { - cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?; + let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) }; + if result == c::FALSE { + let error = unsafe { c::GetLastError() }; + // TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been + // terminated (by us, or for any other reason). So check if the process was actually + // terminated, and if so, do not return an error. + if error != c::ERROR_ACCESS_DENIED || self.try_wait().is_err() { + return Err(crate::io::Error::from_raw_os_error(error as i32)); + } + } Ok(()) } From f0b35a5b88d7b5776e3814f2bdc81035ed462f7b Mon Sep 17 00:00:00 2001 From: Daniyar Nurmukhamet Date: Sun, 2 Jul 2023 10:07:52 +0600 Subject: [PATCH 165/180] fixed documentation of from for Rc: Arc -> Rc --- alloc/src/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index f99395c72..62856fc9a 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -888,7 +888,7 @@ impl From<&CStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { /// Converts a [`CString`] into an [Rc]<[CStr]> by moving the [`CString`] - /// data into a new [`Arc`] buffer. + /// data into a new [`Rc`] buffer. #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); From e9440186744bb8ec1781dcc35ee75366f00746da Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 2 Jul 2023 10:44:25 +0200 Subject: [PATCH 166/180] downgrade compiler_builtins The outline-atomics support in compiler_builtins messed up and wasn't limited to linux only. https://github.com/rust-lang/compiler-builtins/pull/532/files#r1249354225 --- std/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 151809b2d..b2bb1f5ac 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -18,7 +18,8 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } -compiler_builtins = { version = "0.1.93" } +# FIXME(Nilstrieb): https://github.com/rust-lang/compiler-builtins/pull/532/files#r1249354225 +compiler_builtins = { version = "=0.1.93" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } From cdad96d405fdd6d952ad855c699f0e0d7e0394a5 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 29 Jun 2023 16:18:36 -0700 Subject: [PATCH 167/180] Update std to backtrace 0.3.68 Dedup addr2line, miniz_oxide, object in .lock --- backtrace | 2 +- std/Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backtrace b/backtrace index 4245978ca..e1c49fbd6 160000 --- a/backtrace +++ b/backtrace @@ -1 +1 @@ -Subproject commit 4245978ca8169c40c088ff733825e4527f7b914c +Subproject commit e1c49fbd6124a1b626cdf19871aff68c362bdf07 diff --git a/std/Cargo.toml b/std/Cargo.toml index b2bb1f5ac..77b657fd8 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -26,11 +26,11 @@ hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate -addr2line = { version = "0.19.0", optional = true, default-features = false } +addr2line = { version = "0.20.0", optional = true, default-features = false } rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } -miniz_oxide = { version = "0.6.0", optional = true, default-features = false, public = false } +miniz_oxide = { version = "0.7.0", optional = true, default-features = false, public = false } [dependencies.object] -version = "0.30.0" +version = "0.31.1" optional = true default-features = false features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] From 329d337e8b5ae9bd60957b67d4ba93cb6f61a9de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jul 2023 14:05:55 +0200 Subject: [PATCH 168/180] enable test_join test in Miri --- alloc/tests/vec.rs | 1 + core/tests/future.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/alloc/tests/vec.rs b/alloc/tests/vec.rs index 21824c8a1..ddd93e9a4 100644 --- a/alloc/tests/vec.rs +++ b/alloc/tests/vec.rs @@ -1906,6 +1906,7 @@ fn test_stable_pointers() { assert_eq!(*v0, 13); // Smoke test that would fire even outside Miri if an actual relocation happened. + // Also ensures the pointer is still writeable after all this. *v0 -= 13; assert_eq!(v[0], 0); } diff --git a/core/tests/future.rs b/core/tests/future.rs index 74b6f74e4..db417256d 100644 --- a/core/tests/future.rs +++ b/core/tests/future.rs @@ -30,7 +30,6 @@ fn poll_n(val: usize, num: usize) -> PollN { } #[test] -#[cfg_attr(miri, ignore)] // self-referential generators do not work with Miri's aliasing checks fn test_join() { block_on(async move { let x = join!(async { 0 }).await; From e1c8513f0eb5ba1f4dc2a1bcbe67717ab28d5d24 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 1 Jul 2023 01:34:06 +0100 Subject: [PATCH 169/180] Test Child::kill behaviour on exited process --- std/src/process/tests.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index d7f4d335d..e2c56e634 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -582,3 +582,11 @@ fn run_canonical_bat_script() { assert!(output.status.success()); assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, fellow Rustaceans!"); } + +#[test] +fn terminate_exited_process() { + let mut p = known_command().arg("hello").spawn().unwrap(); + p.wait().unwrap(); + assert!(p.kill().is_ok()); + assert!(p.kill().is_ok()); +} From 4db987c4a766f3088cd370d3521a06858a2234c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Jul 2023 04:23:18 -0400 Subject: [PATCH 170/180] Revert "alloc: Allow comparing `Box`s over different allocators" This reverts commit 001b081cc1bfd24657e2dccbd9c8289f9a9d67a5. This change was done as the above commit introduces a regression in type inference. Regression test located at `tests/ui/type-inference/issue-113283-alllocator-trait-eq.rs` --- alloc/src/boxed.rs | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index fa2336759..8ef2bac92 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -1319,56 +1319,39 @@ impl Clone for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq> for Box -where - T: ?Sized + PartialEq, - A1: Allocator, - A2: Allocator, -{ +impl PartialEq for Box { #[inline] - fn eq(&self, other: &Box) -> bool { + fn eq(&self, other: &Self) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &Box) -> bool { + fn ne(&self, other: &Self) -> bool { PartialEq::ne(&**self, &**other) } } - #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd> for Box -where - T: ?Sized + PartialOrd, - A1: Allocator, - A2: Allocator, -{ +impl PartialOrd for Box { #[inline] - fn partial_cmp(&self, other: &Box) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) } - #[inline] - fn lt(&self, other: &Box) -> bool { + fn lt(&self, other: &Self) -> bool { PartialOrd::lt(&**self, &**other) } - #[inline] - fn le(&self, other: &Box) -> bool { + fn le(&self, other: &Self) -> bool { PartialOrd::le(&**self, &**other) } - #[inline] - fn ge(&self, other: &Box) -> bool { + fn ge(&self, other: &Self) -> bool { PartialOrd::ge(&**self, &**other) } - #[inline] - fn gt(&self, other: &Box) -> bool { + fn gt(&self, other: &Self) -> bool { PartialOrd::gt(&**self, &**other) } } - #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Box { #[inline] From a9d307aaff4d162713f63b0d64871cf76aafe867 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 5 Jul 2023 09:54:16 +0100 Subject: [PATCH 171/180] Workaround for old android not having echo --- std/src/process/tests.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/std/src/process/tests.rs b/std/src/process/tests.rs index e2c56e634..366b59146 100644 --- a/std/src/process/tests.rs +++ b/std/src/process/tests.rs @@ -585,7 +585,14 @@ fn run_canonical_bat_script() { #[test] fn terminate_exited_process() { - let mut p = known_command().arg("hello").spawn().unwrap(); + let mut cmd = if cfg!(target_os = "android") { + let mut p = shell_cmd(); + p.args(&["-c", "true"]); + p + } else { + known_command() + }; + let mut p = cmd.stdout(Stdio::null()).spawn().unwrap(); p.wait().unwrap(); assert!(p.kill().is_ok()); assert!(p.kill().is_ok()); From f96ac998ee6d3ff74d4870c18b8c454758bd6e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 4 Jul 2023 19:45:55 +0200 Subject: [PATCH 172/180] Revert "fix ptr cast" This reverts commit 2f459f7f140307b5abbb7ea81440ed1843b490e7. --- std/src/sys/unix/args.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/std/src/sys/unix/args.rs b/std/src/sys/unix/args.rs index f8fa81e6e..7b6f8810c 100644 --- a/std/src/sys/unix/args.rs +++ b/std/src/sys/unix/args.rs @@ -242,15 +242,13 @@ mod imp { let mut res = Vec::new(); unsafe { - let process_info_sel = - sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar); - let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar); - let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar); - let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar); - let object_at_sel = - sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar); - - let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar); + let process_info_sel = sel_registerName(c"processInfo".as_ptr()); + let arguments_sel = sel_registerName(c"arguments".as_ptr()); + let utf8_sel = sel_registerName(c"UTF8String".as_ptr()); + let count_sel = sel_registerName(c"count".as_ptr()); + let object_at_sel = sel_registerName(c"objectAtIndex:".as_ptr()); + + let klass = objc_getClass(c"NSProcessInfo".as_ptr()); let info = objc_msgSend(klass, process_info_sel); let args = objc_msgSend(info, arguments_sel); From 776d882559d2de67d51a4df4195a8184831b7958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 4 Jul 2023 19:45:58 +0200 Subject: [PATCH 173/180] Revert "use c literals in library" This reverts commit f212ba6d6d60963c8101bb24fc3e53fca80c046f. --- std/src/lib.rs | 1 - std/src/sys/unix/args.rs | 12 ++++++------ std/src/sys/unix/fs.rs | 2 +- std/src/sys/unix/mod.rs | 7 ++++--- std/src/sys/unix/process/process_common.rs | 9 +++++---- std/src/sys/unix/thread.rs | 3 ++- std/src/sys/windows/c.rs | 4 ++-- std/src/sys/windows/compat.rs | 6 +++--- std/src/sys/windows/mod.rs | 4 ++-- 9 files changed, 25 insertions(+), 23 deletions(-) diff --git a/std/src/lib.rs b/std/src/lib.rs index da08c018d..72b9ad348 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -241,7 +241,6 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(c_str_literals)] #![feature(c_unwind)] #![feature(cfg_target_thread_local)] #![feature(concat_idents)] diff --git a/std/src/sys/unix/args.rs b/std/src/sys/unix/args.rs index 7b6f8810c..eafd6821f 100644 --- a/std/src/sys/unix/args.rs +++ b/std/src/sys/unix/args.rs @@ -242,13 +242,13 @@ mod imp { let mut res = Vec::new(); unsafe { - let process_info_sel = sel_registerName(c"processInfo".as_ptr()); - let arguments_sel = sel_registerName(c"arguments".as_ptr()); - let utf8_sel = sel_registerName(c"UTF8String".as_ptr()); - let count_sel = sel_registerName(c"count".as_ptr()); - let object_at_sel = sel_registerName(c"objectAtIndex:".as_ptr()); + let process_info_sel = sel_registerName("processInfo\0".as_ptr()); + let arguments_sel = sel_registerName("arguments\0".as_ptr()); + let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); + let count_sel = sel_registerName("count\0".as_ptr()); + let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); - let klass = objc_getClass(c"NSProcessInfo".as_ptr()); + let klass = objc_getClass("NSProcessInfo\0".as_ptr()); let info = objc_msgSend(klass, process_info_sel); let args = objc_msgSend(info, arguments_sel); diff --git a/std/src/sys/unix/fs.rs b/std/src/sys/unix/fs.rs index 9cf5cfcc8..fbc7f04ce 100644 --- a/std/src/sys/unix/fs.rs +++ b/std/src/sys/unix/fs.rs @@ -1097,7 +1097,7 @@ impl File { cfg_has_statx! { if let Some(ret) = unsafe { try_statx( fd, - c"".as_ptr() as *const c_char, + b"\0" as *const _ as *const c_char, libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, libc::STATX_ALL, ) } { diff --git a/std/src/sys/unix/mod.rs b/std/src/sys/unix/mod.rs index 1b72e21a8..326f1481e 100644 --- a/std/src/sys/unix/mod.rs +++ b/std/src/sys/unix/mod.rs @@ -1,5 +1,6 @@ #![allow(missing_docs, nonstandard_style)] +use crate::ffi::CStr; use crate::io::ErrorKind; pub use self::rand::hashmap_random_keys; @@ -74,7 +75,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // thread-id for the main thread and so renaming the main thread will rename the // process and we only want to enable this on platforms we've tested. if cfg!(target_os = "macos") { - thread::Thread::set_name(&c"main"); + thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0")); } unsafe fn sanitize_standard_fds() { @@ -121,7 +122,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { if pfd.revents & libc::POLLNVAL == 0 { continue; } - if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or @@ -151,7 +152,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { use libc::open64; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or diff --git a/std/src/sys/unix/process/process_common.rs b/std/src/sys/unix/process/process_common.rs index 5f316b12b..640648e87 100644 --- a/std/src/sys/unix/process/process_common.rs +++ b/std/src/sys/unix/process/process_common.rs @@ -24,11 +24,11 @@ cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { - const DEV_NULL: &CStr = c"null:"; + const DEV_NULL: &str = "null:\0"; } else if #[cfg(target_os = "vxworks")] { - const DEV_NULL: &CStr = c"/null"; + const DEV_NULL: &str = "/null\0"; } else { - const DEV_NULL: &CStr = c"/dev/null"; + const DEV_NULL: &str = "/dev/null\0"; } } @@ -474,7 +474,8 @@ impl Stdio { let mut opts = OpenOptions::new(); opts.read(readable); opts.write(!readable); - let fd = File::open_c(DEV_NULL, &opts)?; + let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) }; + let fd = File::open_c(&path, &opts)?; Ok((ChildStdio::Owned(fd.into_inner()), None)) } diff --git a/std/src/sys/unix/thread.rs b/std/src/sys/unix/thread.rs index 893f8b8df..4f2d9cf36 100644 --- a/std/src/sys/unix/thread.rs +++ b/std/src/sys/unix/thread.rs @@ -163,9 +163,10 @@ impl Thread { #[cfg(target_os = "netbsd")] pub fn set_name(name: &CStr) { unsafe { + let cname = CStr::from_bytes_with_nul_unchecked(b"%s\0".as_slice()); let res = libc::pthread_setname_np( libc::pthread_self(), - c"%s".as_ptr(), + cname.as_ptr(), name.as_ptr() as *mut libc::c_void, ); debug_assert_eq!(res, 0); diff --git a/std/src/sys/windows/c.rs b/std/src/sys/windows/c.rs index b1b9e84fc..d9ccba0e9 100644 --- a/std/src/sys/windows/c.rs +++ b/std/src/sys/windows/c.rs @@ -321,7 +321,7 @@ pub unsafe fn NtWriteFile( // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { - pub static KERNEL32: &CStr = c"kernel32"; + pub static KERNEL32: &CStr = ansi_str!("kernel32"); // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription @@ -354,7 +354,7 @@ compat_fn_optional! { } compat_fn_with_fallback! { - pub static NTDLL: &CStr = c"ntdll"; + pub static NTDLL: &CStr = ansi_str!("ntdll"); pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, diff --git a/std/src/sys/windows/compat.rs b/std/src/sys/windows/compat.rs index 649cc4bfd..4fe95d411 100644 --- a/std/src/sys/windows/compat.rs +++ b/std/src/sys/windows/compat.rs @@ -228,9 +228,9 @@ macro_rules! compat_fn_optional { /// Load all needed functions from "api-ms-win-core-synch-l1-2-0". pub(super) fn load_synch_functions() { fn try_load() -> Option<()> { - const MODULE_NAME: &CStr = c"api-ms-win-core-synch-l1-2-0"; - const WAIT_ON_ADDRESS: &CStr = c"WaitOnAddress"; - const WAKE_BY_ADDRESS_SINGLE: &CStr = c"WakeByAddressSingle"; + const MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); + const WAIT_ON_ADDRESS: &CStr = ansi_str!("WaitOnAddress"); + const WAKE_BY_ADDRESS_SINGLE: &CStr = ansi_str!("WakeByAddressSingle"); // Try loading the library and all the required functions. // If any step fails, then they all fail. diff --git a/std/src/sys/windows/mod.rs b/std/src/sys/windows/mod.rs index b11c89622..bcc172b0f 100644 --- a/std/src/sys/windows/mod.rs +++ b/std/src/sys/windows/mod.rs @@ -1,6 +1,6 @@ #![allow(missing_docs, nonstandard_style)] -use crate::ffi::{OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::io::ErrorKind; use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; @@ -51,7 +51,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already // exists, we have to call it ourselves. - thread::Thread::set_name(&c"main"); + thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0")); } // SAFETY: must be called only once during runtime cleanup. From 5a9fb37a910028cccaaf0947e1a08eee4b94fa09 Mon Sep 17 00:00:00 2001 From: Havard Eidnes Date: Wed, 5 Jul 2023 10:34:26 +0000 Subject: [PATCH 174/180] Add support for NetBSD/riscv64 aka. riscv64gc-unknown-netbsd. --- core/src/ffi/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/ffi/mod.rs b/core/src/ffi/mod.rs index 7437722fd..0488c8076 100644 --- a/core/src/ffi/mod.rs +++ b/core/src/ffi/mod.rs @@ -132,7 +132,12 @@ mod c_char_definition { ), all( target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "riscv64" + ) ), all( target_os = "vxworks", From 4a1a2b1cdf4a11bf2232e5da7edc4f27e03c14fc Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 5 Jul 2023 10:33:43 -0500 Subject: [PATCH 175/180] Update compiler-builtins to 0.1.95 This pulls in the new `outline-atomics` intrinsics. --- std/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index 77b657fd8..eb4815d0c 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -18,8 +18,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } -# FIXME(Nilstrieb): https://github.com/rust-lang/compiler-builtins/pull/532/files#r1249354225 -compiler_builtins = { version = "=0.1.93" } +compiler_builtins = { version = "0.1.95" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } From be91fd86d85f23bdfdc7d5b1a6eebaf8257cb360 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 7 Jul 2023 04:07:00 -0700 Subject: [PATCH 176/180] Sync portable-simd to 2023 July 07 Sync up to rust-lang/portable-simd@7c7dbe0c505ccbc02ff30c1e37381ab1d47bf46f --- portable-simd/.github/workflows/ci.yml | 9 +- portable-simd/crates/core_simd/src/cast.rs | 74 +++++++-------- .../core_simd/src/elements/const_ptr.rs | 30 +++++- .../crates/core_simd/src/elements/float.rs | 67 +++++++++++++- .../crates/core_simd/src/elements/int.rs | 19 +++- .../crates/core_simd/src/elements/mut_ptr.rs | 30 +++++- .../crates/core_simd/src/elements/uint.rs | 19 +++- portable-simd/crates/core_simd/src/iter.rs | 4 + portable-simd/crates/core_simd/src/lib.rs | 2 +- portable-simd/crates/core_simd/src/masks.rs | 4 + portable-simd/crates/core_simd/src/mod.rs | 2 + portable-simd/crates/core_simd/src/ops.rs | 8 +- portable-simd/crates/core_simd/src/ord.rs | 4 + .../crates/core_simd/src/simd/prelude.rs | 80 ++++++++++++++++ .../crates/core_simd/src/swizzle_dyn.rs | 24 ++++- portable-simd/crates/core_simd/src/vector.rs | 91 ++++--------------- portable-simd/crates/core_simd/tests/cast.rs | 3 +- portable-simd/crates/core_simd/tests/round.rs | 1 + 18 files changed, 338 insertions(+), 133 deletions(-) create mode 100644 portable-simd/crates/core_simd/src/simd/prelude.rs diff --git a/portable-simd/.github/workflows/ci.yml b/portable-simd/.github/workflows/ci.yml index acd47a3da..1ff377fce 100644 --- a/portable-simd/.github/workflows/ci.yml +++ b/portable-simd/.github/workflows/ci.yml @@ -38,8 +38,9 @@ jobs: - i586-unknown-linux-gnu - aarch64-unknown-linux-gnu - armv7-unknown-linux-gnueabihf - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 + # non-nightly since https://github.com/rust-lang/rust/pull/113274 + # - mips-unknown-linux-gnu + # - mips64-unknown-linux-gnuabi64 - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu - riscv64gc-unknown-linux-gnu @@ -191,8 +192,8 @@ jobs: # Note: The issue above means neither of these mips targets will use # MSA (mips simd) but MIPS uses a nonstandard binary representation # for NaNs which makes it worth testing on despite that. - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 + # - mips-unknown-linux-gnu + # - mips64-unknown-linux-gnuabi64 - riscv64gc-unknown-linux-gnu # TODO this test works, but it appears to time out # - powerpc-unknown-linux-gnu diff --git a/portable-simd/crates/core_simd/src/cast.rs b/portable-simd/crates/core_simd/src/cast.rs index 65a3f845f..1c3592f80 100644 --- a/portable-simd/crates/core_simd/src/cast.rs +++ b/portable-simd/crates/core_simd/src/cast.rs @@ -1,55 +1,51 @@ use crate::simd::SimdElement; +mod sealed { + /// Cast vector elements to other types. + /// + /// # Safety + /// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` + /// or `simd_as` intrinsics. + pub unsafe trait Sealed {} +} +use sealed::Sealed; + /// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly. -/// -/// # Safety -/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast` or -/// `simd_as` intrinsics. -pub unsafe trait SimdCast: SimdElement {} +pub trait SimdCast: Sealed + SimdElement {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i8 {} +unsafe impl Sealed for i8 {} +impl SimdCast for i8 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i16 {} +unsafe impl Sealed for i16 {} +impl SimdCast for i16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i32 {} +unsafe impl Sealed for i32 {} +impl SimdCast for i32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for i64 {} +unsafe impl Sealed for i64 {} +impl SimdCast for i64 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for isize {} +unsafe impl Sealed for isize {} +impl SimdCast for isize {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u8 {} +unsafe impl Sealed for u8 {} +impl SimdCast for u8 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u16 {} +unsafe impl Sealed for u16 {} +impl SimdCast for u16 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u32 {} +unsafe impl Sealed for u32 {} +impl SimdCast for u32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for u64 {} +unsafe impl Sealed for u64 {} +impl SimdCast for u64 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for usize {} +unsafe impl Sealed for usize {} +impl SimdCast for usize {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for f32 {} +unsafe impl Sealed for f32 {} +impl SimdCast for f32 {} // Safety: primitive number types can be cast to other primitive number types -unsafe impl SimdCast for f64 {} - -/// Supporting trait for `Simd::cast_ptr`. Typically doesn't need to be used directly. -/// -/// # Safety -/// Implementing this trait asserts that the type is a valid vector element for the `simd_cast_ptr` -/// intrinsic. -pub unsafe trait SimdCastPtr {} - -// Safety: pointers can be cast to other pointer types -unsafe impl SimdCastPtr for *const U -where - U: core::ptr::Pointee, - T: core::ptr::Pointee, -{ -} -// Safety: pointers can be cast to other pointer types -unsafe impl SimdCastPtr for *mut U -where - U: core::ptr::Pointee, - T: core::ptr::Pointee, -{ -} +unsafe impl Sealed for f64 {} +impl SimdCast for f64 {} diff --git a/portable-simd/crates/core_simd/src/elements/const_ptr.rs b/portable-simd/crates/core_simd/src/elements/const_ptr.rs index 0ef9802b5..f215f9a61 100644 --- a/portable-simd/crates/core_simd/src/elements/const_ptr.rs +++ b/portable-simd/crates/core_simd/src/elements/const_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: Copy + Sealed { @@ -9,6 +9,9 @@ pub trait SimdConstPtr: Copy + Sealed { /// Vector of `isize` with the same number of lanes. type Isize; + /// Vector of const pointers with the same number of lanes. + type CastPtr; + /// Vector of mutable pointers to the same type. type MutPtr; @@ -18,6 +21,11 @@ pub trait SimdConstPtr: Copy + Sealed { /// Returns `true` for each lane that is null. fn is_null(self) -> Self::Mask; + /// Casts to a pointer of another type. + /// + /// Equivalent to calling [`pointer::cast`] on each lane. + fn cast(self) -> Self::CastPtr; + /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_mut`] on each lane. @@ -78,6 +86,7 @@ where { type Usize = Simd; type Isize = Simd; + type CastPtr = Simd<*const U, LANES>; type MutPtr = Simd<*mut T, LANES>; type Mask = Mask; @@ -86,9 +95,22 @@ where Simd::splat(core::ptr::null()).simd_eq(self) } + #[inline] + fn cast(self) -> Self::CastPtr { + // SimdElement currently requires zero-sized metadata, so this should never fail. + // If this ever changes, `simd_cast_ptr` should produce a post-mono error. + use core::{mem::size_of, ptr::Pointee}; + assert_eq!(size_of::<::Metadata>(), 0); + assert_eq!(size_of::<::Metadata>(), 0); + + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } + } + #[inline] fn cast_mut(self) -> Self::MutPtr { - self.cast_ptr() + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } } #[inline] @@ -106,9 +128,9 @@ where // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. - self.cast_ptr::<*const u8>() + self.cast::() .wrapping_offset(addr.cast::() - self.addr().cast::()) - .cast_ptr() + .cast() } #[inline] diff --git a/portable-simd/crates/core_simd/src/elements/float.rs b/portable-simd/crates/core_simd/src/elements/float.rs index d60223270..501c1c5dd 100644 --- a/portable-simd/crates/core_simd/src/elements/float.rs +++ b/portable-simd/crates/core_simd/src/elements/float.rs @@ -1,6 +1,6 @@ use super::sealed::Sealed; use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd, + intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialEq, SimdPartialOrd, SupportedLaneCount, }; @@ -15,6 +15,53 @@ pub trait SimdFloat: Copy + Sealed { /// Bit representation of this SIMD vector type. type Bits; + /// A SIMD vector with a different element type. + type Cast; + + /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. + /// + /// This follows the semantics of Rust's `as` conversion for floats (truncating or saturating + /// at the limits) for each element. + /// + /// # Example + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::{SimdFloat, SimdInt, Simd}; + /// let floats: Simd = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]); + /// let ints = floats.cast::(); + /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0])); + /// + /// // Formally equivalent, but `Simd::cast` can optimize better. + /// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32))); + /// + /// // The float conversion does not round-trip. + /// let floats_again = ints.cast(); + /// assert_ne!(floats, floats_again); + /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0])); + /// ``` + #[must_use] + fn cast(self) -> Self::Cast; + + /// Rounds toward zero and converts to the same-width integer type, assuming that + /// the value is finite and fits in that type. + /// + /// # Safety + /// The value must: + /// + /// * Not be NaN + /// * Not be infinite + /// * Be representable in the return type, after truncating off its fractional part + /// + /// If these requirements are infeasible or costly, consider using the safe function [cast], + /// which saturates on conversion. + /// + /// [cast]: Simd::cast + unsafe fn to_int_unchecked(self) -> Self::Cast + where + Self::Scalar: core::convert::FloatToInt; + /// Raw transmutation to an unsigned integer vector type with the /// same size and number of lanes. #[must_use = "method returns a new vector and does not mutate the original value"] @@ -206,6 +253,24 @@ macro_rules! impl_trait { type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>; type Scalar = $ty; type Bits = Simd<$bits_ty, LANES>; + type Cast = Simd; + + #[inline] + fn cast(self) -> Self::Cast + { + // Safety: supported types are guaranteed by SimdCast + unsafe { intrinsics::simd_as(self) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn to_int_unchecked(self) -> Self::Cast + where + Self::Scalar: core::convert::FloatToInt, + { + // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants + unsafe { intrinsics::simd_cast(self) } + } #[inline] fn to_bits(self) -> Simd<$bits_ty, LANES> { diff --git a/portable-simd/crates/core_simd/src/elements/int.rs b/portable-simd/crates/core_simd/src/elements/int.rs index 9b8c37ed4..6db89ff9a 100644 --- a/portable-simd/crates/core_simd/src/elements/int.rs +++ b/portable-simd/crates/core_simd/src/elements/int.rs @@ -1,6 +1,6 @@ use super::sealed::Sealed; use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount, + intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialOrd, SupportedLaneCount, }; /// Operations on SIMD vectors of signed integers. @@ -11,6 +11,16 @@ pub trait SimdInt: Copy + Sealed { /// Scalar type contained by this SIMD vector type. type Scalar; + /// A SIMD vector with a different element type. + type Cast; + + /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. + /// + /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to + /// other integer types, and saturating to float types). + #[must_use] + fn cast(self) -> Self::Cast; + /// Lanewise saturating add. /// /// # Examples @@ -198,6 +208,13 @@ macro_rules! impl_trait { { type Mask = Mask<<$ty as SimdElement>::Mask, LANES>; type Scalar = $ty; + type Cast = Simd; + + #[inline] + fn cast(self) -> Self::Cast { + // Safety: supported types are guaranteed by SimdCast + unsafe { intrinsics::simd_as(self) } + } #[inline] fn saturating_add(self, second: Self) -> Self { diff --git a/portable-simd/crates/core_simd/src/elements/mut_ptr.rs b/portable-simd/crates/core_simd/src/elements/mut_ptr.rs index d87986b4a..4bdc6a14c 100644 --- a/portable-simd/crates/core_simd/src/elements/mut_ptr.rs +++ b/portable-simd/crates/core_simd/src/elements/mut_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: Copy + Sealed { @@ -9,6 +9,9 @@ pub trait SimdMutPtr: Copy + Sealed { /// Vector of `isize` with the same number of lanes. type Isize; + /// Vector of const pointers with the same number of lanes. + type CastPtr; + /// Vector of constant pointers to the same type. type ConstPtr; @@ -18,6 +21,11 @@ pub trait SimdMutPtr: Copy + Sealed { /// Returns `true` for each lane that is null. fn is_null(self) -> Self::Mask; + /// Casts to a pointer of another type. + /// + /// Equivalent to calling [`pointer::cast`] on each lane. + fn cast(self) -> Self::CastPtr; + /// Changes constness without changing the type. /// /// Equivalent to calling [`pointer::cast_const`] on each lane. @@ -73,6 +81,7 @@ where { type Usize = Simd; type Isize = Simd; + type CastPtr = Simd<*mut U, LANES>; type ConstPtr = Simd<*const T, LANES>; type Mask = Mask; @@ -81,9 +90,22 @@ where Simd::splat(core::ptr::null_mut()).simd_eq(self) } + #[inline] + fn cast(self) -> Self::CastPtr { + // SimdElement currently requires zero-sized metadata, so this should never fail. + // If this ever changes, `simd_cast_ptr` should produce a post-mono error. + use core::{mem::size_of, ptr::Pointee}; + assert_eq!(size_of::<::Metadata>(), 0); + assert_eq!(size_of::<::Metadata>(), 0); + + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } + } + #[inline] fn cast_const(self) -> Self::ConstPtr { - self.cast_ptr() + // Safety: pointers can be cast + unsafe { intrinsics::simd_cast_ptr(self) } } #[inline] @@ -101,9 +123,9 @@ where // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. - self.cast_ptr::<*mut u8>() + self.cast::() .wrapping_offset(addr.cast::() - self.addr().cast::()) - .cast_ptr() + .cast() } #[inline] diff --git a/portable-simd/crates/core_simd/src/elements/uint.rs b/portable-simd/crates/core_simd/src/elements/uint.rs index 21e7e76eb..3926c395e 100644 --- a/portable-simd/crates/core_simd/src/elements/uint.rs +++ b/portable-simd/crates/core_simd/src/elements/uint.rs @@ -1,11 +1,21 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Simd, SupportedLaneCount}; +use crate::simd::{intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount}; /// Operations on SIMD vectors of unsigned integers. pub trait SimdUint: Copy + Sealed { /// Scalar type contained by this SIMD vector type. type Scalar; + /// A SIMD vector with a different element type. + type Cast; + + /// Performs elementwise conversion of this vector's elements to another SIMD-valid type. + /// + /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to + /// other integer types, and saturating to float types). + #[must_use] + fn cast(self) -> Self::Cast; + /// Lanewise saturating add. /// /// # Examples @@ -77,6 +87,13 @@ macro_rules! impl_trait { LaneCount: SupportedLaneCount, { type Scalar = $ty; + type Cast = Simd; + + #[inline] + fn cast(self) -> Self::Cast { + // Safety: supported types are guaranteed by SimdCast + unsafe { intrinsics::simd_as(self) } + } #[inline] fn saturating_add(self, second: Self) -> Self { diff --git a/portable-simd/crates/core_simd/src/iter.rs b/portable-simd/crates/core_simd/src/iter.rs index 3275b4db8..328c995b8 100644 --- a/portable-simd/crates/core_simd/src/iter.rs +++ b/portable-simd/crates/core_simd/src/iter.rs @@ -10,6 +10,7 @@ macro_rules! impl_traits { where LaneCount: SupportedLaneCount, { + #[inline] fn sum>(iter: I) -> Self { iter.fold(Simd::splat(0 as $type), Add::add) } @@ -19,6 +20,7 @@ macro_rules! impl_traits { where LaneCount: SupportedLaneCount, { + #[inline] fn product>(iter: I) -> Self { iter.fold(Simd::splat(1 as $type), Mul::mul) } @@ -28,6 +30,7 @@ macro_rules! impl_traits { where LaneCount: SupportedLaneCount, { + #[inline] fn sum>(iter: I) -> Self { iter.fold(Simd::splat(0 as $type), Add::add) } @@ -37,6 +40,7 @@ macro_rules! impl_traits { where LaneCount: SupportedLaneCount, { + #[inline] fn product>(iter: I) -> Self { iter.fold(Simd::splat(1 as $type), Mul::mul) } diff --git a/portable-simd/crates/core_simd/src/lib.rs b/portable-simd/crates/core_simd/src/lib.rs index e5307de21..fde406bda 100644 --- a/portable-simd/crates/core_simd/src/lib.rs +++ b/portable-simd/crates/core_simd/src/lib.rs @@ -16,7 +16,7 @@ )] #![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))] #![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))] -#![warn(missing_docs)] +#![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. diff --git a/portable-simd/crates/core_simd/src/masks.rs b/portable-simd/crates/core_simd/src/masks.rs index e0f3c7bee..fea687bdc 100644 --- a/portable-simd/crates/core_simd/src/masks.rs +++ b/portable-simd/crates/core_simd/src/masks.rs @@ -179,6 +179,7 @@ where /// Panics if any lane is not 0 or -1. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] + #[track_caller] pub fn from_int(value: Simd) -> Self { assert!(T::valid(value), "all values must be either 0 or -1",); // Safety: the validity has been checked @@ -217,6 +218,7 @@ where /// Panics if `lane` is greater than or equal to the number of lanes in the vector. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] + #[track_caller] pub fn test(&self, lane: usize) -> bool { assert!(lane < LANES, "lane index out of range"); // Safety: the lane index has been checked @@ -240,6 +242,7 @@ where /// # Panics /// Panics if `lane` is greater than or equal to the number of lanes in the vector. #[inline] + #[track_caller] pub fn set(&mut self, lane: usize, value: bool) { assert!(lane < LANES, "lane index out of range"); // Safety: the lane index has been checked @@ -327,6 +330,7 @@ where T: MaskElement + fmt::Debug, LaneCount: SupportedLaneCount, { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries((0..LANES).map(|lane| self.test(lane))) diff --git a/portable-simd/crates/core_simd/src/mod.rs b/portable-simd/crates/core_simd/src/mod.rs index 35c659b7a..f9891a3b7 100644 --- a/portable-simd/crates/core_simd/src/mod.rs +++ b/portable-simd/crates/core_simd/src/mod.rs @@ -23,6 +23,8 @@ mod vendor; #[doc = include_str!("core_simd_docs.md")] pub mod simd { + pub mod prelude; + pub(crate) use crate::core_simd::intrinsics; pub use crate::core_simd::alias::*; diff --git a/portable-simd/crates/core_simd/src/ops.rs b/portable-simd/crates/core_simd/src/ops.rs index fc1e0bc42..b007456cf 100644 --- a/portable-simd/crates/core_simd/src/ops.rs +++ b/portable-simd/crates/core_simd/src/ops.rs @@ -15,6 +15,7 @@ where I: core::slice::SliceIndex<[T]>, { type Output = I::Output; + #[inline] fn index(&self, index: I) -> &Self::Output { &self.as_array()[index] } @@ -26,6 +27,7 @@ where LaneCount: SupportedLaneCount, I: core::slice::SliceIndex<[T]>, { + #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { &mut self.as_mut_array()[index] } @@ -118,10 +120,14 @@ macro_rules! for_base_types { #[inline] #[must_use = "operator returns a new vector without mutating the inputs"] + // TODO: only useful for int Div::div, but we hope that this + // will essentially always always get inlined anyway. + #[track_caller] fn $call(self, rhs: Self) -> Self::Output { $macro_impl!(self, rhs, $inner, $scalar) } - })* + } + )* } } diff --git a/portable-simd/crates/core_simd/src/ord.rs b/portable-simd/crates/core_simd/src/ord.rs index 1ae9cd061..b2455190e 100644 --- a/portable-simd/crates/core_simd/src/ord.rs +++ b/portable-simd/crates/core_simd/src/ord.rs @@ -94,6 +94,7 @@ macro_rules! impl_integer { } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), @@ -200,6 +201,7 @@ macro_rules! impl_mask { } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), @@ -254,6 +256,7 @@ where } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), @@ -303,6 +306,7 @@ where } #[inline] + #[track_caller] fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), diff --git a/portable-simd/crates/core_simd/src/simd/prelude.rs b/portable-simd/crates/core_simd/src/simd/prelude.rs new file mode 100644 index 000000000..e8fdc932d --- /dev/null +++ b/portable-simd/crates/core_simd/src/simd/prelude.rs @@ -0,0 +1,80 @@ +//! The portable SIMD prelude. +//! +//! Includes important traits and types to be imported with a glob: +//! ```ignore +//! use std::simd::prelude::*; +//! ``` + +#[doc(no_inline)] +pub use super::{ + simd_swizzle, Mask, Simd, SimdConstPtr, SimdFloat, SimdInt, SimdMutPtr, SimdOrd, SimdPartialEq, + SimdPartialOrd, SimdUint, +}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{f32x1, f32x2, f32x4, f32x8, f32x16, f32x32, f32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{f64x1, f64x2, f64x4, f64x8, f64x16, f64x32, f64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i8x1, i8x2, i8x4, i8x8, i8x16, i8x32, i8x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i16x1, i16x2, i16x4, i16x8, i16x16, i16x32, i16x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i32x1, i32x2, i32x4, i32x8, i32x16, i32x32, i32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{i64x1, i64x2, i64x4, i64x8, i64x16, i64x32, i64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{isizex1, isizex2, isizex4, isizex8, isizex16, isizex32, isizex64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u8x1, u8x2, u8x4, u8x8, u8x16, u8x32, u8x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u16x1, u16x2, u16x4, u16x8, u16x16, u16x32, u16x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u32x1, u32x2, u32x4, u32x8, u32x16, u32x32, u32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{u64x1, u64x2, u64x4, u64x8, u64x16, u64x32, u64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{usizex1, usizex2, usizex4, usizex8, usizex16, usizex32, usizex64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask8x1, mask8x2, mask8x4, mask8x8, mask8x16, mask8x32, mask8x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask16x1, mask16x2, mask16x4, mask16x8, mask16x16, mask16x32, mask16x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask32x1, mask32x2, mask32x4, mask32x8, mask32x16, mask32x32, mask32x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{mask64x1, mask64x2, mask64x4, mask64x8, mask64x16, mask64x32, mask64x64}; + +#[rustfmt::skip] +#[doc(no_inline)] +pub use super::{masksizex1, masksizex2, masksizex4, masksizex8, masksizex16, masksizex32, masksizex64}; diff --git a/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/portable-simd/crates/core_simd/src/swizzle_dyn.rs index 6065d6459..ce6217925 100644 --- a/portable-simd/crates/core_simd/src/swizzle_dyn.rs +++ b/portable-simd/crates/core_simd/src/swizzle_dyn.rs @@ -16,9 +16,14 @@ where #[inline] pub fn swizzle_dyn(self, idxs: Simd) -> Self { #![allow(unused_imports, unused_unsafe)] - #[cfg(target_arch = "aarch64")] + #[cfg(all(target_arch = "aarch64", target_endian = "little"))] use core::arch::aarch64::{uint8x8_t, vqtbl1q_u8, vtbl1_u8}; - #[cfg(all(target_arch = "arm", target_feature = "v7", target_feature = "neon"))] + #[cfg(all( + target_arch = "arm", + target_feature = "v7", + target_feature = "neon", + target_endian = "little" + ))] use core::arch::arm::{uint8x8_t, vtbl1_u8}; #[cfg(target_arch = "wasm32")] use core::arch::wasm32 as wasm; @@ -29,13 +34,24 @@ where // SAFETY: Intrinsics covered by cfg unsafe { match N { - #[cfg(target_feature = "neon")] + #[cfg(all( + any( + target_arch = "aarch64", + all(target_arch = "arm", target_feature = "v7") + ), + target_feature = "neon", + target_endian = "little" + ))] 8 => transize(vtbl1_u8, self, idxs), #[cfg(target_feature = "ssse3")] 16 => transize(x86::_mm_shuffle_epi8, self, idxs), #[cfg(target_feature = "simd128")] 16 => transize(wasm::i8x16_swizzle, self, idxs), - #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] + #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + target_endian = "little" + ))] 16 => transize(vqtbl1q_u8, self, idxs), #[cfg(all(target_feature = "avx2", not(target_feature = "avx512vbmi")))] 32 => transize_raw(avx2_pshufb, self, idxs), diff --git a/portable-simd/crates/core_simd/src/vector.rs b/portable-simd/crates/core_simd/src/vector.rs index 3809cc961..9aa7bacfc 100644 --- a/portable-simd/crates/core_simd/src/vector.rs +++ b/portable-simd/crates/core_simd/src/vector.rs @@ -1,6 +1,6 @@ use crate::simd::{ - intrinsics, LaneCount, Mask, MaskElement, SimdCast, SimdCastPtr, SimdConstPtr, SimdMutPtr, - SimdPartialOrd, SupportedLaneCount, Swizzle, + intrinsics, LaneCount, Mask, MaskElement, SimdConstPtr, SimdMutPtr, SimdPartialOrd, + SupportedLaneCount, Swizzle, }; use core::convert::{TryFrom, TryInto}; @@ -122,6 +122,7 @@ where /// let v = u32x4::splat(0); /// assert_eq!(v.lanes(), 4); /// ``` + #[inline] pub const fn lanes(&self) -> usize { Self::LANES } @@ -136,6 +137,7 @@ where /// let v = u32x4::splat(8); /// assert_eq!(v.as_array(), &[8, 8, 8, 8]); /// ``` + #[inline] pub fn splat(value: T) -> Self { // This is preferred over `[value; N]`, since it's explicitly a splat: // https://github.com/rust-lang/rust/issues/97804 @@ -156,6 +158,7 @@ where /// let v: u64x4 = Simd::from_array([0, 1, 2, 3]); /// assert_eq!(v.as_array(), &[0, 1, 2, 3]); /// ``` + #[inline] pub const fn as_array(&self) -> &[T; N] { // SAFETY: `Simd` is just an overaligned `[T; N]` with // potential padding at the end, so pointer casting to a @@ -167,6 +170,7 @@ where } /// Returns a mutable array reference containing the entire SIMD vector. + #[inline] pub fn as_mut_array(&mut self) -> &mut [T; N] { // SAFETY: `Simd` is just an overaligned `[T; N]` with // potential padding at the end, so pointer casting to a @@ -184,6 +188,7 @@ where /// /// # Safety /// Reading `ptr` must be safe, as if by `<*const [T; N]>::read_unaligned`. + #[inline] const unsafe fn load(ptr: *const [T; N]) -> Self { // There are potentially simpler ways to write this function, but this should result in // LLVM `load ` @@ -204,6 +209,7 @@ where /// /// # Safety /// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write_unaligned`. + #[inline] const unsafe fn store(self, ptr: *mut [T; N]) { // There are potentially simpler ways to write this function, but this should result in // LLVM `store ` @@ -216,6 +222,7 @@ where } /// Converts an array to a SIMD vector. + #[inline] pub const fn from_array(array: [T; N]) -> Self { // SAFETY: `&array` is safe to read. // @@ -228,6 +235,7 @@ where } /// Converts a SIMD vector to an array. + #[inline] pub const fn to_array(self) -> [T; N] { let mut tmp = core::mem::MaybeUninit::uninit(); // SAFETY: writing to `tmp` is safe and initializes it. @@ -259,6 +267,8 @@ where /// assert_eq!(v.as_array(), &[1, 2, 3, 4]); /// ``` #[must_use] + #[inline] + #[track_caller] pub const fn from_slice(slice: &[T]) -> Self { assert!( slice.len() >= Self::LANES, @@ -287,6 +297,8 @@ where /// v.copy_to_slice(&mut dest); /// assert_eq!(&dest, &[1, 2, 3, 4, 0, 0]); /// ``` + #[inline] + #[track_caller] pub fn copy_to_slice(self, slice: &mut [T]) { assert!( slice.len() >= Self::LANES, @@ -297,76 +309,6 @@ where unsafe { self.store(slice.as_mut_ptr().cast()) } } - /// Performs elementwise conversion of a SIMD vector's elements to another SIMD-valid type. - /// - /// This follows the semantics of Rust's `as` conversion for casting integers between - /// signed and unsigned (interpreting integers as 2s complement, so `-1` to `U::MAX` and - /// `1 << (U::BITS -1)` becoming `I::MIN` ), and from floats to integers (truncating, - /// or saturating at the limits) for each element. - /// - /// # Examples - /// ``` - /// # #![feature(portable_simd)] - /// # use core::simd::Simd; - /// let floats: Simd = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]); - /// let ints = floats.cast::(); - /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0])); - /// - /// // Formally equivalent, but `Simd::cast` can optimize better. - /// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32))); - /// - /// // The float conversion does not round-trip. - /// let floats_again = ints.cast(); - /// assert_ne!(floats, floats_again); - /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0])); - /// ``` - #[must_use] - #[inline] - pub fn cast(self) -> Simd - where - T: SimdCast, - { - // Safety: supported types are guaranteed by SimdCast - unsafe { intrinsics::simd_as(self) } - } - - /// Casts a vector of pointers to another pointer type. - #[must_use] - #[inline] - pub fn cast_ptr(self) -> Simd - where - T: SimdCastPtr, - U: SimdElement, - { - // Safety: supported types are guaranteed by SimdCastPtr - unsafe { intrinsics::simd_cast_ptr(self) } - } - - /// Rounds toward zero and converts to the same-width integer type, assuming that - /// the value is finite and fits in that type. - /// - /// # Safety - /// The value must: - /// - /// * Not be NaN - /// * Not be infinite - /// * Be representable in the return type, after truncating off its fractional part - /// - /// If these requirements are infeasible or costly, consider using the safe function [cast], - /// which saturates on conversion. - /// - /// [cast]: Simd::cast - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub unsafe fn to_int_unchecked(self) -> Simd - where - T: core::convert::FloatToInt + SimdCast, - I: SimdCast, - { - // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants - unsafe { intrinsics::simd_cast(self) } - } - /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector. /// If an index is out-of-bounds, the element is instead selected from the `or` vector. /// @@ -717,6 +659,7 @@ where LaneCount: SupportedLaneCount, T: SimdElement, { + #[inline] fn clone(&self) -> Self { *self } @@ -861,6 +804,7 @@ where LaneCount: SupportedLaneCount, T: SimdElement, { + #[inline] fn from(array: [T; N]) -> Self { Self::from_array(array) } @@ -871,6 +815,7 @@ where LaneCount: SupportedLaneCount, T: SimdElement, { + #[inline] fn from(vector: Simd) -> Self { vector.to_array() } @@ -883,6 +828,7 @@ where { type Error = core::array::TryFromSliceError; + #[inline] fn try_from(slice: &[T]) -> Result { Ok(Self::from_array(slice.try_into()?)) } @@ -895,6 +841,7 @@ where { type Error = core::array::TryFromSliceError; + #[inline] fn try_from(slice: &mut [T]) -> Result { Ok(Self::from_array(slice.try_into()?)) } diff --git a/portable-simd/crates/core_simd/tests/cast.rs b/portable-simd/crates/core_simd/tests/cast.rs index ab5650f07..00545936e 100644 --- a/portable-simd/crates/core_simd/tests/cast.rs +++ b/portable-simd/crates/core_simd/tests/cast.rs @@ -2,7 +2,8 @@ macro_rules! cast_types { ($start:ident, $($target:ident),*) => { mod $start { - use core_simd::simd::Simd; + #[allow(unused)] + use core_simd::simd::{Simd, SimdInt, SimdUint, SimdFloat}; type Vector = Simd<$start, N>; $( mod $target { diff --git a/portable-simd/crates/core_simd/tests/round.rs b/portable-simd/crates/core_simd/tests/round.rs index 8b9638ad4..aacf7bd3b 100644 --- a/portable-simd/crates/core_simd/tests/round.rs +++ b/portable-simd/crates/core_simd/tests/round.rs @@ -53,6 +53,7 @@ macro_rules! float_rounding_test { test_helpers::test_lanes! { fn to_int_unchecked() { + use core_simd::simd::SimdFloat; // The maximum integer that can be represented by the equivalently sized float has // all of the mantissa digits set to 1, pushed up to the MSB. const ALL_MANTISSA_BITS: IntScalar = ((1 << ::MANTISSA_DIGITS) - 1); From d9fe2ab6fbdbe4bdec5053bb64e7712b2c6983cb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 10 Jul 2023 10:41:13 -0400 Subject: [PATCH 177/180] Replace version placeholder to 1.72 --- alloc/src/string.rs | 2 +- core/src/ffi/c_str.rs | 8 ++++---- std/src/ffi/os_str.rs | 2 +- std/src/sync/mpsc/mod.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/alloc/src/string.rs b/alloc/src/string.rs index 1c6815fa9..ad7b77f54 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -1873,7 +1873,7 @@ impl String { /// let static_ref: &'static mut str = x.leak(); /// assert_eq!(static_ref, "bucket"); /// ``` - #[stable(feature = "string_leak", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "string_leak", since = "1.72.0")] #[inline] pub fn leak<'a>(self) -> &'a mut str { let slice = self.vec.leak(); diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 3de9188ba..39f795c1f 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -377,7 +377,7 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - #[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { @@ -561,7 +561,7 @@ impl CStr { #[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_cstr_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); // FIXME(const-hack) replace with range index @@ -590,7 +590,7 @@ impl CStr { #[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_cstr_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. @@ -614,7 +614,7 @@ impl CStr { /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - #[rustc_const_stable(feature = "const_cstr_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index fbdf7f5ec..e7bad9d54 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -1165,7 +1165,7 @@ impl<'a> From> for OsString { } } -#[stable(feature = "str_tryfrom_osstr_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "str_tryfrom_osstr_impl", since = "1.72.0")] impl<'a> TryFrom<&'a OsStr> for &'a str { type Error = crate::str::Utf8Error; diff --git a/std/src/sync/mpsc/mod.rs b/std/src/sync/mpsc/mod.rs index 71ff4237d..c00134c8b 100644 --- a/std/src/sync/mpsc/mod.rs +++ b/std/src/sync/mpsc/mod.rs @@ -347,7 +347,7 @@ pub struct Sender { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Sender {} -#[stable(feature = "mpsc_sender_sync", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "mpsc_sender_sync", since = "1.72.0")] unsafe impl Sync for Sender {} /// The sending-half of Rust's synchronous [`sync_channel`] type. From 070e8ca258d8a9b1743c454dcc2ec107548bd461 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Wed, 19 Jul 2023 11:50:29 -0400 Subject: [PATCH 178/180] avoid tls access while iterating through mpsc thread entries (cherry picked from commit fb31a1ac21833b205196128b7425f5c587cd883c) --- std/src/sync/mpmc/waker.rs | 46 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/std/src/sync/mpmc/waker.rs b/std/src/sync/mpmc/waker.rs index 4912ca4f8..9aab1b941 100644 --- a/std/src/sync/mpmc/waker.rs +++ b/std/src/sync/mpmc/waker.rs @@ -66,26 +66,32 @@ impl Waker { /// Attempts to find another thread's entry, select the operation, and wake it up. #[inline] pub(crate) fn try_select(&mut self) -> Option { - self.selectors - .iter() - .position(|selector| { - // Does the entry belong to a different thread? - selector.cx.thread_id() != current_thread_id() - && selector // Try selecting this operation. - .cx - .try_select(Selected::Operation(selector.oper)) - .is_ok() - && { - // Provide the packet. - selector.cx.store_packet(selector.packet); - // Wake the thread up. - selector.cx.unpark(); - true - } - }) - // Remove the entry from the queue to keep it clean and improve - // performance. - .map(|pos| self.selectors.remove(pos)) + if self.selectors.is_empty() { + None + } else { + let thread_id = current_thread_id(); + + self.selectors + .iter() + .position(|selector| { + // Does the entry belong to a different thread? + selector.cx.thread_id() != thread_id + && selector // Try selecting this operation. + .cx + .try_select(Selected::Operation(selector.oper)) + .is_ok() + && { + // Provide the packet. + selector.cx.store_packet(selector.packet); + // Wake the thread up. + selector.cx.unpark(); + true + } + }) + // Remove the entry from the queue to keep it clean and improve + // performance. + .map(|pos| self.selectors.remove(pos)) + } } /// Notifies all operations waiting to be ready. From f76185049f8156641ebc2004b8e7615a9791ad9a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 14 Aug 2023 16:48:39 -0700 Subject: [PATCH 179/180] Upgrade std to gimli 0.28.0 --- std/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/Cargo.toml b/std/Cargo.toml index eb4815d0c..e022c2d14 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -25,11 +25,11 @@ hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate -addr2line = { version = "0.20.0", optional = true, default-features = false } +addr2line = { version = "0.21.0", optional = true, default-features = false } rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } miniz_oxide = { version = "0.7.0", optional = true, default-features = false, public = false } [dependencies.object] -version = "0.31.1" +version = "0.32.0" optional = true default-features = false features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] From 22fc544a713c1182881ce9d487a31ca76886315a Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 16 Aug 2023 08:58:02 -0700 Subject: [PATCH 180/180] Partially revert #107200 `Ok(0)` is indeed something the caller may interpret as an error, but that's the *correct* thing to return if the writer can't accept any more bytes. (cherry picked from commit 5210f482d7309004c0ff3f6306f052f8d5adb67b) --- std/src/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 5c1d2d8f4..71d91f213 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -1425,9 +1425,9 @@ pub trait Write { /// /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. - /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the - /// caller may interpret that as an error. To indicate lack of space, - /// implementors should return [`ErrorKind::StorageFull`] error instead. + /// A return value of `Ok(0)` typically means that the underlying object is + /// no longer able to accept bytes and will likely not be able to in the + /// future as well, or that the buffer provided is empty. /// /// # Errors ///