Importing rustc-1.60.0
Test: ./build.py --lto=thin
Bug: 218368713
Change-Id: Id769ad47aab28ec7b551d06785fb811cdf441aec
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index b3ff0fd..2650202 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -6,7 +6,7 @@
description = "The Rust core allocation and collections library"
autotests = false
autobenches = false
-edition = "2018"
+edition = "2021"
[dependencies]
core = { path = "../core" }
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index d075658..9d4f9af 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -348,7 +348,6 @@
// This is the magic symbol to call the global alloc error handler. rustc generates
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
// default implementations below (`__rdl_oom`) otherwise.
- #[rustc_allocator_nounwind]
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
}
@@ -367,7 +366,6 @@
#[stable(feature = "global_alloc", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
-#[rustc_allocator_nounwind]
#[cold]
pub const fn handle_alloc_error(layout: Layout) -> ! {
const fn ct_error(_: Layout) -> ! {
@@ -398,13 +396,13 @@
// if there is no `#[alloc_error_handler]`
#[rustc_std_internal_symbol]
- pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! {
+ pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! {
panic!("memory allocation of {} bytes failed", size)
}
// if there is an `#[alloc_error_handler]`
#[rustc_std_internal_symbol]
- pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! {
+ pub unsafe extern "C-unwind" fn __rg_oom(size: usize, align: usize) -> ! {
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
extern "Rust" {
#[lang = "oom"]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index aa7344b..f753189 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -133,6 +133,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use core::any::Any;
+use core::async_iter::AsyncIterator;
use core::borrow;
use core::cmp::Ordering;
use core::convert::{From, TryFrom};
@@ -149,7 +150,6 @@
};
use core::pin::Pin;
use core::ptr::{self, Unique};
-use core::stream::Stream;
use core::task::{Context, Poll};
#[cfg(not(no_global_oom_handling))]
@@ -1170,8 +1170,7 @@
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_box", issue = "92521")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler.
}
@@ -1992,8 +1991,8 @@
}
}
-#[unstable(feature = "async_stream", issue = "79024")]
-impl<S: ?Sized + Stream + Unpin> Stream for Box<S> {
+#[unstable(feature = "async_iterator", issue = "79024")]
+impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index 6fc6002..e18cd8cd 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -433,7 +433,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from(vec![1, 3]);
+ /// let mut heap = BinaryHeap::from([1, 3]);
///
/// assert_eq!(heap.pop(), Some(3));
/// assert_eq!(heap.pop(), Some(1));
@@ -506,7 +506,7 @@
/// ```
/// use std::collections::BinaryHeap;
///
- /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]);
+ /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]);
/// heap.push(6);
/// heap.push(3);
///
@@ -725,11 +725,8 @@
/// ```
/// use std::collections::BinaryHeap;
///
- /// let v = vec![-10, 1, 2, 3, 3];
- /// let mut a = BinaryHeap::from(v);
- ///
- /// let v = vec![-20, 5, 43];
- /// let mut b = BinaryHeap::from(v);
+ /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]);
+ /// let mut b = BinaryHeap::from([-20, 5, 43]);
///
/// a.append(&mut b);
///
@@ -749,9 +746,12 @@
self.rebuild_tail(start);
}
- /// Returns an iterator which retrieves elements in heap order.
- /// The retrieved elements are removed from the original heap.
- /// The remaining elements will be removed on drop in heap order.
+ /// Clears the binary heap, returning an iterator over the removed elements
+ /// in heap order. If the iterator is dropped before being fully consumed,
+ /// it drops the remaining elements in heap order.
+ ///
+ /// The returned iterator keeps a mutable borrow on the heap to optimize
+ /// its implementation.
///
/// Note:
/// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
@@ -765,7 +765,7 @@
/// #![feature(binary_heap_drain_sorted)]
/// use std::collections::BinaryHeap;
///
- /// let mut heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
+ /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]);
/// assert_eq!(heap.len(), 5);
///
/// drop(heap.drain_sorted()); // removes all elements in heap order
@@ -790,7 +790,7 @@
/// #![feature(binary_heap_retain)]
/// use std::collections::BinaryHeap;
///
- /// let mut heap = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]);
+ /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
///
/// heap.retain(|x| x % 2 == 0); // only keep even numbers
///
@@ -826,7 +826,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]);
+ /// let heap = BinaryHeap::from([1, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.iter() {
@@ -848,9 +848,9 @@
/// ```
/// #![feature(binary_heap_into_iter_sorted)]
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
+ /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]);
///
- /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
+ /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]);
/// ```
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
@@ -1086,7 +1086,7 @@
/// use std::collections::BinaryHeap;
/// use std::io::{self, Write};
///
- /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]);
+ /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
///
/// io::sink().write(heap.as_slice()).unwrap();
/// ```
@@ -1105,7 +1105,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]);
+ /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
/// let vec = heap.into_vec();
///
/// // Will print in some order
@@ -1127,7 +1127,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from(vec![1, 3]);
+ /// let heap = BinaryHeap::from([1, 3]);
///
/// assert_eq!(heap.len(), 2);
/// ```
@@ -1161,9 +1161,12 @@
self.len() == 0
}
- /// Clears the binary heap, returning an iterator over the removed elements.
+ /// Clears the binary heap, returning an iterator over the removed elements
+ /// in arbitrary order. If the iterator is dropped before being fully
+ /// consumed, it drops the remaining elements in arbitrary order.
///
- /// The elements are removed in arbitrary order.
+ /// The returned iterator keeps a mutable borrow on the heap to optimize
+ /// its implementation.
///
/// # Examples
///
@@ -1171,7 +1174,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from(vec![1, 3]);
+ /// let mut heap = BinaryHeap::from([1, 3]);
///
/// assert!(!heap.is_empty());
///
@@ -1195,7 +1198,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from(vec![1, 3]);
+ /// let mut heap = BinaryHeap::from([1, 3]);
///
/// assert!(!heap.is_empty());
///
@@ -1616,7 +1619,7 @@
///
/// ```
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]);
+ /// let heap = BinaryHeap::from([1, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.into_iter() {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 199c05d..67f5b38 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -16,7 +16,10 @@
use super::search::SearchResult::*;
mod entry;
+
+#[stable(feature = "rust1", since = "1.0.0")]
pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry};
+
use Entry::*;
/// Minimum number of elements in a node that is not a root.
@@ -31,7 +34,7 @@
// An empty map is represented either by the absence of a root node or by a
// root node that is an empty leaf.
-/// A map based on a [B-Tree].
+/// An ordered map based on a [B-Tree].
///
/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal
@@ -65,6 +68,10 @@
/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
/// behavior.
///
+/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or
+/// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and
+/// amortized constant time per item returned.
+///
/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree
/// [`Cell`]: core::cell::Cell
/// [`RefCell`]: core::cell::RefCell
@@ -1091,10 +1098,8 @@
/// ```
/// use std::collections::BTreeMap;
///
- /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"]
- /// .iter()
- /// .map(|&s| (s, 0))
- /// .collect();
+ /// let mut map: BTreeMap<&str, i32> =
+ /// [("Alice", 0), ("Bob", 0), ("Carol", 0), ("Cheryl", 0)].into();
/// for (_, balance) in map.range_mut("B".."Cheryl") {
/// *balance += 100;
/// }
@@ -1128,7 +1133,7 @@
/// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
///
/// // count the number of occurrences of letters in the vec
- /// for x in vec!["a", "b", "a", "c", "a", "b"] {
+ /// for x in ["a", "b", "a", "c", "a", "b"] {
/// *count.entry(x).or_insert(0) += 1;
/// }
///
@@ -1228,8 +1233,8 @@
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
/// let evens: BTreeMap<_, _> = map.drain_filter(|k, _v| k % 2 == 0).collect();
/// let odds = map;
- /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), vec![0, 2, 4, 6]);
- /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
+ /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
+ /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
/// ```
#[unstable(feature = "btree_drain_filter", issue = "70530")]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
@@ -2047,6 +2052,8 @@
#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> {
+ /// Converts a `[(K, V); N]` into a `BTreeMap<(K, V)>`.
+ ///
/// ```
/// use std::collections::BTreeMap;
///
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index c95aeea..b39b540 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -728,7 +728,7 @@
#[test]
fn test_range_inclusive_max_value() {
let max = usize::MAX;
- let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect();
+ let map: BTreeMap<_, _> = [(max, 0)].into_iter().collect();
assert_eq!(map.range(max..=max).collect::<Vec<_>>(), &[(&max, &0)]);
}
@@ -2128,7 +2128,7 @@
#[test]
fn test_into_keys() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let vec = [(1, 'a'), (2, 'b'), (3, 'c')];
let map: BTreeMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 394c21b..a4315be 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -15,7 +15,7 @@
// FIXME(conventions): implement bounded iterators
-/// A set based on a B-Tree.
+/// An ordered set based on a B-Tree.
///
/// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance
/// benefits and drawbacks.
@@ -27,6 +27,9 @@
/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
/// behavior.
///
+/// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case
+/// logarithmic and amortized constant time per item returned.
+///
/// [`Ord`]: core::cmp::Ord
/// [`Cell`]: core::cell::Cell
/// [`RefCell`]: core::cell::RefCell
@@ -1094,6 +1097,8 @@
#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {
+ /// Converts a `[T; N]` into a `BTreeSet<T>`.
+ ///
/// ```
/// use std::collections::BTreeSet;
///
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 4a07d5d..d81f24e 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -1953,6 +1953,8 @@
#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T, const N: usize> From<[T; N]> for LinkedList<T> {
+ /// Converts a `[T; N]` into a `LinkedList<T>`.
+ ///
/// ```
/// use std::collections::LinkedList;
///
diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs
index 1ea135a..628a5b1 100644
--- a/library/alloc/src/collections/mod.rs
+++ b/library/alloc/src/collections/mod.rs
@@ -14,7 +14,7 @@
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_map {
- //! A map based on a B-Tree.
+ //! An ordered map based on a B-Tree.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::btree::map::*;
}
@@ -22,7 +22,7 @@
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_set {
- //! A set based on a B-Tree.
+ //! An ordered set based on a B-Tree.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::btree::set::*;
}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 075becf..7139a0f 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1,4 +1,4 @@
-//! A double-ended queue implemented with a growable ring buffer.
+//! A double-ended queue (deque) implemented with a growable ring buffer.
//!
//! This queue has *O*(1) amortized inserts and removals from both ends of the
//! container. It also has *O*(1) indexing like a vector. The contained elements
@@ -156,7 +156,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Default for VecDeque<T> {
- /// Creates an empty `VecDeque<T>`.
+ /// Creates an empty deque.
#[inline]
fn default() -> VecDeque<T> {
VecDeque::new()
@@ -483,14 +483,14 @@
}
impl<T> VecDeque<T> {
- /// Creates an empty `VecDeque`.
+ /// Creates an empty deque.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let vector: VecDeque<u32> = VecDeque::new();
+ /// let deque: VecDeque<u32> = VecDeque::new();
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -499,14 +499,14 @@
VecDeque::new_in(Global)
}
- /// Creates an empty `VecDeque` with space for at least `capacity` elements.
+ /// Creates an empty deque with space for at least `capacity` elements.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+ /// let deque: VecDeque<u32> = VecDeque::with_capacity(10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -517,14 +517,14 @@
}
impl<T, A: Allocator> VecDeque<T, A> {
- /// Creates an empty `VecDeque`.
+ /// Creates an empty deque.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let vector: VecDeque<u32> = VecDeque::new();
+ /// let deque: VecDeque<u32> = VecDeque::new();
/// ```
#[inline]
#[unstable(feature = "allocator_api", issue = "32838")]
@@ -532,14 +532,14 @@
VecDeque::with_capacity_in(INITIAL_CAPACITY, alloc)
}
- /// Creates an empty `VecDeque` with space for at least `capacity` elements.
+ /// Creates an empty deque with space for at least `capacity` elements.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+ /// let deque: VecDeque<u32> = VecDeque::with_capacity(10);
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
@@ -636,7 +636,7 @@
unsafe { ptr::swap(self.ptr().add(ri), self.ptr().add(rj)) }
}
- /// Returns the number of elements the `VecDeque` can hold without
+ /// Returns the number of elements the deque can hold without
/// reallocating.
///
/// # Examples
@@ -654,7 +654,7 @@
}
/// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the
- /// given `VecDeque`. Does nothing if the capacity is already sufficient.
+ /// given deque. Does nothing if the capacity is already sufficient.
///
/// Note that the allocator may give the collection more space than it requests. Therefore
/// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future
@@ -669,7 +669,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
+ /// let mut buf: VecDeque<i32> = [1].into();
/// buf.reserve_exact(10);
/// assert!(buf.capacity() >= 11);
/// ```
@@ -681,7 +681,7 @@
}
/// Reserves capacity for at least `additional` more elements to be inserted in the given
- /// `VecDeque`. The collection may reserve more space to avoid frequent reallocations.
+ /// deque. The collection may reserve more space to avoid frequent reallocations.
///
/// # Panics
///
@@ -692,7 +692,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
+ /// let mut buf: VecDeque<i32> = [1].into();
/// buf.reserve(10);
/// assert!(buf.capacity() >= 11);
/// ```
@@ -714,7 +714,7 @@
}
/// Tries to reserve the minimum capacity for exactly `additional` more elements to
- /// be inserted in the given `VecDeque<T>`. After calling `try_reserve_exact`,
+ /// be inserted in the given deque. After calling `try_reserve_exact`,
/// capacity will be greater than or equal to `self.len() + additional`.
/// Does nothing if the capacity is already sufficient.
///
@@ -756,7 +756,7 @@
}
/// Tries to reserve capacity for at least `additional` more elements to be inserted
- /// in the given `VecDeque<T>`. The collection may reserve more space to avoid
+ /// in the given deque. The collection may reserve more space to avoid
/// frequent reallocations. After calling `try_reserve`, capacity will be
/// greater than or equal to `self.len() + additional`. Does nothing if
/// capacity is already sufficient.
@@ -805,10 +805,10 @@
Ok(())
}
- /// Shrinks the capacity of the `VecDeque` as much as possible.
+ /// Shrinks the capacity of the deque as much as possible.
///
/// It will drop down as close as possible to the length but the allocator may still inform the
- /// `VecDeque` that there is space for a few more elements.
+ /// deque that there is space for a few more elements.
///
/// # Examples
///
@@ -826,7 +826,7 @@
self.shrink_to(0);
}
- /// Shrinks the capacity of the `VecDeque` with a lower bound.
+ /// Shrinks the capacity of the deque with a lower bound.
///
/// The capacity will remain at least as large as both the length
/// and the supplied value.
@@ -909,10 +909,10 @@
}
}
- /// Shortens the `VecDeque`, keeping the first `len` elements and dropping
+ /// Shortens the deque, keeping the first `len` elements and dropping
/// the rest.
///
- /// If `len` is greater than the `VecDeque`'s current length, this has no
+ /// If `len` is greater than the deque's current length, this has no
/// effect.
///
/// # Examples
@@ -1027,10 +1027,10 @@
}
/// Returns a pair of slices which contain, in order, the contents of the
- /// `VecDeque`.
+ /// deque.
///
/// If [`make_contiguous`] was previously called, all elements of the
- /// `VecDeque` will be in the first slice and the second slice will be empty.
+ /// deque will be in the first slice and the second slice will be empty.
///
/// [`make_contiguous`]: VecDeque::make_contiguous
///
@@ -1039,18 +1039,18 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut vector = VecDeque::new();
+ /// let mut deque = VecDeque::new();
///
- /// vector.push_back(0);
- /// vector.push_back(1);
- /// vector.push_back(2);
+ /// deque.push_back(0);
+ /// deque.push_back(1);
+ /// deque.push_back(2);
///
- /// assert_eq!(vector.as_slices(), (&[0, 1, 2][..], &[][..]));
+ /// assert_eq!(deque.as_slices(), (&[0, 1, 2][..], &[][..]));
///
- /// vector.push_front(10);
- /// vector.push_front(9);
+ /// deque.push_front(10);
+ /// deque.push_front(9);
///
- /// assert_eq!(vector.as_slices(), (&[9, 10][..], &[0, 1, 2][..]));
+ /// assert_eq!(deque.as_slices(), (&[9, 10][..], &[0, 1, 2][..]));
/// ```
#[inline]
#[stable(feature = "deque_extras_15", since = "1.5.0")]
@@ -1062,10 +1062,10 @@
}
/// Returns a pair of slices which contain, in order, the contents of the
- /// `VecDeque`.
+ /// deque.
///
/// If [`make_contiguous`] was previously called, all elements of the
- /// `VecDeque` will be in the first slice and the second slice will be empty.
+ /// deque will be in the first slice and the second slice will be empty.
///
/// [`make_contiguous`]: VecDeque::make_contiguous
///
@@ -1074,17 +1074,17 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut vector = VecDeque::new();
+ /// let mut deque = VecDeque::new();
///
- /// vector.push_back(0);
- /// vector.push_back(1);
+ /// deque.push_back(0);
+ /// deque.push_back(1);
///
- /// vector.push_front(10);
- /// vector.push_front(9);
+ /// deque.push_front(10);
+ /// deque.push_front(9);
///
- /// vector.as_mut_slices().0[0] = 42;
- /// vector.as_mut_slices().1[0] = 24;
- /// assert_eq!(vector.as_slices(), (&[42, 10][..], &[24, 1][..]));
+ /// deque.as_mut_slices().0[0] = 42;
+ /// deque.as_mut_slices().1[0] = 24;
+ /// assert_eq!(deque.as_slices(), (&[42, 10][..], &[24, 1][..]));
/// ```
#[inline]
#[stable(feature = "deque_extras_15", since = "1.5.0")]
@@ -1097,34 +1097,34 @@
}
}
- /// Returns the number of elements in the `VecDeque`.
+ /// Returns the number of elements in the deque.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v = VecDeque::new();
- /// assert_eq!(v.len(), 0);
- /// v.push_back(1);
- /// assert_eq!(v.len(), 1);
+ /// let mut deque = VecDeque::new();
+ /// assert_eq!(deque.len(), 0);
+ /// deque.push_back(1);
+ /// assert_eq!(deque.len(), 1);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
count(self.tail, self.head, self.cap())
}
- /// Returns `true` if the `VecDeque` is empty.
+ /// Returns `true` if the deque is empty.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v = VecDeque::new();
- /// assert!(v.is_empty());
- /// v.push_front(1);
- /// assert!(!v.is_empty());
+ /// let mut deque = VecDeque::new();
+ /// assert!(deque.is_empty());
+ /// deque.push_front(1);
+ /// assert!(!deque.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
@@ -1141,24 +1141,24 @@
(tail, head)
}
- /// Creates an iterator that covers the specified range in the `VecDeque`.
+ /// Creates an iterator that covers the specified range in the deque.
///
/// # Panics
///
/// Panics if the starting point is greater than the end point or if
- /// the end point is greater than the length of the vector.
+ /// the end point is greater than the length of the deque.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
- /// let range = v.range(2..).copied().collect::<VecDeque<_>>();
+ /// let deque: VecDeque<_> = [1, 2, 3].into();
+ /// let range = deque.range(2..).copied().collect::<VecDeque<_>>();
/// assert_eq!(range, [3]);
///
/// // A full range covers all contents
- /// let all = v.range(..);
+ /// let all = deque.range(..);
/// assert_eq!(all.len(), 3);
/// ```
#[inline]
@@ -1176,29 +1176,29 @@
}
}
- /// Creates an iterator that covers the specified mutable range in the `VecDeque`.
+ /// Creates an iterator that covers the specified mutable range in the deque.
///
/// # Panics
///
/// Panics if the starting point is greater than the end point or if
- /// the end point is greater than the length of the vector.
+ /// the end point is greater than the length of the deque.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
- /// for v in v.range_mut(2..) {
+ /// let mut deque: VecDeque<_> = [1, 2, 3].into();
+ /// for v in deque.range_mut(2..) {
/// *v *= 2;
/// }
- /// assert_eq!(v, vec![1, 2, 6]);
+ /// assert_eq!(deque, [1, 2, 6]);
///
/// // A full range covers all contents
- /// for v in v.range_mut(..) {
+ /// for v in deque.range_mut(..) {
/// *v *= 2;
/// }
- /// assert_eq!(v, vec![2, 4, 12]);
+ /// assert_eq!(deque, [2, 4, 12]);
/// ```
#[inline]
#[stable(feature = "deque_range", since = "1.51.0")]
@@ -1215,34 +1215,38 @@
unsafe { IterMut::new(ring, tail, head, PhantomData) }
}
- /// Creates a draining iterator that removes the specified range in the
- /// `VecDeque` and yields the removed items.
+ /// Removes the specified range from the deque in bulk, returning all
+ /// removed elements as an iterator. If the iterator is dropped before
+ /// being fully consumed, it drops the remaining removed elements.
///
- /// Note 1: The element range is removed even if the iterator is not
- /// consumed until the end.
+ /// The returned iterator keeps a mutable borrow on the queue to optimize
+ /// its implementation.
///
- /// Note 2: It is unspecified how many elements are removed from the deque,
- /// if the `Drain` value is not dropped, but the borrow it holds expires
- /// (e.g., due to `mem::forget`).
///
/// # Panics
///
/// Panics if the starting point is greater than the end point or if
- /// the end point is greater than the length of the vector.
+ /// the end point is greater than the length of the deque.
+ ///
+ /// # Leaking
+ ///
+ /// If the returned iterator goes out of scope without being dropped (due to
+ /// [`mem::forget`], for example), the deque may have lost and leaked
+ /// elements arbitrarily, including elements outside the range.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
- /// let drained = v.drain(2..).collect::<VecDeque<_>>();
+ /// let mut deque: VecDeque<_> = [1, 2, 3].into();
+ /// let drained = deque.drain(2..).collect::<VecDeque<_>>();
/// assert_eq!(drained, [3]);
- /// assert_eq!(v, [1, 2]);
+ /// assert_eq!(deque, [1, 2]);
///
- /// // A full range clears all contents
- /// v.drain(..);
- /// assert!(v.is_empty());
+ /// // A full range clears all contents, like `clear()` does
+ /// deque.drain(..);
+ /// assert!(deque.is_empty());
/// ```
#[inline]
#[stable(feature = "drain", since = "1.6.0")]
@@ -1297,17 +1301,17 @@
unsafe { Drain::new(drain_head, head, iter, deque) }
}
- /// Clears the `VecDeque`, removing all values.
+ /// Clears the deque, removing all values.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v = VecDeque::new();
- /// v.push_back(1);
- /// v.clear();
- /// assert!(v.is_empty());
+ /// let mut deque = VecDeque::new();
+ /// deque.push_back(1);
+ /// deque.clear();
+ /// assert!(deque.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -1315,7 +1319,7 @@
self.truncate(0);
}
- /// Returns `true` if the `VecDeque` contains an element equal to the
+ /// Returns `true` if the deque contains an element equal to the
/// given value.
///
/// # Examples
@@ -1323,13 +1327,13 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut vector: VecDeque<u32> = VecDeque::new();
+ /// let mut deque: VecDeque<u32> = VecDeque::new();
///
- /// vector.push_back(0);
- /// vector.push_back(1);
+ /// deque.push_back(0);
+ /// deque.push_back(1);
///
- /// assert_eq!(vector.contains(&1), true);
- /// assert_eq!(vector.contains(&10), false);
+ /// assert_eq!(deque.contains(&1), true);
+ /// assert_eq!(deque.contains(&10), false);
/// ```
#[stable(feature = "vec_deque_contains", since = "1.12.0")]
pub fn contains(&self, x: &T) -> bool
@@ -1340,7 +1344,7 @@
a.contains(x) || b.contains(x)
}
- /// Provides a reference to the front element, or `None` if the `VecDeque` is
+ /// Provides a reference to the front element, or `None` if the deque is
/// empty.
///
/// # Examples
@@ -1361,7 +1365,7 @@
}
/// Provides a mutable reference to the front element, or `None` if the
- /// `VecDeque` is empty.
+ /// deque is empty.
///
/// # Examples
///
@@ -1384,7 +1388,7 @@
self.get_mut(0)
}
- /// Provides a reference to the back element, or `None` if the `VecDeque` is
+ /// Provides a reference to the back element, or `None` if the deque is
/// empty.
///
/// # Examples
@@ -1405,7 +1409,7 @@
}
/// Provides a mutable reference to the back element, or `None` if the
- /// `VecDeque` is empty.
+ /// deque is empty.
///
/// # Examples
///
@@ -1428,7 +1432,7 @@
self.get_mut(self.len().wrapping_sub(1))
}
- /// Removes the first element and returns it, or `None` if the `VecDeque` is
+ /// Removes the first element and returns it, or `None` if the deque is
/// empty.
///
/// # Examples
@@ -1455,7 +1459,7 @@
}
}
- /// Removes the last element from the `VecDeque` and returns it, or `None` if
+ /// Removes the last element from the deque and returns it, or `None` if
/// it is empty.
///
/// # Examples
@@ -1480,7 +1484,7 @@
}
}
- /// Prepends an element to the `VecDeque`.
+ /// Prepends an element to the deque.
///
/// # Examples
///
@@ -1505,7 +1509,7 @@
}
}
- /// Appends an element to the back of the `VecDeque`.
+ /// Appends an element to the back of the deque.
///
/// # Examples
///
@@ -1535,7 +1539,7 @@
self.tail <= self.head
}
- /// Removes an element from anywhere in the `VecDeque` and returns it,
+ /// Removes an element from anywhere in the deque and returns it,
/// replacing it with the first element.
///
/// This does not preserve ordering, but is *O*(1).
@@ -1570,8 +1574,8 @@
self.pop_front()
}
- /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
- /// last element.
+ /// Removes an element from anywhere in the deque and returns it,
+ /// replacing it with the last element.
///
/// This does not preserve ordering, but is *O*(1).
///
@@ -1605,14 +1609,14 @@
self.pop_back()
}
- /// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices
- /// greater than or equal to `index` towards the back.
+ /// Inserts an element at `index` within the deque, shifting all elements
+ /// with indices greater than or equal to `index` towards the back.
///
/// Element at index 0 is the front of the queue.
///
/// # Panics
///
- /// Panics if `index` is greater than `VecDeque`'s length
+ /// Panics if `index` is greater than deque's length
///
/// # Examples
///
@@ -1829,7 +1833,7 @@
}
}
- /// Removes and returns the element at `index` from the `VecDeque`.
+ /// Removes and returns the element at `index` from the deque.
/// Whichever end is closer to the removal point will be moved to make
/// room, and all the affected elements will be moved to new positions.
/// Returns `None` if `index` is out of bounds.
@@ -2007,10 +2011,10 @@
elem
}
- /// Splits the `VecDeque` into two at the given index.
+ /// Splits the deque into two at the given index.
///
/// Returns a newly allocated `VecDeque`. `self` contains elements `[0, at)`,
- /// and the returned `VecDeque` contains elements `[at, len)`.
+ /// and the returned deque contains elements `[at, len)`.
///
/// Note that the capacity of `self` does not change.
///
@@ -2025,7 +2029,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+ /// let mut buf: VecDeque<_> = [1, 2, 3].into();
/// let buf2 = buf.split_off(1);
/// assert_eq!(buf, [1]);
/// assert_eq!(buf2, [2, 3]);
@@ -2091,8 +2095,8 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect();
- /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect();
+ /// let mut buf: VecDeque<_> = [1, 2].into();
+ /// let mut buf2: VecDeque<_> = [3, 4].into();
/// buf.append(&mut buf2);
/// assert_eq!(buf, [1, 2, 3, 4]);
/// assert_eq!(buf2, []);
@@ -2227,7 +2231,7 @@
debug_assert!(!self.is_full());
}
- /// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`,
+ /// Modifies the deque in-place so that `len()` is equal to `new_len`,
/// either by removing excess elements from the back or by appending
/// elements generated by calling `generator` to the back.
///
@@ -2272,7 +2276,7 @@
///
/// Once the internal storage is contiguous, the [`as_slices`] and
/// [`as_mut_slices`] methods will return the entire contents of the
- /// `VecDeque` in a single slice.
+ /// deque in a single slice.
///
/// [`as_slices`]: VecDeque::as_slices
/// [`as_mut_slices`]: VecDeque::as_mut_slices
@@ -2524,7 +2528,7 @@
}
}
- /// Binary searches this sorted `VecDeque` for a given element.
+ /// Binary searches the sorted deque for a given element.
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
@@ -2547,7 +2551,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+ /// let deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
///
/// assert_eq!(deque.binary_search(&13), Ok(9));
/// assert_eq!(deque.binary_search(&4), Err(7));
@@ -2556,13 +2560,13 @@
/// assert!(matches!(r, Ok(1..=4)));
/// ```
///
- /// If you want to insert an item to a sorted `VecDeque`, while maintaining
+ /// If you want to insert an item to a sorted deque, while maintaining
/// sort order:
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+ /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// let num = 42;
/// let idx = deque.binary_search(&num).unwrap_or_else(|x| x);
/// deque.insert(idx, num);
@@ -2577,12 +2581,12 @@
self.binary_search_by(|e| e.cmp(x))
}
- /// Binary searches this sorted `VecDeque` with a comparator function.
+ /// Binary searches the sorted deque with a comparator function.
///
/// The comparator function should implement an order consistent
- /// with the sort order of the underlying `VecDeque`, returning an
- /// order code that indicates whether its argument is `Less`,
- /// `Equal` or `Greater` than the desired target.
+ /// with the sort order of the deque, returning an order code that
+ /// indicates whether its argument is `Less`, `Equal` or `Greater`
+ /// than the desired target.
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
@@ -2605,7 +2609,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+ /// let deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
///
/// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)), Ok(9));
/// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)), Err(7));
@@ -2630,9 +2634,9 @@
}
}
- /// Binary searches this sorted `VecDeque` with a key extraction function.
+ /// Binary searches the sorted deque with a key extraction function.
///
- /// Assumes that the `VecDeque` is sorted by the key, for instance with
+ /// Assumes that the deque is sorted by the key, for instance with
/// [`make_contiguous().sort_by_key()`] using the same key extraction function.
///
/// If the value is found then [`Result::Ok`] is returned, containing the
@@ -2658,7 +2662,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
+ /// let deque: VecDeque<_> = [(0, 0), (2, 1), (4, 1), (5, 1),
/// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
/// (1, 21), (2, 34), (4, 55)].into();
///
@@ -2687,7 +2691,7 @@
/// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
/// (all odd numbers are at the start, all even at the end).
///
- /// If this deque is not partitioned, the returned result is unspecified and meaningless,
+ /// If the deque is not partitioned, the returned result is unspecified and meaningless,
/// as this method performs a kind of binary search.
///
/// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`].
@@ -2701,7 +2705,7 @@
/// ```
/// use std::collections::VecDeque;
///
- /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into();
+ /// let deque: VecDeque<_> = [1, 2, 3, 3, 5, 6, 7].into();
/// let i = deque.partition_point(|&x| x < 5);
///
/// assert_eq!(i, 4);
@@ -2724,7 +2728,7 @@
}
impl<T: Clone, A: Allocator> VecDeque<T, A> {
- /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len,
+ /// Modifies the deque in-place so that `len()` is equal to new_len,
/// either by removing excess elements from the back or by appending clones of `value`
/// to the back.
///
@@ -2878,7 +2882,7 @@
type Item = T;
type IntoIter = IntoIter<T, A>;
- /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by
+ /// Consumes the deque into a front-to-back iterator yielding elements by
/// value.
fn into_iter(self) -> IntoIter<T, A> {
IntoIter::new(self)
@@ -3049,6 +3053,8 @@
#[stable(feature = "std_collections_from_array", since = "1.56.0")]
impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
+ /// Converts a `[T; N]` into a `VecDeque<T>`.
+ ///
/// ```
/// use std::collections::VecDeque;
///
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index b4d16d7..aeb7554 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -74,7 +74,7 @@
//! identifier '=' expression
//! ```
//!
-//! For example, the following [`format!`] expressions all use named argument:
+//! For example, the following [`format!`] expressions all use named arguments:
//!
//! ```
//! format!("{argument}", argument = "test"); // => "test"
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 7e663fa..6da32df 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -67,17 +67,14 @@
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
-#![cfg_attr(
- not(bootstrap),
- doc(cfg_hide(
- not(test),
- not(any(test, bootstrap)),
- any(not(feature = "miri-test-libstd"), test, doctest),
- no_global_oom_handling,
- not(no_global_oom_handling),
- target_has_atomic = "ptr"
- ))
-)]
+#![doc(cfg_hide(
+ not(test),
+ not(any(test, bootstrap)),
+ any(not(feature = "miri-test-libstd"), test, doctest),
+ no_global_oom_handling,
+ not(no_global_oom_handling),
+ target_has_atomic = "ptr"
+))]
#![no_std]
#![needs_allocator]
//
@@ -94,7 +91,7 @@
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_windows)]
-#![feature(async_stream)]
+#![feature(async_iterator)]
#![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
#![feature(const_box)]
@@ -115,11 +112,9 @@
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
-#![feature(inherent_ascii_escape)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
#![feature(layout_for_ptr)]
-#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_slice)]
#![cfg_attr(test, feature(new_uninit))]
#![feature(nonnull_slice_from_raw_parts)]
@@ -144,7 +139,7 @@
#![feature(associated_type_bounds)]
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
-#![feature(cfg_target_has_atomic)]
+#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))]
#![feature(const_deref)]
#![feature(const_fn_trait_bound)]
#![feature(const_mut_refs)]
@@ -152,7 +147,6 @@
#![feature(const_precise_live_drops)]
#![feature(const_trait_impl)]
#![feature(const_try)]
-#![cfg_attr(bootstrap, feature(destructuring_assignment))]
#![feature(dropck_eyepatch)]
#![feature(exclusive_range_pattern)]
#![feature(fundamental)]
@@ -168,6 +162,7 @@
#![cfg_attr(test, feature(test))]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
+#![feature(c_unwind)]
//
// Rustdoc features:
#![feature(doc_cfg)]
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index 189da9f..d3e9e65 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -37,6 +37,7 @@
#[cfg(not(test))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "vec_macro"]
#[allow_internal_unstable(box_syntax, liballoc_internals)]
macro_rules! vec {
() => (
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 3806bc5..8fa0242 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -108,7 +108,7 @@
// to round up a request of less than 8 bytes to at least 8 bytes.
// - 4 if elements are moderate-sized (<= 1 KiB).
// - 1 otherwise, to avoid wasting too much space for very short Vecs.
- const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
+ pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
8
} else if mem::size_of::<T>() <= 1024 {
4
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 33bee43..3065169 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -374,33 +374,51 @@
}
}
- /// Constructs a new `Rc<T>` using a weak reference to itself. Attempting
- /// to upgrade the weak reference before this function returns will result
- /// in a `None` value. However, the weak reference may be cloned freely and
- /// stored for use at a later time.
+ /// Constructs a new `Rc<T>` using a closure `data_fn` that has access to a
+ /// weak reference to the constructing `Rc<T>`.
+ ///
+ /// Generally, a structure circularly referencing itself, either directly or
+ /// indirectly, should not hold a strong reference to prevent a memory leak.
+ /// In `data_fn`, initialization of `T` can make use of the weak reference
+ /// by cloning and storing it inside `T` for use at a later time.
+ ///
+ /// Since the new `Rc<T>` is not fully-constructed until `Rc<T>::new_cyclic`
+ /// returns, calling [`upgrade`] on the weak reference inside `data_fn` will
+ /// fail and result in a `None` value.
+ ///
+ /// # Panics
+ /// If `data_fn` panics, the panic is propagated to the caller, and the
+ /// temporary [`Weak<T>`] is dropped normally.
///
/// # Examples
///
/// ```
- /// #![feature(arc_new_cyclic)]
/// #![allow(dead_code)]
/// use std::rc::{Rc, Weak};
///
/// struct Gadget {
- /// self_weak: Weak<Self>,
- /// // ... more fields
+ /// me: Weak<Gadget>,
/// }
+ ///
/// impl Gadget {
- /// pub fn new() -> Rc<Self> {
- /// Rc::new_cyclic(|self_weak| {
- /// Gadget { self_weak: self_weak.clone(), /* ... */ }
- /// })
+ /// /// Construct a reference counted Gadget.
+ /// fn new() -> Rc<Self> {
+ /// Rc::new_cyclic(|me| Gadget { me: me.clone() })
+ /// }
+ ///
+ /// /// Return a reference counted pointer to Self.
+ /// fn me(&self) -> Rc<Self> {
+ /// self.me.upgrade().unwrap()
/// }
/// }
/// ```
+ /// [`upgrade`]: Weak::upgrade
#[cfg(not(no_global_oom_handling))]
- #[unstable(feature = "arc_new_cyclic", issue = "75861")]
- pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
+ #[stable(feature = "arc_new_cyclic", since = "1.60.0")]
+ pub fn new_cyclic<F>(data_fn: F) -> Rc<T>
+ where
+ F: FnOnce(&Weak<T>) -> T,
+ {
// Construct the inner in the "uninitialized" state with a single
// weak reference.
let uninit_ptr: NonNull<_> = Box::leak(box RcBox {
@@ -451,12 +469,10 @@
///
/// let mut five = Rc::<u32>::new_uninit();
///
- /// let five = unsafe {
- /// // Deferred initialization:
- /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+ /// // Deferred initialization:
+ /// Rc::get_mut(&mut five).unwrap().write(5);
///
- /// five.assume_init()
- /// };
+ /// let five = unsafe { five.assume_init() };
///
/// assert_eq!(*five, 5)
/// ```
@@ -543,12 +559,10 @@
///
/// let mut five = Rc::<u32>::try_new_uninit()?;
///
- /// let five = unsafe {
- /// // Deferred initialization:
- /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+ /// // Deferred initialization:
+ /// Rc::get_mut(&mut five).unwrap().write(5);
///
- /// five.assume_init()
- /// };
+ /// let five = unsafe { five.assume_init() };
///
/// assert_eq!(*five, 5);
/// # Ok::<(), std::alloc::AllocError>(())
@@ -660,14 +674,13 @@
///
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
///
- /// let values = unsafe {
- /// // Deferred initialization:
- /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
- /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
- /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+ /// // Deferred initialization:
+ /// let data = Rc::get_mut(&mut values).unwrap();
+ /// data[0].write(1);
+ /// data[1].write(2);
+ /// data[2].write(3);
///
- /// values.assume_init()
- /// };
+ /// let values = unsafe { values.assume_init() };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
@@ -738,12 +751,10 @@
///
/// let mut five = Rc::<u32>::new_uninit();
///
- /// let five = unsafe {
- /// // Deferred initialization:
- /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+ /// // Deferred initialization:
+ /// Rc::get_mut(&mut five).unwrap().write(5);
///
- /// five.assume_init()
- /// };
+ /// let five = unsafe { five.assume_init() };
///
/// assert_eq!(*five, 5)
/// ```
@@ -777,14 +788,13 @@
///
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
///
- /// let values = unsafe {
- /// // Deferred initialization:
- /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
- /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
- /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+ /// // Deferred initialization:
+ /// let data = Rc::get_mut(&mut values).unwrap();
+ /// data[0].write(1);
+ /// data[1].write(2);
+ /// data[2].write(3);
///
- /// values.assume_init()
- /// };
+ /// let values = unsafe { values.assume_init() };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
@@ -1193,6 +1203,41 @@
// reference to the allocation.
unsafe { &mut this.ptr.as_mut().value }
}
+
+ /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
+ /// clone.
+ ///
+ /// Assuming `rc_t` is of type `Rc<T>`, this function is functionally equivalent to
+ /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(arc_unwrap_or_clone)]
+ /// # use std::{ptr, rc::Rc};
+ /// let inner = String::from("test");
+ /// let ptr = inner.as_ptr();
+ ///
+ /// let rc = Rc::new(inner);
+ /// let inner = Rc::unwrap_or_clone(rc);
+ /// // The inner value was not cloned
+ /// assert!(ptr::eq(ptr, inner.as_ptr()));
+ ///
+ /// let rc = Rc::new(inner);
+ /// let rc2 = rc.clone();
+ /// let inner = Rc::unwrap_or_clone(rc);
+ /// // Because there were 2 references, we had to clone the inner value.
+ /// assert!(!ptr::eq(ptr, inner.as_ptr()));
+ /// // `rc2` is the last reference, so when we unwrap it we get back
+ /// // the original `String`.
+ /// let inner = Rc::unwrap_or_clone(rc2);
+ /// assert!(ptr::eq(ptr, inner.as_ptr()));
+ /// ```
+ #[inline]
+ #[unstable(feature = "arc_unwrap_or_clone", issue = "93610")]
+ pub fn unwrap_or_clone(this: Self) -> T {
+ Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone())
+ }
}
impl Rc<dyn Any> {
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 8853577..f0397d0 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -108,7 +108,7 @@
pub use core::slice::ArrayChunksMut;
#[unstable(feature = "array_windows", issue = "75027")]
pub use core::slice::ArrayWindows;
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub use core::slice::EscapeAscii;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
@@ -375,7 +375,10 @@
/// Sorts the slice with a key extraction function.
///
- /// During sorting, the key function is called only once per element.
+ /// During sorting, the key function is called at most once per element, by using
+ /// temporary storage to remember the results of key evaluation.
+ /// The order of calls to the key function is unspecified and may change in future versions
+ /// of the standard library.
///
/// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*))
/// worst-case, where the key function is *O*(*m*).
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 7c0faf0..716bb49 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1628,17 +1628,24 @@
self.vec.clear()
}
- /// Creates a draining iterator that removes the specified range in the `String`
- /// and yields the removed `chars`.
+ /// Removes the specified range from the string in bulk, returning all
+ /// removed characters as an iterator.
///
- /// Note: The element range is removed even if the iterator is not
- /// consumed until the end.
+ /// The returned iterator keeps a mutable borrow on the string to optimize
+ /// its implementation.
///
/// # Panics
///
/// Panics if the starting point or end point do not lie on a [`char`]
/// boundary, or if they're out of bounds.
///
+ /// # Leaking
+ ///
+ /// If the returned iterator goes out of scope without being dropped (due to
+ /// [`core::mem::forget`], for example), the string may still contain a copy
+ /// of any drained characters, or may have lost characters arbitrarily,
+ /// including characters outside the range.
+ ///
/// # Examples
///
/// Basic usage:
@@ -1652,7 +1659,7 @@
/// assert_eq!(t, "α is alpha, ");
/// assert_eq!(s, "β is beta");
///
- /// // A full range clears the string
+ /// // A full range clears the string, like `clear()` does
/// s.drain(..);
/// assert_eq!(s, "");
/// ```
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 7c065f3..7e7670a 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -351,30 +351,51 @@
unsafe { Self::from_inner(Box::leak(x).into()) }
}
- /// Constructs a new `Arc<T>` using a weak reference to itself. Attempting
- /// to upgrade the weak reference before this function returns will result
- /// in a `None` value. However, the weak reference may be cloned freely and
- /// stored for use at a later time.
+ /// Constructs a new `Arc<T>` using a closure `data_fn` that has access to
+ /// a weak reference to the constructing `Arc<T>`.
///
- /// # Examples
+ /// Generally, a structure circularly referencing itself, either directly or
+ /// indirectly, should not hold a strong reference to prevent a memory leak.
+ /// In `data_fn`, initialization of `T` can make use of the weak reference
+ /// by cloning and storing it inside `T` for use at a later time.
+ ///
+ /// Since the new `Arc<T>` is not fully-constructed until
+ /// `Arc<T>::new_cyclic` returns, calling [`upgrade`] on the weak
+ /// reference inside `data_fn` will fail and result in a `None` value.
+ ///
+ /// # Panics
+ /// If `data_fn` panics, the panic is propagated to the caller, and the
+ /// temporary [`Weak<T>`] is dropped normally.
+ ///
+ /// # Example
/// ```
- /// #![feature(arc_new_cyclic)]
/// #![allow(dead_code)]
- ///
/// use std::sync::{Arc, Weak};
///
- /// struct Foo {
- /// me: Weak<Foo>,
+ /// struct Gadget {
+ /// me: Weak<Gadget>,
/// }
///
- /// let foo = Arc::new_cyclic(|me| Foo {
- /// me: me.clone(),
- /// });
+ /// impl Gadget {
+ /// /// Construct a reference counted Gadget.
+ /// fn new() -> Arc<Self> {
+ /// Arc::new_cyclic(|me| Gadget { me: me.clone() })
+ /// }
+ ///
+ /// /// Return a reference counted pointer to Self.
+ /// fn me(&self) -> Arc<Self> {
+ /// self.me.upgrade().unwrap()
+ /// }
+ /// }
/// ```
+ /// [`upgrade`]: Weak::upgrade
#[cfg(not(no_global_oom_handling))]
#[inline]
- #[unstable(feature = "arc_new_cyclic", issue = "75861")]
- pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T> {
+ #[stable(feature = "arc_new_cyclic", since = "1.60.0")]
+ pub fn new_cyclic<F>(data_fn: F) -> Arc<T>
+ where
+ F: FnOnce(&Weak<T>) -> T,
+ {
// Construct the inner in the "uninitialized" state with a single
// weak reference.
let uninit_ptr: NonNull<_> = Box::leak(box ArcInner {
@@ -437,12 +458,10 @@
///
/// let mut five = Arc::<u32>::new_uninit();
///
- /// let five = unsafe {
- /// // Deferred initialization:
- /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+ /// // Deferred initialization:
+ /// Arc::get_mut(&mut five).unwrap().write(5);
///
- /// five.assume_init()
- /// };
+ /// let five = unsafe { five.assume_init() };
///
/// assert_eq!(*five, 5)
/// ```
@@ -545,12 +564,10 @@
///
/// let mut five = Arc::<u32>::try_new_uninit()?;
///
- /// let five = unsafe {
- /// // Deferred initialization:
- /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+ /// // Deferred initialization:
+ /// Arc::get_mut(&mut five).unwrap().write(5);
///
- /// five.assume_init()
- /// };
+ /// let five = unsafe { five.assume_init() };
///
/// assert_eq!(*five, 5);
/// # Ok::<(), std::alloc::AllocError>(())
@@ -652,14 +669,13 @@
///
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
///
- /// let values = unsafe {
- /// // Deferred initialization:
- /// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
- /// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
- /// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+ /// // Deferred initialization:
+ /// let data = Arc::get_mut(&mut values).unwrap();
+ /// data[0].write(1);
+ /// data[1].write(2);
+ /// data[2].write(3);
///
- /// values.assume_init()
- /// };
+ /// let values = unsafe { values.assume_init() };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
@@ -730,12 +746,10 @@
///
/// let mut five = Arc::<u32>::new_uninit();
///
- /// let five = unsafe {
- /// // Deferred initialization:
- /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+ /// // Deferred initialization:
+ /// Arc::get_mut(&mut five).unwrap().write(5);
///
- /// five.assume_init()
- /// };
+ /// let five = unsafe { five.assume_init() };
///
/// assert_eq!(*five, 5)
/// ```
@@ -770,14 +784,13 @@
///
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
///
- /// let values = unsafe {
- /// // Deferred initialization:
- /// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
- /// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
- /// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+ /// // Deferred initialization:
+ /// let data = Arc::get_mut(&mut values).unwrap();
+ /// data[0].write(1);
+ /// data[1].write(2);
+ /// data[2].write(3);
///
- /// values.assume_init()
- /// };
+ /// let values = unsafe { values.assume_init() };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
@@ -1464,6 +1477,41 @@
// either unique to begin with, or became one upon cloning the contents.
unsafe { Self::get_mut_unchecked(this) }
}
+
+ /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
+ /// clone.
+ ///
+ /// Assuming `arc_t` is of type `Arc<T>`, this function is functionally equivalent to
+ /// `(*arc_t).clone()`, but will avoid cloning the inner value where possible.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(arc_unwrap_or_clone)]
+ /// # use std::{ptr, sync::Arc};
+ /// let inner = String::from("test");
+ /// let ptr = inner.as_ptr();
+ ///
+ /// let arc = Arc::new(inner);
+ /// let inner = Arc::unwrap_or_clone(arc);
+ /// // The inner value was not cloned
+ /// assert!(ptr::eq(ptr, inner.as_ptr()));
+ ///
+ /// let arc = Arc::new(inner);
+ /// let arc2 = arc.clone();
+ /// let inner = Arc::unwrap_or_clone(arc);
+ /// // Because there were 2 references, we had to clone the inner value.
+ /// assert!(!ptr::eq(ptr, inner.as_ptr()));
+ /// // `arc2` is the last reference, so when we unwrap it we get back
+ /// // the original `String`.
+ /// let inner = Arc::unwrap_or_clone(arc2);
+ /// assert!(ptr::eq(ptr, inner.as_ptr()));
+ /// ```
+ #[inline]
+ #[unstable(feature = "arc_unwrap_or_clone", issue = "93610")]
+ pub fn unwrap_or_clone(this: Self) -> T {
+ Arc::try_unwrap(this).unwrap_or_else(|arc| (*arc).clone())
+ }
}
impl<T: ?Sized> Arc<T> {
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 18e191f..f985fb7 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -125,7 +125,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> Iterator for IntoIter<T, A> {
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 3ad48a1..c29aa0f 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1372,9 +1372,12 @@
///
/// Note: Because this shifts over the remaining elements, it has a
/// worst-case performance of *O*(*n*). If you don't need the order of elements
- /// to be preserved, use [`swap_remove`] instead.
+ /// to be preserved, use [`swap_remove`] instead. If you'd like to remove
+ /// elements from the beginning of the `Vec`, consider using
+ /// [`VecDeque::pop_front`] instead.
///
/// [`swap_remove`]: Vec::swap_remove
+ /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
///
/// # Panics
///
@@ -1735,6 +1738,11 @@
/// Removes the last element from a vector and returns it, or [`None`] if it
/// is empty.
///
+ /// If you'd like to pop the first element, consider using
+ /// [`VecDeque::pop_front`] instead.
+ ///
+ /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
+ ///
/// # Examples
///
/// ```
@@ -1791,19 +1799,24 @@
self.len += count;
}
- /// Creates a draining iterator that removes the specified range in the vector
- /// and yields the removed items.
+ /// Removes the specified range from the vector in bulk, returning all
+ /// removed elements as an iterator. If the iterator is dropped before
+ /// being fully consumed, it drops the remaining removed elements.
///
- /// When the iterator **is** dropped, all elements in the range are removed
- /// from the vector, even if the iterator was not fully consumed. If the
- /// iterator **is not** dropped (with [`mem::forget`] for example), it is
- /// unspecified how many elements are removed.
+ /// The returned iterator keeps a mutable borrow on the vector to optimize
+ /// its implementation.
///
/// # Panics
///
/// Panics if the starting point is greater than the end point or if
/// the end point is greater than the length of the vector.
///
+ /// # Leaking
+ ///
+ /// If the returned iterator goes out of scope without being dropped (due to
+ /// [`mem::forget`], for example), the vector may have lost and leaked
+ /// elements arbitrarily, including elements outside the range.
+ ///
/// # Examples
///
/// ```
@@ -1812,7 +1825,7 @@
/// assert_eq!(v, &[1]);
/// assert_eq!(u, &[2, 3]);
///
- /// // A full range clears the vector
+ /// // A full range clears the vector, like `clear()` does
/// v.drain(..);
/// assert_eq!(v, &[]);
/// ```
@@ -2043,8 +2056,6 @@
/// # Examples
///
/// ```
- /// #![feature(vec_spare_capacity)]
- ///
/// // Allocate vector big enough for 10 elements.
/// let mut v = Vec::with_capacity(10);
///
@@ -2061,7 +2072,7 @@
///
/// assert_eq!(&v, &[0, 1, 2]);
/// ```
- #[unstable(feature = "vec_spare_capacity", issue = "75017")]
+ #[stable(feature = "vec_spare_capacity", since = "1.60.0")]
#[inline]
pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
// Note:
@@ -2900,10 +2911,6 @@
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "vec_from_array", since = "1.44.0")]
impl<T, const N: usize> From<[T; N]> for Vec<T> {
- #[cfg(not(test))]
- fn from(s: [T; N]) -> Vec<T> {
- <[T]>::into_vec(box s)
- }
/// Allocate a `Vec<T>` and move `s`'s items into it.
///
/// # Examples
@@ -2911,6 +2918,11 @@
/// ```
/// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]);
/// ```
+ #[cfg(not(test))]
+ fn from(s: [T; N]) -> Vec<T> {
+ <[T]>::into_vec(box s)
+ }
+
#[cfg(test)]
fn from(s: [T; N]) -> Vec<T> {
crate::slice::into_vec(box s)
@@ -3004,14 +3016,12 @@
/// # Examples
///
/// ```
- /// use std::convert::TryInto;
/// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
/// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
/// ```
///
/// If the length doesn't match, the input comes back in `Err`:
/// ```
- /// use std::convert::TryInto;
/// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
/// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
/// ```
@@ -3019,7 +3029,6 @@
/// If you're fine with just getting a prefix of the `Vec<T>`,
/// you can call [`.truncate(N)`](Vec::truncate) first.
/// ```
- /// use std::convert::TryInto;
/// let mut v = String::from("hello world").into_bytes();
/// v.sort();
/// v.truncate(2);
diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs
index 948cf04..f915ebb 100644
--- a/library/alloc/src/vec/spec_from_iter_nested.rs
+++ b/library/alloc/src/vec/spec_from_iter_nested.rs
@@ -1,5 +1,8 @@
+use core::cmp;
use core::iter::TrustedLen;
-use core::ptr::{self};
+use core::ptr;
+
+use crate::raw_vec::RawVec;
use super::{SpecExtend, Vec};
@@ -24,8 +27,11 @@
None => return Vec::new(),
Some(element) => {
let (lower, _) = iterator.size_hint();
- let mut vector = Vec::with_capacity(lower.saturating_add(1));
+ let initial_capacity =
+ cmp::max(RawVec::<T>::MIN_NON_ZERO_CAP, lower.saturating_add(1));
+ let mut vector = Vec::with_capacity(initial_capacity);
unsafe {
+ // SAFETY: We requested capacity at least 1
ptr::write(vector.as_mut_ptr(), element);
vector.set_len(1);
}
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index 0d7acfe..9e5123b 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -160,7 +160,7 @@
*boxed = 42;
assert!(*boxed == 42);
- *boxed
+ *Box::leak(boxed)
};
assert!(VALUE == 42);
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index eec24a5..cbb8626 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -29,15 +29,16 @@
#![feature(binary_heap_as_slice)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
+#![feature(round_char_boundary)]
#![feature(slice_group_by)]
#![feature(slice_partition_dedup)]
-#![feature(vec_spare_capacity)]
#![feature(string_remove_matches)]
#![feature(const_btree_new)]
#![feature(const_default_impls)]
#![feature(const_trait_impl)]
#![feature(const_str_from_utf8)]
#![feature(nonnull_slice_from_raw_parts)]
+#![feature(panic_update_hook)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
diff --git a/library/alloc/tests/linked_list.rs b/library/alloc/tests/linked_list.rs
index afcb9e0..5f5bd9a 100644
--- a/library/alloc/tests/linked_list.rs
+++ b/library/alloc/tests/linked_list.rs
@@ -304,7 +304,7 @@
let list: LinkedList<_> = (0..10).collect();
assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
- let list: LinkedList<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
+ let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
}
@@ -336,7 +336,7 @@
assert_eq!(a.len(), 4);
assert!(a.iter().eq(&[1, 2, 3, 4]));
- let b: LinkedList<_> = vec![5, 6, 7].into_iter().collect();
+ let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
a.extend(b); // specializes to `append`
assert_eq!(a.len(), 7);
@@ -375,7 +375,7 @@
#[test]
fn drain_filter_zst() {
- let mut list: LinkedList<_> = vec![(), (), (), (), ()].into_iter().collect();
+ let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
let initial_len = list.len();
let mut count = 0;
@@ -398,7 +398,7 @@
#[test]
fn drain_filter_false() {
- let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ 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;
@@ -421,7 +421,7 @@
#[test]
fn drain_filter_true() {
- let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ 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;
@@ -447,7 +447,7 @@
fn drain_filter_complex() {
{
// [+xxx++++++xxxxx++++x+x++]
- let mut list = vec![
+ let mut list = [
1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
39,
]
@@ -467,11 +467,10 @@
{
// [xxx++++++xxxxx++++x+x++]
- let mut list = vec![
- 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39,
- ]
- .into_iter()
- .collect::<LinkedList<_>>();
+ let mut list =
+ [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
+ .into_iter()
+ .collect::<LinkedList<_>>();
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
assert_eq!(removed.len(), 10);
@@ -487,7 +486,7 @@
{
// [xxx++++++xxxxx++++x+x]
let mut list =
- vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
+ [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
.into_iter()
.collect::<LinkedList<_>>();
@@ -504,7 +503,7 @@
{
// [xxxxxxxxxx+++++++++++]
- let mut list = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+ let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
.into_iter()
.collect::<LinkedList<_>>();
@@ -518,7 +517,7 @@
{
// [+++++++++++xxxxxxxxxx]
- let mut list = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+ let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
.into_iter()
.collect::<LinkedList<_>>();
diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs
index 18ea6a2..b93d793 100644
--- a/library/alloc/tests/slice.rs
+++ b/library/alloc/tests/slice.rs
@@ -1783,12 +1783,11 @@
#[test]
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
fn panic_safe() {
- let prev = panic::take_hook();
- panic::set_hook(Box::new(move |info| {
+ panic::update_hook(move |prev, info| {
if !SILENCE_PANIC.with(|s| s.get()) {
prev(info);
}
- }));
+ });
let mut rng = thread_rng();
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index e92881b..6b8be25 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -2230,3 +2230,137 @@
assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
}
+
+#[test]
+fn utf8_char_counts() {
+ let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)];
+ let mut reps =
+ [8, 64, 256, 512, 1024].iter().copied().flat_map(|n| n - 8..=n + 8).collect::<Vec<usize>>();
+ if cfg!(not(miri)) {
+ let big = 1 << 16;
+ reps.extend(big - 8..=big + 8);
+ }
+ let counts = if cfg!(miri) { 0..1 } else { 0..8 };
+ let padding = counts.map(|len| " ".repeat(len)).collect::<Vec<String>>();
+
+ for repeat in reps {
+ for (tmpl_str, tmpl_char_count) in strs {
+ for pad_start in &padding {
+ for pad_end in &padding {
+ // Create a string with padding...
+ let with_padding =
+ format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end);
+ // ...and then skip past that padding. This should ensure
+ // that we test several different alignments for both head
+ // and tail.
+ let si = pad_start.len();
+ let ei = with_padding.len() - pad_end.len();
+ let target = &with_padding[si..ei];
+
+ assert!(!target.starts_with(" ") && !target.ends_with(" "));
+ let expected_count = tmpl_char_count * repeat;
+ assert_eq!(
+ expected_count,
+ target.chars().count(),
+ "wrong count for `{:?}.repeat({})` (padding: `{:?}`)",
+ tmpl_str,
+ repeat,
+ (pad_start.len(), pad_end.len()),
+ );
+ }
+ }
+ }
+ }
+}
+
+#[test]
+fn floor_char_boundary() {
+ fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+ for idx in arg {
+ assert_eq!(
+ s.floor_char_boundary(idx),
+ ret,
+ "{:?}.floor_char_boundary({:?}) != {:?}",
+ s,
+ idx,
+ ret
+ );
+ }
+ }
+
+ // edge case
+ check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0);
+
+ // basic check
+ check_many("x", [0], 0);
+ check_many("x", [1, isize::MAX as usize, usize::MAX], 1);
+
+ // 1-byte chars
+ check_many("jp", [0], 0);
+ check_many("jp", [1], 1);
+ check_many("jp", 2..4, 2);
+
+ // 2-byte chars
+ check_many("ĵƥ", 0..2, 0);
+ check_many("ĵƥ", 2..4, 2);
+ check_many("ĵƥ", 4..6, 4);
+
+ // 3-byte chars
+ check_many("日本", 0..3, 0);
+ check_many("日本", 3..6, 3);
+ check_many("日本", 6..8, 6);
+
+ // 4-byte chars
+ check_many("🇯🇵", 0..4, 0);
+ check_many("🇯🇵", 4..8, 4);
+ check_many("🇯🇵", 8..10, 8);
+}
+
+#[test]
+fn ceil_char_boundary() {
+ fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+ for idx in arg {
+ assert_eq!(
+ s.ceil_char_boundary(idx),
+ ret,
+ "{:?}.ceil_char_boundary({:?}) != {:?}",
+ s,
+ idx,
+ ret
+ );
+ }
+ }
+
+ // edge case
+ check_many("", [0], 0);
+
+ // basic check
+ check_many("x", [0], 0);
+ check_many("x", [1], 1);
+
+ // 1-byte chars
+ check_many("jp", [0], 0);
+ check_many("jp", [1], 1);
+ check_many("jp", [2], 2);
+
+ // 2-byte chars
+ check_many("ĵƥ", 0..=0, 0);
+ check_many("ĵƥ", 1..=2, 2);
+ check_many("ĵƥ", 3..=4, 4);
+
+ // 3-byte chars
+ check_many("日本", 0..=0, 0);
+ check_many("日本", 1..=3, 3);
+ check_many("日本", 4..=6, 6);
+
+ // 4-byte chars
+ check_many("🇯🇵", 0..=0, 0);
+ check_many("🇯🇵", 1..=4, 4);
+ check_many("🇯🇵", 5..=8, 8);
+}
+
+#[test]
+#[should_panic]
+fn ceil_char_boundary_above_len_panic() {
+ let _ = "x".ceil_char_boundary(2);
+}
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index 7be1371..893283e 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -489,7 +489,7 @@
b.extend(u.chars());
assert_eq!(s, b);
- let c: String = vec![t, u].into_iter().collect();
+ let c: String = [t, u].into_iter().collect();
assert_eq!(s, c);
let mut d = t.to_string();
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 7731428..705914b 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -449,10 +449,10 @@
#[test]
fn test_partition() {
- assert_eq!(vec![].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
- assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
- assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
- assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
+ assert_eq!([].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
}
#[test]
@@ -924,7 +924,7 @@
#[test]
fn test_into_iter_count() {
- assert_eq!(vec![1, 2, 3].into_iter().count(), 3);
+ assert_eq!([1, 2, 3].into_iter().count(), 3);
}
#[test]
@@ -933,7 +933,7 @@
let v: Vec<i32> = it.collect();
assert_eq!(&v[..], slice);
}
- let mut it = vec![1, 2, 3].into_iter();
+ let mut it = [1, 2, 3].into_iter();
iter_equal(it.clone(), &[1, 2, 3]);
assert_eq!(it.next(), Some(1));
let mut it = it.rev();
@@ -972,7 +972,7 @@
#[test]
fn test_into_iter_advance_by() {
- let mut i = vec![1, 2, 3, 4, 5].into_iter();
+ let mut i = [1, 2, 3, 4, 5].into_iter();
i.advance_by(0).unwrap();
i.advance_back_by(0).unwrap();
assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
@@ -1799,7 +1799,7 @@
assert_eq!(*v0, 13);
next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range
assert_eq!(*v0, 13);
- next_then_drop(v.splice(5..6, vec![1; 10].into_iter().filter(|_| true))); // lower bound not exact
+ next_then_drop(v.splice(5..6, [1; 10].into_iter().filter(|_| true))); // lower bound not exact
assert_eq!(*v0, 13);
// spare_capacity_mut
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index ddfb4c0..18954f0 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -927,8 +927,8 @@
#[test]
fn test_append() {
- let mut a: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
- let mut b: VecDeque<_> = vec![4, 5, 6].into_iter().collect();
+ let mut a: VecDeque<_> = [1, 2, 3].into_iter().collect();
+ let mut b: VecDeque<_> = [4, 5, 6].into_iter().collect();
// normal append
a.append(&mut b);
@@ -1209,7 +1209,7 @@
{
// Same basic idea, but with non-zero len
- let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!");
@@ -1240,7 +1240,7 @@
{
// Same basic idea, but with interesting type size
- let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_u32s: VecDeque<u32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
@@ -1322,7 +1322,7 @@
}
{
- let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
@@ -1355,7 +1355,7 @@
}
{
- let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_u32s: VecDeque<u32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml
index 6f10b9e..6a0c6cd 100644
--- a/library/core/Cargo.toml
+++ b/library/core/Cargo.toml
@@ -6,7 +6,9 @@
description = "The Rust Core Library"
autotests = false
autobenches = false
-edition = "2018"
+# If you update this, be sure to update it in a bunch of other places too!
+# As of 2022, it was the ci/pgo.sh script and the core-no-fp-fmt-parse test.
+edition = "2021"
[lib]
test = false
diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs
index 1527aa0..78865d8 100644
--- a/library/core/benches/str.rs
+++ b/library/core/benches/str.rs
@@ -1,33 +1,10 @@
use std::str;
use test::{black_box, Bencher};
-const LOREM_SHORT: &str = "Lorem ipsum";
-
-const LOREM: &str = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
-Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
-Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
-Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
-Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
-At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur";
-
-const EMOJI: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶🌫️😏😒🙄😬😮💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵💫🤯🤠🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊💋💌💘💝💖💗💓💞💕💟❣💔❤️🔥❤️🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💣💬👁️🗨️🗨🗯💭💤👋🤚🖐✋🖖👌🤌🤏✌🤞🤟🤘🤙👈👉👆🖕👇☝👍👎✊👊🤛🤜👏🙌👐🤲🤝🙏✍💅🤳💪🦾🦿🦵🦶👂🦻👃🧠🫀🫁🦷🦴👀👁👅👄👶🧒👦👧🧑👱👨🧔🧔♂️🧔♀️👨🦰👨🦱👨🦳👨🦲👩👩🦰🧑🦰👩🦱🧑🦱👩🦳🧑🦳👩🦲🧑🦲👱♀️👱♂️🧓👴👵🙍🙍♂️🙍♀️🙎🙎♂️🙎♀️🙅🙅♂️🙅♀️🙆🙆♂️🙆♀️💁💁♂️💁♀️🙋🙋♂️🙋♀️🧏🧏♂️🧏♀️🙇🙇♂️🙇♀️🤦🤦♂️🤦♀️🤷🤷♂️🤷♀️🧑⚕️👨⚕️👩⚕️🧑🎓👨🎓👩🎓🧑🏫👨🏫👩🏫🧑⚖️👨⚖️👩⚖️🧑🌾👨🌾👩🌾🧑🍳👨🍳👩🍳🧑🔧👨🔧👩🔧🧑🏭👨🏭👩🏭🧑💼👨💼👩💼🧑🔬👨🔬👩🔬🧑💻👨💻👩💻🧑🎤👨🎤👩🎤🧑🎨👨🎨👩🎨🧑✈️👨✈️👩✈️🧑🚀👨🚀👩🚀🧑🚒👨🚒👩🚒👮👮♂️👮♀️🕵🕵️♂️🕵️♀️💂💂♂️💂♀️🥷👷👷♂️👷♀️🤴👸👳👳♂️👳♀️👲🧕🤵🤵♂️🤵♀️👰👰♂️👰♀️🤰🤱👩🍼👨🍼🧑🍼👼🎅🤶🧑🎄🦸🦸♂️🦸♀️🦹🦹♂️🦹♀️🧙🧙♂️🧙♀️🧚🧚♂️🧚♀️🧛🧛♂️🧛♀️🧜🧜♂️🧜♀️🧝🧝♂️🧝♀️🧞🧞♂️🧞♀️🧟🧟♂️🧟♀️💆💆♂️💆♀️💇💇♂️💇♀️🚶🚶♂️🚶♀️🧍🧍♂️🧍♀️🧎🧎♂️🧎♀️🧑🦯👨🦯👩🦯🧑🦼👨🦼👩🦼🧑🦽👨🦽👩🦽🏃🏃♂️🏃♀️💃🕺🕴👯👯♂️👯♀️🧖🧖♂️🧖♀️🧗🧗♂️🧗♀️🤺🏇⛷🏂🏌🏌️♂️🏌️♀️🏄🏄♂️🏄♀️🚣🚣♂️🚣♀️🏊🏊♂️🏊♀️⛹⛹️♂️⛹️♀️🏋🏋️♂️🏋️♀️🚴🚴♂️🚴♀️🚵🚵♂️🚵♀️🤸🤸♂️🤸♀️🤼🤼♂️🤼♀️🤽🤽♂️🤽♀️🤾🤾♂️🤾♀️🤹🤹♂️🤹♀️🧘🧘♂️🧘♀️🛀🛌🧑🤝🧑👭👫👬💏👩❤️💋👨👨❤️💋👨👩❤️💋👩💑👩❤️👨👨❤️👨👩❤️👩👪👨👩👦👨👩👧👨👩👧👦👨👩👦👦👨👩👧👧👨👨👦👨👨👧👨👨👧👦👨👨👦👦👨👨👧👧👩👩👦👩👩👧👩👩👧👦👩👩👦👦👩👩👧👧👨👦👨👦👦👨👧👨👧👦👨👧👧👩👦👩👦👦👩👧👩👧👦👩👧👧🗣👤👥🫂👣🦰🦱🦳🦲🐵🐒🦍🦧🐶🐕🦮🐕🦺🐩🐺🦊🦝🐱🐈🐈⬛🦁🐯🐅🐆🐴🐎🦄🦓🦌🦬🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🦙🦒🐘🦣🦏🦛🐭🐁🐀🐹🐰🐇🐿🦫🦔🦇🐻🐻❄️🐨🐼🦥🦦🦨🦘🦡🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊🦅🦆🦢🦉🦤🪶🦩🦚🦜🐸🐊🐢🦎🐍🐲🐉🦕🦖🐳🐋🐬🦭🐟🐠🐡🦈🐙🐚🐌🦋🐛🐜🐝🪲🐞🦗🪳🕷🕸🦂🦟🪰🪱🦠💐🌸💮🏵🌹🥀🌺🌻🌼🌷🌱🪴🌲🌳🌴🌵🌾🌿☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🫐🥝🍅🫒🥥🥑🍆🥔🥕🌽🌶🫑🥒🥬🥦🧄🧅🍄🥜🌰🍞🥐🥖🫓🥨🥯🥞🧇🧀🍖🍗🥩🥓🍔🍟🍕🌭🥪🌮🌯🫔🥙🧆🥚🍳🥘🍲🫕🥣🥗🍿🧈🧂🥫🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🥮🍡🥟🥠🥡🦀🦞🦐🦑🦪🍦🍧🍨🍩🍪🎂🍰🧁🥧🍫🍬🍭🍮🍯🍼🥛☕🫖🍵🍶🍾🍷🍸🍹🍺🍻🥂🥃🥤🧋🧃🧉🧊🥢🍽🍴🥄🔪🏺🌍🌎🌏🌐🗺🗾🧭🏔⛰🌋🗻🏕🏖🏜🏝🏞🏟🏛🏗🧱🪨🪵🛖🏘🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🛕🕍⛩🕋⛲⛺🌁🌃🏙🌄🌅🌆🌇🌉♨🎠🎡🎢💈🎪🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🛻🚚🚛🚜🏎🏍🛵🦽🦼🛺🚲🛴🛹🛼🚏🛣🛤🛢⛽🚨🚥🚦🛑🚧⚓⛵🛶🚤🛳⛴🛥🚢✈🛩🛫🛬🪂💺🚁🚟🚠🚡🛰🚀🛸🛎🧳⌛⏳⌚⏰⏱⏲🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡☀🌝🌞🪐⭐🌟🌠🌌☁⛅⛈🌤🌥🌦🌧🌨🌩🌪🌫🌬🌀🌈🌂☂☔⛱⚡❄☃⛄☄🔥💧🌊🎃🎄🎆🎇🧨✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗🎟🎫🎖🏆🏅🥇🥈🥉⚽⚾🥎🏀🏐🏈🏉🎾🥏🎳🏏🏑🏒🥍🏓🏸🥊🥋🥅⛳⛸🎣🤿🎽🎿🛷🥌🎯🪀🪁🎱🔮🪄🧿🎮🕹🎰🎲🧩🧸🪅🪆♠♥♦♣♟🃏🀄🎴🎭🖼🎨🧵🪡🧶🪢👓🕶🥽🥼🦺👔👕👖🧣🧤🧥🧦👗👘🥻🩱🩲🩳👙👚👛👜👝🛍🎒🩴👞👟🥾🥿👠👡🩰👢👑👒🎩🎓🧢🪖⛑📿💄💍💎🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙🎚🎛🎤🎧📻🎷🪗🎸🎹🎺🎻🪕🥁";
-
-#[bench]
-fn str_char_count_lorem(b: &mut Bencher) {
- b.iter(|| black_box(LOREM).chars().count());
-}
-
-#[bench]
-fn str_char_count_lorem_short(b: &mut Bencher) {
- b.iter(|| black_box(LOREM_SHORT).chars().count());
-}
-
-#[bench]
-fn str_char_count_emoji(b: &mut Bencher) {
- b.iter(|| black_box(EMOJI).chars().count());
-}
+mod char_count;
+mod corpora;
#[bench]
fn str_validate_emoji(b: &mut Bencher) {
- b.iter(|| str::from_utf8(black_box(EMOJI.as_bytes())));
+ b.iter(|| str::from_utf8(black_box(corpora::emoji::LARGE.as_bytes())));
}
diff --git a/library/core/benches/str/char_count.rs b/library/core/benches/str/char_count.rs
new file mode 100644
index 0000000..25d9b2e
--- /dev/null
+++ b/library/core/benches/str/char_count.rs
@@ -0,0 +1,107 @@
+use super::corpora::*;
+use test::{black_box, Bencher};
+
+macro_rules! define_benches {
+ ($( fn $name: ident($arg: ident: &str) $body: block )+) => {
+ define_benches!(mod en_tiny, en::TINY, $($name $arg $body)+);
+ define_benches!(mod en_small, en::SMALL, $($name $arg $body)+);
+ define_benches!(mod en_medium, en::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod en_large, en::LARGE, $($name $arg $body)+);
+ define_benches!(mod en_huge, en::HUGE, $($name $arg $body)+);
+
+ define_benches!(mod zh_tiny, zh::TINY, $($name $arg $body)+);
+ define_benches!(mod zh_small, zh::SMALL, $($name $arg $body)+);
+ define_benches!(mod zh_medium, zh::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod zh_large, zh::LARGE, $($name $arg $body)+);
+ define_benches!(mod zh_huge, zh::HUGE, $($name $arg $body)+);
+
+ define_benches!(mod ru_tiny, ru::TINY, $($name $arg $body)+);
+ define_benches!(mod ru_small, ru::SMALL, $($name $arg $body)+);
+ define_benches!(mod ru_medium, ru::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod ru_large, ru::LARGE, $($name $arg $body)+);
+ define_benches!(mod ru_huge, ru::HUGE, $($name $arg $body)+);
+
+ define_benches!(mod emoji_tiny, emoji::TINY, $($name $arg $body)+);
+ define_benches!(mod emoji_small, emoji::SMALL, $($name $arg $body)+);
+ define_benches!(mod emoji_medium, emoji::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod emoji_large, emoji::LARGE, $($name $arg $body)+);
+ define_benches!(mod emoji_huge, emoji::HUGE, $($name $arg $body)+);
+ };
+ (mod $mod_name: ident, $input: expr, $($name: ident $arg: ident $body: block)+) => {
+ mod $mod_name {
+ use super::*;
+ $(
+ #[bench]
+ fn $name(bencher: &mut Bencher) {
+ let input = $input;
+ bencher.bytes = input.len() as u64;
+ let mut input_s = input.to_string();
+ bencher.iter(|| {
+ let $arg: &str = &black_box(&mut input_s);
+ black_box($body)
+ })
+ }
+ )+
+ }
+ };
+}
+
+define_benches! {
+ fn case00_libcore(s: &str) {
+ libcore(s)
+ }
+
+ fn case01_filter_count_cont_bytes(s: &str) {
+ filter_count_cont_bytes(s)
+ }
+
+ fn case02_iter_increment(s: &str) {
+ iterator_increment(s)
+ }
+
+ fn case03_manual_char_len(s: &str) {
+ manual_char_len(s)
+ }
+}
+
+fn libcore(s: &str) -> usize {
+ s.chars().count()
+}
+
+#[inline]
+fn utf8_is_cont_byte(byte: u8) -> bool {
+ (byte as i8) < -64
+}
+
+fn filter_count_cont_bytes(s: &str) -> usize {
+ s.as_bytes().iter().filter(|&&byte| !utf8_is_cont_byte(byte)).count()
+}
+
+fn iterator_increment(s: &str) -> usize {
+ let mut c = 0;
+ for _ in s.chars() {
+ c += 1;
+ }
+ c
+}
+
+fn manual_char_len(s: &str) -> usize {
+ let s = s.as_bytes();
+ let mut c = 0;
+ let mut i = 0;
+ let l = s.len();
+ while i < l {
+ let b = s[i];
+ if b < 0x80 {
+ i += 1;
+ } else if b < 0xe0 {
+ i += 2;
+ } else if b < 0xf0 {
+ i += 3;
+ } else {
+ i += 4;
+ }
+ c += 1;
+ }
+ c
+}
diff --git a/library/core/benches/str/corpora.rs b/library/core/benches/str/corpora.rs
new file mode 100644
index 0000000..b4ac625
--- /dev/null
+++ b/library/core/benches/str/corpora.rs
@@ -0,0 +1,88 @@
+//! Exposes a number of modules with different kinds of strings.
+//!
+//! Each module contains `&str` constants named `TINY`, `SMALL`, `MEDIUM`,
+//! `LARGE`, and `HUGE`.
+//!
+//! - The `TINY` string is generally around 8 bytes.
+//! - The `SMALL` string is generally around 30-40 bytes.
+//! - The `MEDIUM` string is generally around 600-700 bytes.
+//! - The `LARGE` string is the `MEDIUM` string repeated 8x, and is around 5kb.
+//! - The `HUGE` string is the `LARGE` string repeated 8x (or the `MEDIUM`
+//! string repeated 64x), and is around 40kb.
+//!
+//! Except for `mod emoji` (which is just a bunch of emoji), the strings were
+//! pulled from (localizations of) rust-lang.org.
+
+macro_rules! repeat8 {
+ ($s:expr) => {
+ concat!($s, $s, $s, $s, $s, $s, $s, $s)
+ };
+}
+
+macro_rules! define_consts {
+ ($s:literal) => {
+ pub const MEDIUM: &str = $s;
+ pub const LARGE: &str = repeat8!($s);
+ pub const HUGE: &str = repeat8!(repeat8!(repeat8!($s)));
+ };
+}
+
+pub mod en {
+ pub const TINY: &str = "Mary had";
+ pub const SMALL: &str = "Mary had a little lamb, Little lamb";
+ define_consts! {
+ "Rust is blazingly fast and memory-efficient: with no runtime or garbage
+ collector, it can power performance-critical services, run on embedded
+ devices, and easily integrate with other languages. Rust’s rich type system
+ and ownership model guarantee memory-safety and thread-safety — enabling you
+ to eliminate many classes of bugs at compile-time. Rust has great
+ documentation, a friendly compiler with useful error messages, and top-notch
+ tooling — an integrated package manager and build tool, smart multi-editor
+ support with auto-completion and type inspections, an auto-formatter, and
+ more."
+ }
+}
+
+pub mod zh {
+ pub const TINY: &str = "速度惊";
+ pub const SMALL: &str = "速度惊人且内存利用率极高";
+ define_consts! {
+ "Rust 速度惊人且内存利用率极高。由于\
+ 没有运行时和垃圾回收,它能够胜任对性能要\
+ 求特别高的服务,可以在嵌入式设备上运行,\
+ 还能轻松和其他语言集成。Rust 丰富的类型\
+ 系统和所有权模型保证了内存安全和线程安全,\
+ 让您在编译期就能够消除各种各样的错误。\
+ Rust 拥有出色的文档、友好的编译器和清晰\
+ 的错误提示信息, 还集成了一流的工具——\
+ 包管理器和构建工具, 智能地自动补全和类\
+ 型检验的多编辑器支持, 以及自动格式化代\
+ 码等等。"
+ }
+}
+
+pub mod ru {
+ pub const TINY: &str = "Сотни";
+ pub const SMALL: &str = "Сотни компаний по";
+ define_consts! {
+ "Сотни компаний по всему миру используют Rust в реальных\
+ проектах для быстрых кросс-платформенных решений с\
+ ограниченными ресурсами. Такие проекты, как Firefox,\
+ Dropbox и Cloudflare, используют Rust. Rust отлично\
+ подходит как для стартапов, так и для больших компаний,\
+ как для встраиваемых устройств, так и для масштабируемых\
+ web-сервисов. Мой самый большой комплимент Rust."
+ }
+}
+
+pub mod emoji {
+ pub const TINY: &str = "😀😃";
+ pub const SMALL: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘";
+ define_consts! {
+ "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶🌫️😏😒\
+ 🙄😬😮💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵💫🤯��🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨\
+ 😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊\
+ 💋💌💘💝💖💗💓��💕💟❣💔❤️🔥❤️🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💬👁️🗨️🗨🗯💭💤👋\
+ 🤚🖐✋🖖👌🤌🤏✌"
+ }
+}
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 37292bf..ee79021 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -66,8 +66,6 @@
///
/// ```rust
/// #![feature(array_from_fn)]
-/// # // Apparently these doc tests are still on edition2018
-/// # use std::convert::TryInto;
///
/// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
@@ -514,6 +512,7 @@
/// 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")]
pub const fn as_slice(&self) -> &[T] {
self
}
diff --git a/library/core/src/stream/stream.rs b/library/core/src/async_iter/async_iter.rs
similarity index 60%
rename from library/core/src/stream/stream.rs
rename to library/core/src/async_iter/async_iter.rs
index 2cfddf9..f29de31 100644
--- a/library/core/src/stream/stream.rs
+++ b/library/core/src/async_iter/async_iter.rs
@@ -4,50 +4,50 @@
/// An interface for dealing with asynchronous iterators.
///
-/// This is the main stream trait. For more about the concept of streams
+/// This is the main async iterator trait. For more about the concept of async iterators
/// generally, please see the [module-level documentation]. In particular, you
-/// may want to know how to [implement `Stream`][impl].
+/// may want to know how to [implement `AsyncIterator`][impl].
///
/// [module-level documentation]: index.html
-/// [impl]: index.html#implementing-stream
-#[unstable(feature = "async_stream", issue = "79024")]
-#[must_use = "streams do nothing unless polled"]
-pub trait Stream {
- /// The type of items yielded by the stream.
+/// [impl]: index.html#implementing-async-iterator
+#[unstable(feature = "async_iterator", issue = "79024")]
+#[must_use = "async iterators do nothing unless polled"]
+pub trait AsyncIterator {
+ /// The type of items yielded by the async iterator.
type Item;
- /// Attempt to pull out the next value of this stream, registering the
+ /// Attempt to pull out the next value of this async iterator, registering the
/// current task for wakeup if the value is not yet available, and returning
- /// `None` if the stream is exhausted.
+ /// `None` if the async iterator is exhausted.
///
/// # Return value
///
/// There are several possible return values, each indicating a distinct
- /// stream state:
+ /// async iterator state:
///
- /// - `Poll::Pending` means that this stream's next value is not ready
+ /// - `Poll::Pending` means that this async iterator's next value is not ready
/// yet. Implementations will ensure that the current task will be notified
/// when the next value may be ready.
///
- /// - `Poll::Ready(Some(val))` means that the stream has successfully
+ /// - `Poll::Ready(Some(val))` means that the async iterator has successfully
/// produced a value, `val`, and may produce further values on subsequent
/// `poll_next` calls.
///
- /// - `Poll::Ready(None)` means that the stream has terminated, and
+ /// - `Poll::Ready(None)` means that the async iterator has terminated, and
/// `poll_next` should not be invoked again.
///
/// # Panics
///
- /// Once a stream has finished (returned `Ready(None)` from `poll_next`), calling its
+ /// Once an async iterator has finished (returned `Ready(None)` from `poll_next`), calling its
/// `poll_next` method again may panic, block forever, or cause other kinds of
- /// problems; the `Stream` trait places no requirements on the effects of
+ /// problems; the `AsyncIterator` trait places no requirements on the effects of
/// such a call. However, as the `poll_next` method is not marked `unsafe`,
/// Rust's usual rules apply: calls must never cause undefined behavior
/// (memory corruption, incorrect use of `unsafe` functions, or the like),
- /// regardless of the stream's state.
+ /// regardless of the async iterator's state.
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
- /// Returns the bounds on the remaining length of the stream.
+ /// Returns the bounds on the remaining length of the async iterator.
///
/// Specifically, `size_hint()` returns a tuple where the first element
/// is the lower bound, and the second element is the upper bound.
@@ -58,12 +58,12 @@
///
/// # Implementation notes
///
- /// It is not enforced that a stream implementation yields the declared
- /// number of elements. A buggy stream may yield less than the lower bound
+ /// It is not enforced that an async iterator implementation yields the declared
+ /// number of elements. A buggy async iterator may yield less than the lower bound
/// or more than the upper bound of elements.
///
/// `size_hint()` is primarily intended to be used for optimizations such as
- /// reserving space for the elements of the stream, but must not be
+ /// reserving space for the elements of the async iterator, but must not be
/// trusted to e.g., omit bounds checks in unsafe code. An incorrect
/// implementation of `size_hint()` should not lead to memory safety
/// violations.
@@ -72,15 +72,15 @@
/// because otherwise it would be a violation of the trait's protocol.
///
/// The default implementation returns <code>(0, [None])</code> which is correct for any
- /// stream.
+ /// async iterator.
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}
}
-#[unstable(feature = "async_stream", issue = "79024")]
-impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
+#[unstable(feature = "async_iterator", issue = "79024")]
+impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for &mut S {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
@@ -92,16 +92,16 @@
}
}
-#[unstable(feature = "async_stream", issue = "79024")]
-impl<P> Stream for Pin<P>
+#[unstable(feature = "async_iterator", issue = "79024")]
+impl<P> AsyncIterator for Pin<P>
where
P: DerefMut,
- P::Target: Stream,
+ P::Target: AsyncIterator,
{
- type Item = <P::Target as Stream>::Item;
+ type Item = <P::Target as AsyncIterator>::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
- <P::Target as Stream>::poll_next(self.as_deref_mut(), cx)
+ <P::Target as AsyncIterator>::poll_next(self.as_deref_mut(), cx)
}
fn size_hint(&self) -> (usize, Option<usize>) {
diff --git a/library/core/src/async_iter/from_iter.rs b/library/core/src/async_iter/from_iter.rs
new file mode 100644
index 0000000..3180187
--- /dev/null
+++ b/library/core/src/async_iter/from_iter.rs
@@ -0,0 +1,38 @@
+use crate::pin::Pin;
+
+use crate::async_iter::AsyncIterator;
+use crate::task::{Context, Poll};
+
+/// An async iterator that was created from iterator.
+///
+/// This async iterator is created by the [`from_iter`] function.
+/// See it documentation for more.
+///
+/// [`from_iter`]: fn.from_iter.html
+#[unstable(feature = "async_iter_from_iter", issue = "81798")]
+#[derive(Clone, Debug)]
+pub struct FromIter<I> {
+ iter: I,
+}
+
+#[unstable(feature = "async_iter_from_iter", issue = "81798")]
+impl<I> Unpin for FromIter<I> {}
+
+/// Converts an iterator into an async iterator.
+#[unstable(feature = "async_iter_from_iter", issue = "81798")]
+pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> {
+ FromIter { iter: iter.into_iter() }
+}
+
+#[unstable(feature = "async_iter_from_iter", issue = "81798")]
+impl<I: Iterator> AsyncIterator for FromIter<I> {
+ type Item = I::Item;
+
+ fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+ Poll::Ready(self.iter.next())
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
diff --git a/library/core/src/async_iter/mod.rs b/library/core/src/async_iter/mod.rs
new file mode 100644
index 0000000..0c6f637
--- /dev/null
+++ b/library/core/src/async_iter/mod.rs
@@ -0,0 +1,128 @@
+//! Composable asynchronous iteration.
+//!
+//! If you've found yourself with an asynchronous collection of some kind,
+//! and needed to perform an operation on the elements of said collection,
+//! you'll quickly run into 'async iterators'. Async Iterators are heavily used in
+//! idiomatic asynchronous Rust code, so it's worth becoming familiar with them.
+//!
+//! Before explaining more, let's talk about how this module is structured:
+//!
+//! # Organization
+//!
+//! This module is largely organized by type:
+//!
+//! * [Traits] are the core portion: these traits define what kind of async iterators
+//! exist and what you can do with them. The methods of these traits are worth
+//! putting some extra study time into.
+//! * Functions provide some helpful ways to create some basic async iterators.
+//! * Structs are often the return types of the various methods on this
+//! module's traits. You'll usually want to look at the method that creates
+//! the `struct`, rather than the `struct` itself. For more detail about why,
+//! see '[Implementing Async Iterator](#implementing-async-iterator)'.
+//!
+//! [Traits]: #traits
+//!
+//! That's it! Let's dig into async iterators.
+//!
+//! # Async Iterators
+//!
+//! The heart and soul of this module is the [`AsyncIterator`] trait. The core of
+//! [`AsyncIterator`] looks like this:
+//!
+//! ```
+//! # use core::task::{Context, Poll};
+//! # use core::pin::Pin;
+//! trait AsyncIterator {
+//! type Item;
+//! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
+//! }
+//! ```
+//!
+//! Unlike `Iterator`, `AsyncIterator` makes a distinction between the [`poll_next`]
+//! method which is used when implementing an `AsyncIterator`, and a (to-be-implemented)
+//! `next` method which is used when consuming an async iterator. Consumers of `AsyncIterator`
+//! only need to consider `next`, which when called, returns a future which
+//! yields `Option<AsyncIterator::Item>`.
+//!
+//! The future returned by `next` will yield `Some(Item)` as long as there are
+//! elements, and once they've all been exhausted, will yield `None` to indicate
+//! that iteration is finished. If we're waiting on something asynchronous to
+//! resolve, the future will wait until the async iterator is ready to yield again.
+//!
+//! Individual async iterators may choose to resume iteration, and so calling `next`
+//! again may or may not eventually yield `Some(Item)` again at some point.
+//!
+//! [`AsyncIterator`]'s full definition includes a number of other methods as well,
+//! but they are default methods, built on top of [`poll_next`], and so you get
+//! them for free.
+//!
+//! [`Poll`]: super::task::Poll
+//! [`poll_next`]: AsyncIterator::poll_next
+//!
+//! # Implementing Async Iterator
+//!
+//! Creating an async iterator of your own involves two steps: creating a `struct` to
+//! hold the async iterator's state, and then implementing [`AsyncIterator`] for that
+//! `struct`.
+//!
+//! Let's make an async iterator named `Counter` which counts from `1` to `5`:
+//!
+//! ```no_run
+//! #![feature(async_iterator)]
+//! # use core::async_iter::AsyncIterator;
+//! # use core::task::{Context, Poll};
+//! # use core::pin::Pin;
+//!
+//! // First, the struct:
+//!
+//! /// An async iterator which counts from one to five
+//! struct Counter {
+//! count: usize,
+//! }
+//!
+//! // we want our count to start at one, so let's add a new() method to help.
+//! // This isn't strictly necessary, but is convenient. Note that we start
+//! // `count` at zero, we'll see why in `poll_next()`'s implementation below.
+//! impl Counter {
+//! fn new() -> Counter {
+//! Counter { count: 0 }
+//! }
+//! }
+//!
+//! // Then, we implement `AsyncIterator` for our `Counter`:
+//!
+//! impl AsyncIterator for Counter {
+//! // we will be counting with usize
+//! type Item = usize;
+//!
+//! // poll_next() is the only required method
+//! fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+//! // Increment our count. This is why we started at zero.
+//! self.count += 1;
+//!
+//! // Check to see if we've finished counting or not.
+//! if self.count < 6 {
+//! Poll::Ready(Some(self.count))
+//! } else {
+//! Poll::Ready(None)
+//! }
+//! }
+//! }
+//! ```
+//!
+//! # Laziness
+//!
+//! Async iterators are *lazy*. This means that just creating an async iterator doesn't
+//! _do_ a whole lot. Nothing really happens until you call `poll_next`. This is
+//! sometimes a source of confusion when creating an async iterator solely for its side
+//! effects. The compiler will warn us about this kind of behavior:
+//!
+//! ```text
+//! warning: unused result that must be used: async iterators do nothing unless polled
+//! ```
+
+mod async_iter;
+mod from_iter;
+
+pub use async_iter::AsyncIterator;
+pub use from_iter::{from_iter, FromIter};
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index bc3f716..aef7ad7 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -315,6 +315,7 @@
#[stable(feature = "cell_from", since = "1.12.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for Cell<T> {
+ /// Creates a new `Cell<T>` containing the given value.
fn from(t: T) -> Cell<T> {
Cell::new(t)
}
@@ -1244,6 +1245,7 @@
#[stable(feature = "cell_from", since = "1.12.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for RefCell<T> {
+ /// Creates a new `RefCell<T>` containing the given value.
fn from(t: T) -> RefCell<T> {
RefCell::new(t)
}
@@ -1310,11 +1312,7 @@
///
/// See the [module-level documentation](self) for more.
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(
- not(bootstrap),
- must_not_suspend = "holding a Ref across suspend \
- points can cause BorrowErrors"
-)]
+#[must_not_suspend = "holding a Ref across suspend points can cause BorrowErrors"]
pub struct Ref<'b, T: ?Sized + 'b> {
value: &'b T,
borrow: BorrowRef<'b>,
@@ -1692,11 +1690,7 @@
///
/// See the [module-level documentation](self) for more.
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(
- not(bootstrap),
- must_not_suspend = "holding a RefMut across suspend \
- points can cause BorrowErrors"
-)]
+#[must_not_suspend = "holding a RefMut across suspend points can cause BorrowErrors"]
pub struct RefMut<'b, T: ?Sized + 'b> {
value: &'b mut T,
borrow: BorrowRefMut<'b>,
@@ -1967,6 +1961,7 @@
/// ```
#[inline(always)]
#[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
+ #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
pub const fn raw_get(this: *const Self) -> *mut T {
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
// #[repr(transparent)]. This exploits libstd's special status, there is
@@ -1986,6 +1981,7 @@
#[stable(feature = "cell_from", since = "1.12.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for UnsafeCell<T> {
+ /// Creates a new `UnsafeCell<T>` containing the given value.
fn from(t: T) -> UnsafeCell<T> {
UnsafeCell::new(t)
}
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs
index 5dd8c5e..8b9f979 100644
--- a/library/core/src/char/decode.rs
+++ b/library/core/src/char/decode.rs
@@ -120,9 +120,34 @@
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (low, high) = self.iter.size_hint();
- // we could be entirely valid surrogates (2 elements per
- // char), or entirely non-surrogates (1 element per char)
- (low / 2, high)
+
+ let (low_buf, high_buf) = match self.buf {
+ // buf is empty, no additional elements from it.
+ None => (0, 0),
+ // `u` is a non surrogate, so it's always an additional character.
+ Some(u) if u < 0xD800 || 0xDFFF < u => (1, 1),
+ // `u` is a leading surrogate (it can never be a trailing surrogate and
+ // it's a surrogate due to the previous branch) and `self.iter` is empty.
+ //
+ // `u` can't be paired, since the `self.iter` is empty,
+ // so it will always become an additional element (error).
+ Some(_u) if high == Some(0) => (1, 1),
+ // `u` is a leading surrogate and `iter` may be non-empty.
+ //
+ // `u` can either pair with a trailing surrogate, in which case no additional elements
+ // are produced, or it can become an error, in which case it's an additional character (error).
+ Some(_u) => (0, 1),
+ };
+
+ // `self.iter` could contain entirely valid surrogates (2 elements per
+ // char), or entirely non-surrogates (1 element per char).
+ //
+ // On odd lower bound, at least one element must stay unpaired
+ // (with other elements from `self.iter`), so we round up.
+ let low = low.div_ceil(2) + low_buf;
+ let high = high.and_then(|h| h.checked_add(high_buf));
+
+ (low, high)
}
}
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 7250dca..c4c0a5a 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -9,14 +9,19 @@
#[lang = "char"]
impl char {
- /// The highest valid code point a `char` can have.
+ /// The highest valid code point a `char` can have, `'\u{10FFFF}'`.
///
- /// A `char` is a [Unicode Scalar Value], which means that it is a [Code
- /// Point], but only ones within a certain range. `MAX` is the highest valid
- /// code point that's a valid [Unicode Scalar Value].
+ /// # Examples
///
- /// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value
- /// [Code Point]: https://www.unicode.org/glossary/#code_point
+ /// ```
+ /// # fn something_which_returns_char() -> char { 'a' }
+ /// let c: char = something_which_returns_char();
+ /// assert!(c <= char::MAX);
+ ///
+ /// let value_at_max = char::MAX as u32;
+ /// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}'));
+ /// assert_eq!(char::from_u32(value_at_max + 1), None);
+ /// ```
#[stable(feature = "assoc_char_consts", since = "1.52.0")]
pub const MAX: char = '\u{10ffff}';
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index f65f84e..9364ac4 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -89,14 +89,19 @@
Cn Unassigned a reserved unassigned code point or a noncharacter
*/
-/// The highest valid code point a `char` can have.
+/// The highest valid code point a `char` can have, `'\u{10FFFF}'`.
///
-/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code
-/// Point], but only ones within a certain range. `MAX` is the highest valid
-/// code point that's a valid [Unicode Scalar Value].
+/// # Examples
///
-/// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value
-/// [Code Point]: https://www.unicode.org/glossary/#code_point
+/// ```
+/// # fn something_which_returns_char() -> char { 'a' }
+/// let c: char = something_which_returns_char();
+/// assert!(c <= char::MAX);
+///
+/// let value_at_max = char::MAX as u32;
+/// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}'));
+/// assert_eq!(char::from_u32(value_at_max + 1), None);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub const MAX: char = char::MAX;
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index deed990..a3e7747 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -199,9 +199,20 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "==")]
#[doc(alias = "!=")]
-#[rustc_on_unimplemented(
- message = "can't compare `{Self}` with `{Rhs}`",
- label = "no implementation for `{Self} == {Rhs}`"
+#[cfg_attr(
+ bootstrap,
+ rustc_on_unimplemented(
+ message = "can't compare `{Self}` with `{Rhs}`",
+ label = "no implementation for `{Self} == {Rhs}`"
+ )
+)]
+#[cfg_attr(
+ not(bootstrap),
+ rustc_on_unimplemented(
+ message = "can't compare `{Self}` with `{Rhs}`",
+ label = "no implementation for `{Self} == {Rhs}`",
+ append_const_msg,
+ )
)]
#[rustc_diagnostic_item = "PartialEq"]
pub trait PartialEq<Rhs: ?Sized = Self> {
@@ -661,20 +672,37 @@
///
/// ## Derivable
///
-/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a
-/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the top-to-bottom declaration order of the struct's members.
-/// When `derive`d on enums, variants are ordered by their top-to-bottom discriminant order.
-/// This means variants at the top are less than variants at the bottom.
-/// Here's an example:
+/// This trait can be used with `#[derive]`.
+///
+/// When `derive`d on structs, it will produce a
+/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
+/// based on the top-to-bottom declaration order of the struct's members.
+///
+/// When `derive`d on enums, variants are ordered by their discriminants.
+/// By default, the discriminant is smallest for variants at the top, and
+/// largest for variants at the bottom. Here's an example:
///
/// ```
-/// #[derive(PartialEq, PartialOrd)]
-/// enum Size {
-/// Small,
-/// Large,
+/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
+/// enum E {
+/// Top,
+/// Bottom,
/// }
///
-/// assert!(Size::Small < Size::Large);
+/// assert!(E::Top < E::Bottom);
+/// ```
+///
+/// However, manually setting the discriminants can override this default
+/// behavior:
+///
+/// ```
+/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
+/// enum E {
+/// Top = 2,
+/// Bottom = 1,
+/// }
+///
+/// assert!(E::Bottom < E::Top);
/// ```
///
/// ## Lexicographical comparison
@@ -852,7 +880,7 @@
}
}
-/// Trait for values that can be compared for a sort-order.
+/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
///
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
/// the `<`, `<=`, `>`, and `>=` operators, respectively.
@@ -895,9 +923,38 @@
///
/// ## Derivable
///
-/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a
-/// lexicographic ordering based on the top-to-bottom declaration order of the struct's members.
-/// When `derive`d on enums, variants are ordered by their top-to-bottom discriminant order.
+/// This trait can be used with `#[derive]`.
+///
+/// When `derive`d on structs, it will produce a
+/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
+/// based on the top-to-bottom declaration order of the struct's members.
+///
+/// When `derive`d on enums, variants are ordered by their discriminants.
+/// By default, the discriminant is smallest for variants at the top, and
+/// largest for variants at the bottom. Here's an example:
+///
+/// ```
+/// #[derive(PartialEq, PartialOrd)]
+/// enum E {
+/// Top,
+/// Bottom,
+/// }
+///
+/// assert!(E::Top < E::Bottom);
+/// ```
+///
+/// However, manually setting the discriminants can override this default
+/// behavior:
+///
+/// ```
+/// #[derive(PartialEq, PartialOrd)]
+/// enum E {
+/// Top = 2,
+/// Bottom = 1,
+/// }
+///
+/// assert!(E::Bottom < E::Top);
+/// ```
///
/// ## How can I implement `PartialOrd`?
///
@@ -970,8 +1027,8 @@
/// # Examples
///
/// ```
-/// let x : u32 = 0;
-/// let y : u32 = 1;
+/// let x: u32 = 0;
+/// let y: u32 = 1;
///
/// assert_eq!(x < y, true);
/// assert_eq!(x.lt(&y), true);
@@ -985,9 +1042,20 @@
#[doc(alias = "<")]
#[doc(alias = "<=")]
#[doc(alias = ">=")]
-#[rustc_on_unimplemented(
- message = "can't compare `{Self}` with `{Rhs}`",
- label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`"
+#[cfg_attr(
+ bootstrap,
+ rustc_on_unimplemented(
+ message = "can't compare `{Self}` with `{Rhs}`",
+ label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+ )
+)]
+#[cfg_attr(
+ not(bootstrap),
+ rustc_on_unimplemented(
+ message = "can't compare `{Self}` with `{Rhs}`",
+ label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+ append_const_msg,
+ )
)]
#[rustc_diagnostic_item = "PartialOrd"]
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 1c2e673..0ceedf9 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -91,7 +91,7 @@
/// ```rust
/// use std::convert::identity;
///
-/// let iter = vec![Some(1), None, Some(3)].into_iter();
+/// let iter = [Some(1), None, Some(3)].into_iter();
/// let filtered = iter.filter_map(identity).collect::<Vec<_>>();
/// assert_eq!(vec![1, 3], filtered);
/// ```
@@ -426,8 +426,6 @@
/// `TryFrom<T>` can be implemented as follows:
///
/// ```
-/// use std::convert::TryFrom;
-///
/// struct GreaterThanZero(i32);
///
/// impl TryFrom<i32> for GreaterThanZero {
@@ -448,8 +446,6 @@
/// As described, [`i32`] implements `TryFrom<`[`i64`]`>`:
///
/// ```
-/// use std::convert::TryFrom;
-///
/// let big_number = 1_000_000_000_000i64;
/// // Silently truncates `big_number`, requires detecting
/// // and handling the truncation after the fact.
@@ -485,9 +481,10 @@
// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized, U: ?Sized> const AsRef<U> for &T
where
- T: AsRef<U>,
+ T: ~const AsRef<U>,
{
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
@@ -496,9 +493,10 @@
// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &mut T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized, U: ?Sized> const AsRef<U> for &mut T
where
- T: AsRef<U>,
+ T: ~const AsRef<U>,
{
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
@@ -515,9 +513,10 @@
// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsMut<U> for &mut T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized, U: ?Sized> const AsMut<U> for &mut T
where
- T: AsMut<U>,
+ T: ~const AsMut<U>,
{
fn as_mut(&mut self) -> &mut U {
(*self).as_mut()
@@ -539,6 +538,10 @@
where
U: ~const From<T>,
{
+ /// Calls `U::from(self)`.
+ ///
+ /// That is, this conversion is whatever the implementation of
+ /// <code>[From]<T> for U</code> chooses to do.
fn into(self) -> U {
U::from(self)
}
@@ -548,6 +551,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for T {
+ /// Returns the argument unchanged.
fn from(t: T) -> T {
t
}
@@ -571,9 +575,10 @@
// TryFrom implies TryInto
#[stable(feature = "try_from", since = "1.34.0")]
-impl<T, U> TryInto<U> for T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, U> const TryInto<U> for T
where
- U: TryFrom<T>,
+ U: ~const TryFrom<T>,
{
type Error = U::Error;
@@ -585,9 +590,10 @@
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
#[stable(feature = "try_from", since = "1.34.0")]
-impl<T, U> TryFrom<U> for T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, U> const TryFrom<U> for T
where
- U: Into<T>,
+ U: ~const Into<T>,
{
type Error = Infallible;
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 8a2a64f..e1ea988 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -308,9 +308,21 @@
loop {}
};
+macro_rules! arg_new {
+ ($f: ident, $t: ident) => {
+ #[doc(hidden)]
+ #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+ #[inline]
+ pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> {
+ Self::new(x, $t::fmt)
+ }
+ };
+}
+
impl<'a> ArgumentV1<'a> {
#[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+ #[inline]
pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
// SAFETY: `mem::transmute(x)` is safe because
// 1. `&'b T` keeps the lifetime it originated with `'b`
@@ -323,6 +335,16 @@
unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } }
}
+ arg_new!(new_display, Display);
+ arg_new!(new_debug, Debug);
+ arg_new!(new_octal, Octal);
+ arg_new!(new_lower_hex, LowerHex);
+ arg_new!(new_upper_hex, UpperHex);
+ arg_new!(new_pointer, Pointer);
+ arg_new!(new_binary, Binary);
+ arg_new!(new_lower_exp, LowerExp);
+ arg_new!(new_upper_exp, UpperExp);
+
#[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index cac1866..0912f86 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -13,7 +13,7 @@
/// Creates a future from a value.
#[unstable(feature = "into_future", issue = "67644")]
- #[cfg_attr(not(bootstrap), lang = "into_future")]
+ #[lang = "into_future"]
fn into_future(self) -> Self::Future;
}
diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs
index a6ffbe0..fa4eb0d 100644
--- a/library/core/src/future/join.rs
+++ b/library/core/src/future/join.rs
@@ -9,7 +9,7 @@
/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
///
-/// While `join!(a, b)` is similar to `(a.await, b.await)`,
+/// While `join!(a, b).await` is similar to `(a.await, b.await)`,
/// `join!` polls both futures concurrently and is therefore more efficient.
///
/// # Examples
diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs
index 560dd25..2877e66 100644
--- a/library/core/src/future/pending.rs
+++ b/library/core/src/future/pending.rs
@@ -12,7 +12,7 @@
#[stable(feature = "future_readiness_fns", since = "1.48.0")]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Pending<T> {
- _data: marker::PhantomData<T>,
+ _data: marker::PhantomData<fn() -> T>,
}
/// Creates a future which never resolves, representing a computation that never
@@ -44,9 +44,6 @@
}
#[stable(feature = "future_readiness_fns", since = "1.48.0")]
-impl<T> Unpin for Pending<T> {}
-
-#[stable(feature = "future_readiness_fns", since = "1.48.0")]
impl<T> Debug for Pending<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Pending").finish()
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 3ff84cc..53de8b4 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -602,7 +602,7 @@
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts
#[stable(since = "1.7.0", feature = "build_hasher")]
-pub struct BuildHasherDefault<H>(marker::PhantomData<H>);
+pub struct BuildHasherDefault<H>(marker::PhantomData<fn() -> H>);
#[stable(since = "1.9.0", feature = "core_impl_debug")]
impl<H> fmt::Debug for BuildHasherDefault<H> {
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 4ecc3b0..b522839 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -961,7 +961,7 @@
/// Below are common applications of `transmute` which can be replaced with safer
/// constructs.
///
- /// Turning raw bytes(`&[u8]`) to `u32`, `f64`, etc.:
+ /// Turning raw bytes (`&[u8]`) into `u32`, `f64`, etc.:
///
/// ```
/// let raw_bytes = [0x78, 0x56, 0x34, 0x12];
@@ -1893,7 +1893,7 @@
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
+ #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
/// See documentation of `<*const T>::guaranteed_eq` for details.
@@ -1914,10 +1914,31 @@
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
- /// Allocate at compile time. Should not be called at runtime.
+ /// Allocates a block of memory at compile time.
+ /// At runtime, just returns a null pointer.
+ ///
+ /// # Safety
+ ///
+ /// - The `align` argument must be a power of two.
+ /// - At compile time, a compile error occurs if this constraint is violated.
+ /// - At runtime, it is not checked.
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
+ /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
+ /// At runtime, does nothing.
+ ///
+ /// # Safety
+ ///
+ /// - The `align` argument must be a power of two.
+ /// - At compile time, a compile error occurs if this constraint is violated.
+ /// - At runtime, it is not checked.
+ /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
+ /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
+ #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+ #[cfg(not(bootstrap))]
+ pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
+
/// Determines whether the raw bytes of the two values are equal.
///
/// This is particularly handy for arrays, since it allows things like just
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index 449650a..b2ed825 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -19,7 +19,7 @@
/// you can also [`map`] backwards:
///
/// ```rust
-/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
+/// let v: Vec<i32> = [1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
///
/// assert_eq!(v, [4, 3, 2]);
/// ```
@@ -32,7 +32,7 @@
/// ```rust
/// let mut c = 0;
///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// for pair in ['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) }) {
/// println!("{:?}", pair);
/// }
@@ -49,7 +49,7 @@
/// ```rust
/// let mut c = 0;
///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// for pair in ['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) })
/// .rev() {
/// println!("{:?}", pair);
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index b1b9177..2ae92e8 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1,5 +1,5 @@
use crate::iter::{InPlaceIterable, Iterator};
-use crate::ops::{ControlFlow, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
mod chain;
mod cloned;
@@ -24,6 +24,7 @@
mod take_while;
mod zip;
+#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{
chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap,
flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev,
@@ -127,41 +128,45 @@
}
/// An iterator adapter that produces output as long as the underlying
-/// iterator produces `Result::Ok` values.
+/// iterator produces values where `Try::branch` says to `ControlFlow::Continue`.
///
-/// If an error is encountered, the iterator stops and the error is
-/// stored.
-pub(crate) struct ResultShunt<'a, I, E> {
+/// If a `ControlFlow::Break` is encountered, the iterator stops and the
+/// residual is stored.
+pub(crate) struct GenericShunt<'a, I, R> {
iter: I,
- error: &'a mut Result<(), E>,
+ residual: &'a mut Option<R>,
}
-/// Process the given iterator as if it yielded a `T` instead of a
-/// `Result<T, _>`. Any errors will stop the inner iterator and
-/// the overall result will be an error.
-pub(crate) fn process_results<I, T, E, F, U>(iter: I, mut f: F) -> Result<U, E>
+/// Process the given iterator as if it yielded a the item's `Try::Output`
+/// type instead. Any `Try::Residual`s encountered will stop the inner iterator
+/// and be propagated back to the overall result.
+pub(crate) fn try_process<I, T, R, F, U>(iter: I, mut f: F) -> ChangeOutputType<I::Item, U>
where
- I: Iterator<Item = Result<T, E>>,
- for<'a> F: FnMut(ResultShunt<'a, I, E>) -> U,
+ I: Iterator<Item: Try<Output = T, Residual = R>>,
+ for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U,
+ R: Residual<U>,
{
- let mut error = Ok(());
- let shunt = ResultShunt { iter, error: &mut error };
+ let mut residual = None;
+ let shunt = GenericShunt { iter, residual: &mut residual };
let value = f(shunt);
- error.map(|()| value)
+ match residual {
+ Some(r) => FromResidual::from_residual(r),
+ None => Try::from_output(value),
+ }
}
-impl<I, T, E> Iterator for ResultShunt<'_, I, E>
+impl<I, R> Iterator for GenericShunt<'_, I, R>
where
- I: Iterator<Item = Result<T, E>>,
+ I: Iterator<Item: Try<Residual = R>>,
{
- type Item = T;
+ type Item = <I::Item as Try>::Output;
fn next(&mut self) -> Option<Self::Item> {
- self.find(|_| true)
+ self.try_for_each(ControlFlow::Break).break_value()
}
fn size_hint(&self) -> (usize, Option<usize>) {
- if self.error.is_err() {
+ if self.residual.is_some() {
(0, Some(0))
} else {
let (_, upper) = self.iter.size_hint();
@@ -169,17 +174,16 @@
}
}
- fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ fn try_fold<B, F, T>(&mut self, init: B, mut f: F) -> T
where
- F: FnMut(B, Self::Item) -> R,
- R: Try<Output = B>,
+ F: FnMut(B, Self::Item) -> T,
+ T: Try<Output = B>,
{
- let error = &mut *self.error;
self.iter
- .try_fold(init, |acc, x| match x {
- Ok(x) => ControlFlow::from_try(f(acc, x)),
- Err(e) => {
- *error = Err(e);
+ .try_fold(init, |acc, x| match Try::branch(x) {
+ ControlFlow::Continue(x) => ControlFlow::from_try(f(acc, x)),
+ ControlFlow::Break(r) => {
+ *self.residual = Some(r);
ControlFlow::Break(try { acc })
}
})
@@ -191,17 +195,12 @@
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
+ self.try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
}
}
#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I, E> SourceIter for ResultShunt<'_, I, E>
+unsafe impl<I, R> SourceIter for GenericShunt<'_, I, R>
where
I: SourceIter,
{
@@ -214,11 +213,11 @@
}
}
-// SAFETY: ResultShunt::next calls I::find, which has to advance `iter` in order to
-// return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's guaranteed that
-// at least one item will be moved out from the underlying source.
+// SAFETY: GenericShunt::next calls `I::try_for_each`, which has to advance `iter`
+// in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's
+// guaranteed that at least one item will be moved out from the underlying source.
#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I, T, E> InPlaceIterable for ResultShunt<'_, I, E> where
- I: Iterator<Item = Result<T, E>> + InPlaceIterable
+unsafe impl<I, T, R> InPlaceIterable for GenericShunt<'_, I, R> where
+ I: Iterator<Item: Try<Output = T, Residual = R>> + InPlaceIterable
{
}
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index da459ed..65f56f6 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -417,7 +417,7 @@
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
pub use self::adapters::{Intersperse, IntersperseWith};
-pub(crate) use self::adapters::process_results;
+pub(crate) use self::adapters::try_process;
mod adapters;
mod range;
diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs
index de06631..37b6f2e 100644
--- a/library/core/src/iter/sources.rs
+++ b/library/core/src/iter/sources.rs
@@ -6,6 +6,7 @@
mod repeat_with;
mod successors;
+#[stable(feature = "rust1", since = "1.0.0")]
pub use self::repeat::{repeat, Repeat};
#[stable(feature = "iter_empty", since = "1.2.0")]
diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs
index 7abe01d..98734c5 100644
--- a/library/core/src/iter/sources/empty.rs
+++ b/library/core/src/iter/sources/empty.rs
@@ -22,17 +22,17 @@
Empty(marker::PhantomData)
}
+// Newtype for use in `PhantomData` to avoid
+// > error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
+// in `const fn empty<T>()` above.
+struct FnReturning<T>(fn() -> T);
+
/// An iterator that yields nothing.
///
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iter_empty", since = "1.2.0")]
-pub struct Empty<T>(marker::PhantomData<T>);
-
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Send for Empty<T> {}
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Sync for Empty<T> {}
+pub struct Empty<T>(marker::PhantomData<FnReturning<T>>);
#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<T> fmt::Debug for Empty<T> {
diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs
index c2e837d..84d83ee 100644
--- a/library/core/src/iter/traits/accum.rs
+++ b/library/core/src/iter/traits/accum.rs
@@ -167,7 +167,7 @@
where
I: Iterator<Item = Result<U, E>>,
{
- iter::process_results(iter, |i| i.sum())
+ iter::try_process(iter, |i| i.sum())
}
}
@@ -183,7 +183,7 @@
where
I: Iterator<Item = Result<U, E>>,
{
- iter::process_results(iter, |i| i.product())
+ iter::try_process(iter, |i| i.product())
}
}
@@ -210,7 +210,7 @@
where
I: Iterator<Item = Option<U>>,
{
- iter.map(|x| x.ok_or(())).sum::<Result<_, _>>().ok()
+ iter::try_process(iter, |i| i.sum())
}
}
@@ -226,6 +226,6 @@
where
I: Iterator<Item = Option<U>>,
{
- iter.map(|x| x.ok_or(())).product::<Result<_, _>>().ok()
+ iter::try_process(iter, |i| i.product())
}
}
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 56fad60..637d7bc 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -15,8 +15,6 @@
/// Basic usage:
///
/// ```
-/// use std::iter::FromIterator;
-///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
@@ -37,8 +35,6 @@
/// Implementing `FromIterator` for your type:
///
/// ```
-/// use std::iter::FromIterator;
-///
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
@@ -85,6 +81,32 @@
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
+ on(
+ _Self = "[{A}]",
+ message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
+ label = "try explicitly collecting into a `Vec<{A}>`",
+ ),
+ on(
+ all(
+ A = "{integer}",
+ any(
+ _Self = "[i8]",
+ _Self = "[i16]",
+ _Self = "[i32]",
+ _Self = "[i64]",
+ _Self = "[i128]",
+ _Self = "[isize]",
+ _Self = "[u8]",
+ _Self = "[u16]",
+ _Self = "[u32]",
+ _Self = "[u64]",
+ _Self = "[u128]",
+ _Self = "[usize]"
+ )
+ ),
+ message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
+ label = "try explicitly collecting into a `Vec<{A}>`",
+ ),
message = "a value of type `{Self}` cannot be built from an iterator \
over elements of type `{A}`",
label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
@@ -102,8 +124,6 @@
/// Basic usage:
///
/// ```
- /// use std::iter::FromIterator;
- ///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
@@ -130,7 +150,7 @@
/// Basic usage:
///
/// ```
-/// let v = vec![1, 2, 3];
+/// let v = [1, 2, 3];
/// let mut iter = v.into_iter();
///
/// assert_eq!(Some(1), iter.next());
@@ -221,7 +241,7 @@
/// Basic usage:
///
/// ```
- /// let v = vec![1, 2, 3];
+ /// let v = [1, 2, 3];
/// let mut iter = v.into_iter();
///
/// assert_eq!(Some(1), iter.next());
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 9a9a844..5a361ed 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1,6 +1,7 @@
use crate::cmp::{self, Ordering};
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
+use super::super::try_process;
use super::super::TrustedRandomAccessNoCoerce;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
@@ -515,8 +516,44 @@
/// assert_eq!((2, 'o'), zipper[2]);
/// ```
///
+ /// If both iterators have roughly equivalent syntax, it may be more readable to use [`zip`]:
+ ///
+ /// ```
+ /// use std::iter::zip;
+ ///
+ /// let a = [1, 2, 3];
+ /// let b = [2, 3, 4];
+ ///
+ /// let mut zipped = zip(
+ /// a.into_iter().map(|x| x * 2).skip(1),
+ /// b.into_iter().map(|x| x * 2).skip(1),
+ /// );
+ ///
+ /// assert_eq!(zipped.next(), Some((4, 6)));
+ /// assert_eq!(zipped.next(), Some((6, 8)));
+ /// assert_eq!(zipped.next(), None);
+ /// ```
+ ///
+ /// compared to:
+ ///
+ /// ```
+ /// # let a = [1, 2, 3];
+ /// # let b = [2, 3, 4];
+ /// #
+ /// let mut zipped = a
+ /// .into_iter()
+ /// .map(|x| x * 2)
+ /// .skip(1)
+ /// .zip(b.into_iter().map(|x| x * 2).skip(1));
+ /// #
+ /// # assert_eq!(zipped.next(), Some((4, 6)));
+ /// # assert_eq!(zipped.next(), Some((6, 8)));
+ /// # assert_eq!(zipped.next(), None);
+ /// ```
+ ///
/// [`enumerate`]: Iterator::enumerate
/// [`next`]: Iterator::next
+ /// [`zip`]: crate::iter::zip
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
@@ -590,7 +627,7 @@
/// #[derive(PartialEq, Debug)]
/// struct NotClone(usize);
///
- /// let v = vec![NotClone(0), NotClone(1), NotClone(2)];
+ /// let v = [NotClone(0), NotClone(1), NotClone(2)];
/// let mut it = v.into_iter().intersperse_with(|| NotClone(99));
///
/// assert_eq!(it.next(), Some(NotClone(0))); // The first element from `v`.
@@ -1155,8 +1192,6 @@
/// Stopping after an initial [`None`]:
///
/// ```
- /// use std::convert::TryFrom;
- ///
/// let a = [0, 1, 2, -3, 4, 5, -6];
///
/// let iter = a.iter().map_while(|x| u32::try_from(*x).ok());
@@ -1172,8 +1207,6 @@
/// removed:
///
/// ```
- /// use std::convert::TryFrom;
- ///
/// let a = [1, 2, -3, 4];
/// let mut iter = a.iter();
///
@@ -1274,7 +1307,7 @@
/// `take` will limit itself to the size of the underlying iterator:
///
/// ```
- /// let v = vec![1, 2];
+ /// let v = [1, 2];
/// let mut iter = v.into_iter().take(5);
/// assert_eq!(iter.next(), Some(1));
/// assert_eq!(iter.next(), Some(2));
@@ -1608,7 +1641,7 @@
/// Basic usage:
///
/// ```
- /// let mut words = vec!["hello", "world", "of", "Rust"].into_iter();
+ /// let mut words = ["hello", "world", "of", "Rust"].into_iter();
///
/// // Take the first two words.
/// let hello_world: Vec<_> = words.by_ref().take(2).collect();
@@ -1745,6 +1778,87 @@
FromIterator::from_iter(self)
}
+ /// Fallibly transforms an iterator into a collection, short circuiting if
+ /// a failure is encountered.
+ ///
+ /// `try_collect()` is a variation of [`collect()`][`collect`] that allows fallible
+ /// conversions during collection. Its main use case is simplifying conversions from
+ /// iterators yielding [`Option<T>`][`Option`] into `Option<Collection<T>>`, or similarly for other [`Try`]
+ /// types (e.g. [`Result`]).
+ ///
+ /// Importantly, `try_collect()` doesn't require that the outer [`Try`] type also implements [`FromIterator`];
+ /// only the inner type produced on `Try::Output` must implement it. Concretely,
+ /// this means that collecting into `ControlFlow<_, Vec<i32>>` is valid because `Vec<i32>` implements
+ /// [`FromIterator`], even though [`ControlFlow`] doesn't.
+ ///
+ /// Also, if a failure is encountered during `try_collect()`, the iterator is still valid and
+ /// may continue to be used, in which case it will continue iterating starting after the element that
+ /// triggered the failure. See the last example below for an example of how this works.
+ ///
+ /// # Examples
+ /// Successfully collecting an iterator of `Option<i32>` into `Option<Vec<i32>>`:
+ /// ```
+ /// #![feature(iterator_try_collect)]
+ ///
+ /// let u = vec![Some(1), Some(2), Some(3)];
+ /// let v = u.into_iter().try_collect::<Vec<i32>>();
+ /// assert_eq!(v, Some(vec![1, 2, 3]));
+ /// ```
+ ///
+ /// Failing to collect in the same way:
+ /// ```
+ /// #![feature(iterator_try_collect)]
+ ///
+ /// let u = vec![Some(1), Some(2), None, Some(3)];
+ /// let v = u.into_iter().try_collect::<Vec<i32>>();
+ /// assert_eq!(v, None);
+ /// ```
+ ///
+ /// A similar example, but with `Result`:
+ /// ```
+ /// #![feature(iterator_try_collect)]
+ ///
+ /// let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
+ /// let v = u.into_iter().try_collect::<Vec<i32>>();
+ /// assert_eq!(v, Ok(vec![1, 2, 3]));
+ ///
+ /// let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
+ /// let v = u.into_iter().try_collect::<Vec<i32>>();
+ /// assert_eq!(v, Err(()));
+ /// ```
+ ///
+ /// Finally, even [`ControlFlow`] works, despite the fact that it
+ /// doesn't implement [`FromIterator`]. Note also that the iterator can
+ /// continue to be used, even if a failure is encountered:
+ ///
+ /// ```
+ /// #![feature(iterator_try_collect)]
+ ///
+ /// use core::ops::ControlFlow::{Break, Continue};
+ ///
+ /// let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
+ /// let mut it = u.into_iter();
+ ///
+ /// let v = it.try_collect::<Vec<_>>();
+ /// assert_eq!(v, Break(3));
+ ///
+ /// let v = it.try_collect::<Vec<_>>();
+ /// assert_eq!(v, Continue(vec![4, 5]));
+ /// ```
+ ///
+ /// [`collect`]: Iterator::collect
+ #[inline]
+ #[unstable(feature = "iterator_try_collect", issue = "94047")]
+ fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B>
+ where
+ Self: Sized,
+ <Self as Iterator>::Item: Try,
+ <<Self as Iterator>::Item as Try>::Residual: Residual<B>,
+ B: FromIterator<<Self::Item as Try>::Output>,
+ {
+ try_process(self, |i| i.collect())
+ }
+
/// Consumes an iterator, creating two collections from it.
///
/// The predicate passed to `partition()` can return `true`, or `false`.
@@ -2704,7 +2818,7 @@
/// incomparable. You can work around this by using [`Iterator::reduce`]:
/// ```
/// assert_eq!(
- /// vec![2.4, f32::NAN, 1.3]
+ /// [2.4, f32::NAN, 1.3]
/// .into_iter()
/// .reduce(f32::max)
/// .unwrap(),
@@ -2742,7 +2856,7 @@
/// incomparable. You can work around this by using [`Iterator::reduce`]:
/// ```
/// assert_eq!(
- /// vec![2.4, f32::NAN, 1.3]
+ /// [2.4, f32::NAN, 1.3]
/// .into_iter()
/// .reduce(f32::min)
/// .unwrap(),
diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs
index ffd745a..ed0fb63 100644
--- a/library/core/src/iter/traits/mod.rs
+++ b/library/core/src/iter/traits/mod.rs
@@ -5,15 +5,17 @@
mod iterator;
mod marker;
-pub use self::accum::{Product, Sum};
-pub use self::collect::{Extend, FromIterator, IntoIterator};
-pub use self::double_ended::DoubleEndedIterator;
-pub use self::exact_size::ExactSizeIterator;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::iterator::Iterator;
+pub use self::{
+ accum::{Product, Sum},
+ collect::{Extend, FromIterator, IntoIterator},
+ double_ended::DoubleEndedIterator,
+ exact_size::ExactSizeIterator,
+ iterator::Iterator,
+ marker::{FusedIterator, TrustedLen},
+};
+
#[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::marker::InPlaceIterable;
#[unstable(feature = "trusted_step", issue = "85731")]
pub use self::marker::TrustedStep;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::marker::{FusedIterator, TrustedLen};
diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs
index 788f0cc..8882678 100644
--- a/library/core/src/lazy.rs
+++ b/library/core/src/lazy.rs
@@ -75,6 +75,7 @@
#[unstable(feature = "once_cell", issue = "74465")]
impl<T> const From<T> for OnceCell<T> {
+ /// Creates a new `OnceCell<T>` which already contains the given `value`.
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index d61800d..aa1ad93 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -60,32 +60,29 @@
test(no_crate_inject, attr(deny(warnings))),
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
-#![cfg_attr(
- not(bootstrap),
- doc(cfg_hide(
- not(test),
- any(not(feature = "miri-test-libstd"), test, doctest),
- no_fp_fmt_parse,
- target_pointer_width = "16",
- target_pointer_width = "32",
- target_pointer_width = "64",
- target_has_atomic = "8",
- target_has_atomic = "16",
- target_has_atomic = "32",
- target_has_atomic = "64",
- target_has_atomic = "ptr",
- target_has_atomic_equal_alignment = "8",
- target_has_atomic_equal_alignment = "16",
- target_has_atomic_equal_alignment = "32",
- target_has_atomic_equal_alignment = "64",
- target_has_atomic_equal_alignment = "ptr",
- target_has_atomic_load_store = "8",
- target_has_atomic_load_store = "16",
- target_has_atomic_load_store = "32",
- target_has_atomic_load_store = "64",
- target_has_atomic_load_store = "ptr",
- ))
-)]
+#![doc(cfg_hide(
+ not(test),
+ any(not(feature = "miri-test-libstd"), test, doctest),
+ no_fp_fmt_parse,
+ target_pointer_width = "16",
+ target_pointer_width = "32",
+ target_pointer_width = "64",
+ target_has_atomic = "8",
+ target_has_atomic = "16",
+ target_has_atomic = "32",
+ target_has_atomic = "64",
+ target_has_atomic = "ptr",
+ target_has_atomic_equal_alignment = "8",
+ target_has_atomic_equal_alignment = "16",
+ target_has_atomic_equal_alignment = "32",
+ target_has_atomic_equal_alignment = "64",
+ target_has_atomic_equal_alignment = "ptr",
+ target_has_atomic_load_store = "8",
+ target_has_atomic_load_store = "16",
+ target_has_atomic_load_store = "32",
+ target_has_atomic_load_store = "64",
+ target_has_atomic_load_store = "ptr",
+))]
#![no_core]
//
// Lints:
@@ -159,6 +156,7 @@
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(cfg_target_has_atomic)]
+#![cfg_attr(not(bootstrap), feature(cfg_target_has_atomic_equal_alignment))]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(const_fn_trait_bound)]
@@ -180,7 +178,6 @@
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
-#![feature(llvm_asm)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
#![feature(must_not_suspend)]
@@ -308,6 +305,8 @@
pub mod any;
pub mod array;
pub mod ascii;
+#[unstable(feature = "async_iterator", issue = "79024")]
+pub mod async_iter;
pub mod cell;
pub mod char;
pub mod ffi;
@@ -319,8 +318,6 @@
pub mod panicking;
pub mod pin;
pub mod result;
-#[unstable(feature = "async_stream", issue = "79024")]
-pub mod stream;
pub mod sync;
pub mod fmt;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index cd2b01e..628b679 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -31,6 +31,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "assert_eq_macro")]
#[allow_internal_unstable(core_panic)]
macro_rules! assert_eq {
($left:expr, $right:expr $(,)?) => ({
@@ -80,6 +81,7 @@
/// ```
#[macro_export]
#[stable(feature = "assert_ne", since = "1.13.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "assert_ne_macro")]
#[allow_internal_unstable(core_panic)]
macro_rules! assert_ne {
($left:expr, $right:expr $(,)?) => ({
@@ -236,6 +238,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_eq_macro")]
macro_rules! debug_assert_eq {
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); })
}
@@ -261,6 +264,7 @@
/// ```
#[macro_export]
#[stable(feature = "assert_ne", since = "1.13.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_ne_macro")]
macro_rules! debug_assert_ne {
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
}
@@ -320,6 +324,7 @@
/// ```
#[macro_export]
#[stable(feature = "matches_macro", since = "1.42.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")]
macro_rules! matches {
($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
match $expression {
@@ -475,6 +480,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")]
macro_rules! write {
($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*)))
}
@@ -525,6 +531,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")]
#[allow_internal_unstable(format_args_nl)]
macro_rules! writeln {
($dst:expr $(,)?) => (
@@ -605,6 +612,7 @@
#[cfg(bootstrap)]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")]
#[allow_internal_unstable(core_panic)]
macro_rules! unreachable {
() => ({
@@ -691,6 +699,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "unimplemented_macro")]
#[allow_internal_unstable(core_panic)]
macro_rules! unimplemented {
() => ($crate::panicking::panic("not implemented"));
@@ -753,6 +762,7 @@
/// ```
#[macro_export]
#[stable(feature = "todo_macro", since = "1.40.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "todo_macro")]
#[allow_internal_unstable(core_panic)]
macro_rules! todo {
() => ($crate::panicking::panic("not yet implemented"));
@@ -802,6 +812,7 @@
#[stable(feature = "compile_error_macro", since = "1.20.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "compile_error_macro")]
macro_rules! compile_error {
($msg:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -851,6 +862,7 @@
/// assert_eq!(s, format!("hello {}", "world"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "format_args_macro")]
#[allow_internal_unsafe]
#[allow_internal_unstable(fmt_internals)]
#[rustc_builtin_macro]
@@ -860,7 +872,7 @@
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
}
- /// Same as `format_args`, but can be used in some const contexts.
+ /// Same as [`format_args`], but can be used in some const contexts.
///
/// This macro is used by the panic macros for the `const_panic` feature.
///
@@ -874,7 +886,7 @@
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
}
- /// Same as `format_args`, but adds a newline in the end.
+ /// Same as [`format_args`], but adds a newline in the end.
#[unstable(
feature = "format_args_nl",
issue = "none",
@@ -921,6 +933,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "env_macro")]
macro_rules! env {
($name:expr $(,)?) => {{ /* compiler built-in */ }};
($name:expr, $error_msg:expr $(,)?) => {{ /* compiler built-in */ }};
@@ -946,6 +959,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "option_env_macro")]
macro_rules! option_env {
($name:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1005,7 +1019,6 @@
/// assert_eq!(s, b"ABCDEF");
/// # }
/// ```
- #[cfg(not(bootstrap))]
#[unstable(feature = "concat_bytes", issue = "87555")]
#[rustc_builtin_macro]
#[macro_export]
@@ -1031,6 +1044,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "concat_macro")]
macro_rules! concat {
($($e:expr),* $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1056,6 +1070,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "line_macro")]
macro_rules! line {
() => {
/* compiler built-in */
@@ -1095,6 +1110,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "column_macro")]
macro_rules! column {
() => {
/* compiler built-in */
@@ -1120,6 +1136,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "file_macro")]
macro_rules! file {
() => {
/* compiler built-in */
@@ -1144,6 +1161,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "stringify_macro")]
macro_rules! stringify {
($($t:tt)*) => {
/* compiler built-in */
@@ -1185,6 +1203,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "include_str_macro")]
macro_rules! include_str {
($file:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1224,6 +1243,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "include_bytes_macro")]
macro_rules! include_bytes {
($file:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1248,6 +1268,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "module_path_macro")]
macro_rules! module_path {
() => {
/* compiler built-in */
@@ -1281,6 +1302,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "cfg_macro")]
macro_rules! cfg {
($($cfg:tt)*) => {
/* compiler built-in */
@@ -1331,6 +1353,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "include_macro")]
macro_rules! include {
($file:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1389,32 +1412,6 @@
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
}
- /// LLVM-style inline assembly.
- ///
- /// Read the [unstable book] for the usage.
- ///
- /// [unstable book]: ../unstable-book/library-features/llvm-asm.html
- #[unstable(
- feature = "llvm_asm",
- issue = "70173",
- reason = "prefer using the new asm! syntax instead"
- )]
- #[rustc_deprecated(
- since = "1.56",
- reason = "will be removed from the compiler, use asm! instead"
- )]
- #[rustc_builtin_macro]
- #[macro_export]
- macro_rules! llvm_asm {
- ("assembly template"
- : $("output"(operand),)*
- : $("input"(operand),)*
- : $("clobbers",)*
- : $("options",)*) => {
- /* compiler built-in */
- };
- }
-
/// Prints passed tokens into the standard output.
#[unstable(
feature = "log_syntax",
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 3b0e4a3..e38c041 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -1,8 +1,9 @@
use crate::any::type_name;
use crate::fmt;
use crate::intrinsics;
-use crate::mem::ManuallyDrop;
+use crate::mem::{self, ManuallyDrop};
use crate::ptr;
+use crate::slice;
/// A wrapper type to construct uninitialized instances of `T`.
///
@@ -330,7 +331,7 @@
/// # Examples
///
/// ```no_run
- /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)]
+ /// #![feature(maybe_uninit_uninit_array, maybe_uninit_slice)]
///
/// use std::mem::MaybeUninit;
///
@@ -662,7 +663,6 @@
/// Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit_extra)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<u32>::uninit();
@@ -683,7 +683,6 @@
/// *Incorrect* usage of this method:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit_extra)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
@@ -693,8 +692,8 @@
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
/// // they both get dropped!
/// ```
- #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
- #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
+ #[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init_read", issue = "63567")]
#[inline(always)]
#[track_caller]
pub const unsafe fn assume_init_read(&self) -> T {
@@ -728,7 +727,7 @@
///
/// [`assume_init`]: MaybeUninit::assume_init
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
- #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
+ #[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
pub unsafe fn assume_init_drop(&mut self) {
// SAFETY: the caller must guarantee that `self` is initialized and
// satisfies all invariants of `T`.
@@ -1040,7 +1039,7 @@
/// ```
///
/// ```
- /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)]
+ /// #![feature(maybe_uninit_write_slice)]
/// use std::mem::MaybeUninit;
///
/// let mut vec = Vec::with_capacity(32);
@@ -1100,7 +1099,7 @@
/// ```
///
/// ```
- /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)]
+ /// #![feature(maybe_uninit_write_slice)]
/// use std::mem::MaybeUninit;
///
/// let mut vec = Vec::with_capacity(32);
@@ -1162,4 +1161,126 @@
// SAFETY: Valid elements have just been written into `this` so it is initialized
unsafe { MaybeUninit::slice_assume_init_mut(this) }
}
+
+ /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
+ ///
+ /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+ /// contain padding bytes which are left uninitialized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
+ /// use std::mem::MaybeUninit;
+ ///
+ /// let val = 0x12345678i32;
+ /// let uninit = MaybeUninit::new(val);
+ /// let uninit_bytes = uninit.as_bytes();
+ /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) };
+ /// assert_eq!(bytes, val.to_ne_bytes());
+ /// ```
+ #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+ pub fn as_bytes(&self) -> &[MaybeUninit<u8>] {
+ // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+ unsafe {
+ slice::from_raw_parts(self.as_ptr() as *const MaybeUninit<u8>, mem::size_of::<T>())
+ }
+ }
+
+ /// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized
+ /// bytes.
+ ///
+ /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+ /// contain padding bytes which are left uninitialized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(maybe_uninit_as_bytes)]
+ /// use std::mem::MaybeUninit;
+ ///
+ /// let val = 0x12345678i32;
+ /// let mut uninit = MaybeUninit::new(val);
+ /// let uninit_bytes = uninit.as_bytes_mut();
+ /// if cfg!(target_endian = "little") {
+ /// uninit_bytes[0].write(0xcd);
+ /// } else {
+ /// uninit_bytes[3].write(0xcd);
+ /// }
+ /// let val2 = unsafe { uninit.assume_init() };
+ /// assert_eq!(val2, 0x123456cd);
+ /// ```
+ #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+ pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+ unsafe {
+ slice::from_raw_parts_mut(
+ self.as_mut_ptr() as *mut MaybeUninit<u8>,
+ mem::size_of::<T>(),
+ )
+ }
+ }
+
+ /// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized
+ /// bytes.
+ ///
+ /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+ /// contain padding bytes which are left uninitialized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
+ /// use std::mem::MaybeUninit;
+ ///
+ /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)];
+ /// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit);
+ /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) };
+ /// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap());
+ /// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap());
+ /// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]);
+ /// ```
+ #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+ pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>] {
+ // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+ unsafe {
+ slice::from_raw_parts(
+ this.as_ptr() as *const MaybeUninit<u8>,
+ this.len() * mem::size_of::<T>(),
+ )
+ }
+ }
+
+ /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of
+ /// potentially uninitialized bytes.
+ ///
+ /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+ /// contain padding bytes which are left uninitialized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
+ /// use std::mem::MaybeUninit;
+ ///
+ /// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
+ /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
+ /// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]);
+ /// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) };
+ /// if cfg!(target_endian = "little") {
+ /// assert_eq!(vals, &[0x3412u16, 0x7856u16]);
+ /// } else {
+ /// assert_eq!(vals, &[0x1234u16, 0x5678u16]);
+ /// }
+ /// ```
+ #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+ pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>] {
+ // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+ unsafe {
+ slice::from_raw_parts_mut(
+ this.as_mut_ptr() as *mut MaybeUninit<u8>,
+ this.len() * mem::size_of::<T>(),
+ )
+ }
+ }
}
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index 8a06a09..de85fdd 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -19,18 +19,8 @@
)]
#![macro_use]
-use crate::intrinsics;
-
/// Arithmetic operations required by bignums.
pub trait FullOps: Sized {
- /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
- /// where `W` is the number of bits in `Self`.
- fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self);
-
- /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
- /// where `W` is the number of bits in `Self`.
- fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self);
-
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
/// where `W` is the number of bits in `Self`.
fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
@@ -45,22 +35,6 @@
($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
$(
impl FullOps for $ty {
- fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) {
- // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`.
- // FIXME: will LLVM optimize this into ADC or similar?
- let (v, carry1) = intrinsics::add_with_overflow(self, other);
- let (v, carry2) = intrinsics::add_with_overflow(v, if carry {1} else {0});
- (carry1 || carry2, v)
- }
-
- fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
- // This cannot overflow;
- // the output is between `0` and `2^nbits * (2^nbits - 1)`.
- // FIXME: will LLVM optimize this into ADC or similar?
- let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
- ((v >> <$ty>::BITS) as $ty, v as $ty)
- }
-
fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
// This cannot overflow;
// the output is between `0` and `2^nbits * (2^nbits - 1)`.
@@ -158,36 +132,26 @@
/// Returns the number of bits necessary to represent this value. Note that zero
/// is considered to need 0 bits.
pub fn bit_length(&self) -> usize {
- // Skip over the most significant digits which are zero.
- let digits = self.digits();
- let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
- let end = digits.len() - zeros;
- let nonzero = &digits[..end];
-
- if nonzero.is_empty() {
- // There are no non-zero digits, i.e., the number is zero.
- return 0;
- }
- // This could be optimized with leading_zeros() and bit shifts, but that's
- // probably not worth the hassle.
let digitbits = <$ty>::BITS as usize;
- let mut i = nonzero.len() * digitbits - 1;
- while self.get_bit(i) == 0 {
- i -= 1;
+ let digits = self.digits();
+ // Find the most significant non-zero digit.
+ let msd = digits.iter().rposition(|&x| x != 0);
+ match msd {
+ Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
+ // There are no non-zero digits, i.e., the number is zero.
+ _ => 0,
}
- i + 1
}
/// Adds `other` to itself and returns its own mutable reference.
pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
use crate::cmp;
use crate::iter;
- use crate::num::bignum::FullOps;
let mut sz = cmp::max(self.size, other.size);
let mut carry = false;
for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
- let (c, v) = (*a).full_add(*b, carry);
+ let (v, c) = (*a).carrying_add(*b, carry);
*a = v;
carry = c;
}
@@ -200,13 +164,11 @@
}
pub fn add_small(&mut self, other: $ty) -> &mut $name {
- use crate::num::bignum::FullOps;
-
- let (mut carry, v) = self.base[0].full_add(other, false);
+ let (v, mut carry) = self.base[0].carrying_add(other, false);
self.base[0] = v;
let mut i = 1;
while carry {
- let (c, v) = self.base[i].full_add(0, carry);
+ let (v, c) = self.base[i].carrying_add(0, carry);
self.base[i] = v;
carry = c;
i += 1;
@@ -221,12 +183,11 @@
pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
use crate::cmp;
use crate::iter;
- use crate::num::bignum::FullOps;
let sz = cmp::max(self.size, other.size);
let mut noborrow = true;
for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
- let (c, v) = (*a).full_add(!*b, noborrow);
+ let (v, c) = (*a).carrying_add(!*b, noborrow);
*a = v;
noborrow = c;
}
@@ -238,12 +199,10 @@
/// Multiplies itself by a digit-sized `other` and returns its own
/// mutable reference.
pub fn mul_small(&mut self, other: $ty) -> &mut $name {
- use crate::num::bignum::FullOps;
-
let mut sz = self.size;
let mut carry = 0;
for a in &mut self.base[..sz] {
- let (c, v) = (*a).full_mul(other, carry);
+ let (v, c) = (*a).carrying_mul(other, carry);
*a = v;
carry = c;
}
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 85ceede..d8dcfda 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -675,7 +675,7 @@
/// Returns the maximum of the two numbers.
///
/// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
- /// This matches the behavior of libm’s fmin.
+ /// This matches the behavior of libm’s fmax.
///
/// ```
/// let x = 1.0f32;
@@ -1008,29 +1008,37 @@
Self::from_bits(u32::from_ne_bytes(bytes))
}
- /// Returns an ordering between self and other values.
+ /// Return the ordering between `self` and `other`.
+ ///
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
- /// the totalOrder predicate as defined in IEEE 754 (2008 revision)
- /// floating point standard. The values are ordered in following order:
- /// - Negative quiet NaN
- /// - Negative signaling NaN
- /// - Negative infinity
- /// - Negative numbers
- /// - Negative subnormal numbers
- /// - Negative zero
- /// - Positive zero
- /// - Positive subnormal numbers
- /// - Positive numbers
- /// - Positive infinity
- /// - Positive signaling NaN
- /// - Positive quiet NaN
+ /// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
+ /// floating point standard. The values are ordered in the following sequence:
///
- /// Note that this function does not always agree with the [`PartialOrd`]
- /// and [`PartialEq`] implementations of `f32`. In particular, they regard
- /// negative and positive zero as equal, while `total_cmp` doesn't.
+ /// - negative quiet NaN
+ /// - negative signaling NaN
+ /// - negative infinity
+ /// - negative numbers
+ /// - negative subnormal numbers
+ /// - negative zero
+ /// - positive zero
+ /// - positive subnormal numbers
+ /// - positive numbers
+ /// - positive infinity
+ /// - positive signaling NaN
+ /// - positive quiet NaN.
+ ///
+ /// The ordering established by this function does not always agree with the
+ /// [`PartialOrd`] and [`PartialEq`] implementations of `f32`. For example,
+ /// they consider negative and positive zero equal, while `total_cmp`
+ /// doesn't.
+ ///
+ /// The interpretation of the signaling NaN bit follows the definition in
+ /// the IEEE 754 standard, which may not match the interpretation by some of
+ /// the older, non-conformant (e.g. MIPS) hardware implementations.
///
/// # Example
+ ///
/// ```
/// #![feature(total_cmp)]
/// struct GoodBoy {
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 4049c95..7c2f51f 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -691,7 +691,7 @@
/// Returns the maximum of the two numbers.
///
/// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
- /// This matches the behavior of libm’s fmin.
+ /// This matches the behavior of libm’s fmax.
///
/// ```
/// let x = 1.0_f64;
@@ -1024,29 +1024,37 @@
Self::from_bits(u64::from_ne_bytes(bytes))
}
- /// Returns an ordering between self and other values.
+ /// Return the ordering between `self` and `other`.
+ ///
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
- /// the totalOrder predicate as defined in IEEE 754 (2008 revision)
- /// floating point standard. The values are ordered in following order:
- /// - Negative quiet NaN
- /// - Negative signaling NaN
- /// - Negative infinity
- /// - Negative numbers
- /// - Negative subnormal numbers
- /// - Negative zero
- /// - Positive zero
- /// - Positive subnormal numbers
- /// - Positive numbers
- /// - Positive infinity
- /// - Positive signaling NaN
- /// - Positive quiet NaN
+ /// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
+ /// floating point standard. The values are ordered in the following sequence:
///
- /// Note that this function does not always agree with the [`PartialOrd`]
- /// and [`PartialEq`] implementations of `f64`. In particular, they regard
- /// negative and positive zero as equal, while `total_cmp` doesn't.
+ /// - negative quiet NaN
+ /// - negative signaling NaN
+ /// - negative infinity
+ /// - negative numbers
+ /// - negative subnormal numbers
+ /// - negative zero
+ /// - positive zero
+ /// - positive subnormal numbers
+ /// - positive numbers
+ /// - positive infinity
+ /// - positive signaling NaN
+ /// - positive quiet NaN.
+ ///
+ /// The ordering established by this function does not always agree with the
+ /// [`PartialOrd`] and [`PartialEq`] implementations of `f64`. For example,
+ /// they consider negative and positive zero equal, while `total_cmp`
+ /// doesn't.
+ ///
+ /// The interpretation of the signaling NaN bit follows the definition in
+ /// the IEEE 754 standard, which may not match the interpretation by some of
+ /// the older, non-conformant (e.g. MIPS) hardware implementations.
///
/// # Example
+ ///
/// ```
/// #![feature(total_cmp)]
/// struct GoodBoy {
diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs
index a8455fb..cc26c04 100644
--- a/library/core/src/num/int_log10.rs
+++ b/library/core/src/num/int_log10.rs
@@ -1,141 +1,140 @@
-mod unchecked {
- // 0 < val <= u8::MAX
- #[inline]
- pub const fn u8(val: u8) -> u32 {
- let val = val as u32;
+/// These functions compute the integer logarithm of their type, assuming
+/// that someone has already checked that the the value is strictly positive.
- // For better performance, avoid branches by assembling the solution
- // in the bits above the low 8 bits.
+// 0 < val <= u8::MAX
+#[inline]
+pub const fn u8(val: u8) -> u32 {
+ let val = val as u32;
- // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
- const C1: u32 = 0b11_00000000 - 10; // 758
- // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
- const C2: u32 = 0b10_00000000 - 100; // 412
+ // For better performance, avoid branches by assembling the solution
+ // in the bits above the low 8 bits.
- // Value of top bits:
- // +c1 +c2 1&2
- // 0..=9 10 01 00 = 0
- // 10..=99 11 01 01 = 1
- // 100..=255 11 10 10 = 2
- ((val + C1) & (val + C2)) >> 8
- }
+ // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
+ const C1: u32 = 0b11_00000000 - 10; // 758
+ // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
+ const C2: u32 = 0b10_00000000 - 100; // 412
- // 0 < val < 100_000
- #[inline]
- const fn less_than_5(val: u32) -> u32 {
- // Similar to u8, when adding one of these constants to val,
- // we get two possible bit patterns above the low 17 bits,
- // depending on whether val is below or above the threshold.
- const C1: u32 = 0b011_00000000000000000 - 10; // 393206
- const C2: u32 = 0b100_00000000000000000 - 100; // 524188
- const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
- const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
-
- // Value of top bits:
- // +c1 +c2 1&2 +c3 +c4 3&4 ^
- // 0..=9 010 011 010 110 011 010 000 = 0
- // 10..=99 011 011 011 110 011 010 001 = 1
- // 100..=999 011 100 000 110 011 010 010 = 2
- // 1000..=9999 011 100 000 111 011 011 011 = 3
- // 10000..=99999 011 100 000 111 100 100 100 = 4
- (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
- }
-
- // 0 < val <= u16::MAX
- #[inline]
- pub const fn u16(val: u16) -> u32 {
- less_than_5(val as u32)
- }
-
- // 0 < val <= u32::MAX
- #[inline]
- pub const fn u32(mut val: u32) -> u32 {
- let mut log = 0;
- if val >= 100_000 {
- val /= 100_000;
- log += 5;
- }
- log + less_than_5(val)
- }
-
- // 0 < val <= u64::MAX
- #[inline]
- pub const fn u64(mut val: u64) -> u32 {
- let mut log = 0;
- if val >= 10_000_000_000 {
- val /= 10_000_000_000;
- log += 10;
- }
- if val >= 100_000 {
- val /= 100_000;
- log += 5;
- }
- log + less_than_5(val as u32)
- }
-
- // 0 < val <= u128::MAX
- #[inline]
- pub const fn u128(mut val: u128) -> u32 {
- let mut log = 0;
- if val >= 100_000_000_000_000_000_000_000_000_000_000 {
- val /= 100_000_000_000_000_000_000_000_000_000_000;
- log += 32;
- return log + u32(val as u32);
- }
- if val >= 10_000_000_000_000_000 {
- val /= 10_000_000_000_000_000;
- log += 16;
- }
- log + u64(val as u64)
- }
-
- // 0 < val <= i8::MAX
- #[inline]
- pub const fn i8(val: i8) -> u32 {
- u8(val as u8)
- }
-
- // 0 < val <= i16::MAX
- #[inline]
- pub const fn i16(val: i16) -> u32 {
- u16(val as u16)
- }
-
- // 0 < val <= i32::MAX
- #[inline]
- pub const fn i32(val: i32) -> u32 {
- u32(val as u32)
- }
-
- // 0 < val <= i64::MAX
- #[inline]
- pub const fn i64(val: i64) -> u32 {
- u64(val as u64)
- }
-
- // 0 < val <= i128::MAX
- #[inline]
- pub const fn i128(val: i128) -> u32 {
- u128(val as u128)
- }
+ // Value of top bits:
+ // +c1 +c2 1&2
+ // 0..=9 10 01 00 = 0
+ // 10..=99 11 01 01 = 1
+ // 100..=255 11 10 10 = 2
+ ((val + C1) & (val + C2)) >> 8
}
-macro_rules! impl_checked {
- ($T:ident) => {
- #[inline]
- pub const fn $T(val: $T) -> Option<u32> {
- if val > 0 { Some(unchecked::$T(val)) } else { None }
- }
- };
+// 0 < val < 100_000
+#[inline]
+const fn less_than_5(val: u32) -> u32 {
+ // Similar to u8, when adding one of these constants to val,
+ // we get two possible bit patterns above the low 17 bits,
+ // depending on whether val is below or above the threshold.
+ const C1: u32 = 0b011_00000000000000000 - 10; // 393206
+ const C2: u32 = 0b100_00000000000000000 - 100; // 524188
+ const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
+ const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
+
+ // Value of top bits:
+ // +c1 +c2 1&2 +c3 +c4 3&4 ^
+ // 0..=9 010 011 010 110 011 010 000 = 0
+ // 10..=99 011 011 011 110 011 010 001 = 1
+ // 100..=999 011 100 000 110 011 010 010 = 2
+ // 1000..=9999 011 100 000 111 011 011 011 = 3
+ // 10000..=99999 011 100 000 111 100 100 100 = 4
+ (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
}
-impl_checked! { u8 }
-impl_checked! { u16 }
-impl_checked! { u32 }
-impl_checked! { u64 }
-impl_checked! { u128 }
-impl_checked! { i8 }
-impl_checked! { i16 }
-impl_checked! { i32 }
-impl_checked! { i64 }
-impl_checked! { i128 }
+// 0 < val <= u16::MAX
+#[inline]
+pub const fn u16(val: u16) -> u32 {
+ less_than_5(val as u32)
+}
+
+// 0 < val <= u32::MAX
+#[inline]
+pub const fn u32(mut val: u32) -> u32 {
+ let mut log = 0;
+ if val >= 100_000 {
+ val /= 100_000;
+ log += 5;
+ }
+ log + less_than_5(val)
+}
+
+// 0 < val <= u64::MAX
+#[inline]
+pub const fn u64(mut val: u64) -> u32 {
+ let mut log = 0;
+ if val >= 10_000_000_000 {
+ val /= 10_000_000_000;
+ log += 10;
+ }
+ if val >= 100_000 {
+ val /= 100_000;
+ log += 5;
+ }
+ log + less_than_5(val as u32)
+}
+
+// 0 < val <= u128::MAX
+#[inline]
+pub const fn u128(mut val: u128) -> u32 {
+ let mut log = 0;
+ if val >= 100_000_000_000_000_000_000_000_000_000_000 {
+ val /= 100_000_000_000_000_000_000_000_000_000_000;
+ log += 32;
+ return log + u32(val as u32);
+ }
+ if val >= 10_000_000_000_000_000 {
+ val /= 10_000_000_000_000_000;
+ log += 16;
+ }
+ log + u64(val as u64)
+}
+
+#[cfg(target_pointer_width = "16")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+ u16(val as _)
+}
+
+#[cfg(target_pointer_width = "32")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+ u32(val as _)
+}
+
+#[cfg(target_pointer_width = "64")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+ u64(val as _)
+}
+
+// 0 < val <= i8::MAX
+#[inline]
+pub const fn i8(val: i8) -> u32 {
+ u8(val as u8)
+}
+
+// 0 < val <= i16::MAX
+#[inline]
+pub const fn i16(val: i16) -> u32 {
+ u16(val as u16)
+}
+
+// 0 < val <= i32::MAX
+#[inline]
+pub const fn i32(val: i32) -> u32 {
+ u32(val as u32)
+}
+
+// 0 < val <= i64::MAX
+#[inline]
+pub const fn i64(val: i64) -> u32 {
+ u64(val as u64)
+}
+
+// 0 < val <= i128::MAX
+#[inline]
+pub const fn i128(val: i128) -> u32 {
+ u128(val as u128)
+}
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index e6ae4af..199af08 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -4,7 +4,7 @@
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
/// The smallest value that can be represented by this integer type,
- #[doc = concat!("-2<sup>", $BITS_MINUS_ONE, "</sup>.")]
+ #[doc = concat!("−2<sup>", $BITS_MINUS_ONE, "</sup>.")]
///
/// # Examples
///
@@ -17,7 +17,7 @@
pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
/// The largest value that can be represented by this integer type,
- #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> - 1.")]
+ #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> − 1.")]
///
/// # Examples
///
@@ -1064,6 +1064,7 @@
///
/// ```
#[stable(feature = "saturating_div", since = "1.58.0")]
+ #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -2362,7 +2363,11 @@
without modifying the original"]
#[inline]
pub const fn checked_log10(self) -> Option<u32> {
- int_log10::$ActualT(self as $ActualT)
+ if self > 0 {
+ Some(int_log10::$ActualT(self as $ActualT))
+ } else {
+ None
+ }
}
/// Computes the absolute value of `self`.
@@ -2415,14 +2420,14 @@
/// Basic usage:
///
/// ```
- /// #![feature(int_abs_diff)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($UnsignedT), ");")]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($UnsignedT), ");")]
#[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(80), 180", stringify!($UnsignedT), ");")]
#[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(-120), 20", stringify!($UnsignedT), ");")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.abs_diff(", stringify!($SelfT), "::MAX), ", stringify!($UnsignedT), "::MAX);")]
/// ```
- #[unstable(feature = "int_abs_diff", issue = "89492")]
+ #[stable(feature = "int_abs_diff", since = "1.60.0")]
+ #[rustc_const_stable(feature = "int_abs_diff", since = "1.60.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -2602,8 +2607,6 @@
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
@@ -2633,8 +2636,6 @@
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
@@ -2675,8 +2676,6 @@
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index e3eab07..7210588 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -264,7 +264,7 @@
#[lang = "u8"]
impl u8 {
- uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
+ uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
"[0x12]", "", "" }
widening_impl! { u8, u16, 8, unsigned }
@@ -791,7 +791,6 @@
/// # Examples
///
/// ```
- /// #![feature(inherent_ascii_escape)]
///
/// assert_eq!("0", b'0'.escape_ascii().to_string());
/// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
@@ -804,30 +803,35 @@
/// ```
#[must_use = "this returns the escaped byte as an iterator, \
without modifying the original"]
- #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+ #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
#[inline]
- pub fn escape_ascii(&self) -> ascii::EscapeDefault {
- ascii::escape_default(*self)
+ pub fn escape_ascii(self) -> ascii::EscapeDefault {
+ ascii::escape_default(self)
+ }
+
+ pub(crate) fn is_utf8_char_boundary(self) -> bool {
+ // This is bit magic equivalent to: b < 128 || b >= 192
+ (self as i8) >= -0x40
}
}
#[lang = "u16"]
impl u16 {
- uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+ uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
widening_impl! { u16, u32, 16, unsigned }
}
#[lang = "u32"]
impl u32 {
- uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+ uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
widening_impl! { u32, u64, 32, unsigned }
}
#[lang = "u64"]
impl u64 {
- uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+ uint_impl! { u64, u64, i64, NonZeroU64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -837,7 +841,7 @@
#[lang = "u128"]
impl u128 {
- uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16,
+ uint_impl! { u128, u128, i128, NonZeroU128, 128, 340282366920938463463374607431768211455, 16,
"0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
"0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
"[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -850,7 +854,7 @@
#[cfg(target_pointer_width = "16")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+ uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
widening_impl! { usize, u32, 16, unsigned }
@@ -858,7 +862,7 @@
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+ uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
widening_impl! { usize, u64, 32, unsigned }
@@ -867,7 +871,7 @@
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+ uint_impl! { usize, u64, isize, NonZeroUsize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 8f895c3..1ebd1c5 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -302,7 +302,7 @@
// A bunch of methods for unsigned nonzero types only.
macro_rules! nonzero_unsigned_operations {
- ( $( $Ty: ident($Int: ty); )+ ) => {
+ ( $( $Ty: ident($Int: ident); )+ ) => {
$(
impl $Ty {
/// Add an unsigned integer to a non-zero value.
@@ -442,6 +442,56 @@
None
}
}
+
+ /// Returns the base 2 logarithm of the number, rounded down.
+ ///
+ /// This is the same operation as
+ #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+ /// except that it has no failure cases to worry about
+ /// since this value can never be zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(int_log)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+ /// ```
+ #[unstable(feature = "int_log", issue = "70887")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn log2(self) -> u32 {
+ <$Int>::BITS - 1 - self.leading_zeros()
+ }
+
+ /// Returns the base 10 logarithm of the number, rounded down.
+ ///
+ /// This is the same operation as
+ #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+ /// except that it has no failure cases to worry about
+ /// since this value can never be zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(int_log)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+ /// ```
+ #[unstable(feature = "int_log", issue = "70887")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn log10(self) -> u32 {
+ super::int_log10::$Int(self.0)
+ }
}
)+
}
@@ -922,6 +972,7 @@
/// ```
#[must_use]
#[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
+ #[rustc_const_stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
#[inline]
pub const fn is_power_of_two(self) -> bool {
// LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs
index d9b14c8..8982473 100644
--- a/library/core/src/num/saturating.rs
+++ b/library/core/src/num/saturating.rs
@@ -226,6 +226,15 @@
}
forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl AddAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn add_assign(&mut self, other: $t) {
+ *self = *self + Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl Sub for Saturating<$t> {
type Output = Saturating<$t>;
@@ -247,6 +256,15 @@
}
forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl SubAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn sub_assign(&mut self, other: $t) {
+ *self = *self - Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl Mul for Saturating<$t> {
type Output = Saturating<$t>;
@@ -268,6 +286,15 @@
}
forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl MulAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn mul_assign(&mut self, other: $t) {
+ *self = *self * Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t }
+
/// # Examples
///
/// Basic usage:
@@ -299,6 +326,7 @@
forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>,
#[unstable(feature = "saturating_int_impl", issue = "87920")] }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl DivAssign for Saturating<$t> {
#[inline]
@@ -308,6 +336,15 @@
}
forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl DivAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn div_assign(&mut self, other: $t) {
+ *self = *self / Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl Rem for Saturating<$t> {
type Output = Saturating<$t>;
@@ -329,6 +366,15 @@
}
forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl RemAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn rem_assign(&mut self, other: $t) {
+ *self = *self % Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl Not for Saturating<$t> {
type Output = Saturating<$t>;
@@ -362,6 +408,15 @@
}
forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl BitXorAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn bitxor_assign(&mut self, other: $t) {
+ *self = *self ^ Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl BitOr for Saturating<$t> {
type Output = Saturating<$t>;
@@ -383,6 +438,15 @@
}
forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl BitOrAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn bitor_assign(&mut self, other: $t) {
+ *self = *self | Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t }
+
#[unstable(feature = "saturating_int_impl", issue = "87920")]
impl BitAnd for Saturating<$t> {
type Output = Saturating<$t>;
@@ -404,6 +468,15 @@
}
forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> }
+ #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+ impl BitAndAssign<$t> for Saturating<$t> {
+ #[inline]
+ fn bitand_assign(&mut self, other: $t) {
+ *self = *self & Saturating(other);
+ }
+ }
+ forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t }
+
)*)
}
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 3cc454b..feec448 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1,5 +1,6 @@
macro_rules! uint_impl {
- ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr,
+ ($SelfT:ty, $ActualT:ident, $SignedT:ident, $NonZeroT:ident,
+ $BITS:expr, $MaxV:expr,
$rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
@@ -16,7 +17,7 @@
pub const MIN: Self = 0;
/// The largest value that can be represented by this integer type,
- #[doc = concat!("2<sup>", $BITS, "</sup> - 1.")]
+ #[doc = concat!("2<sup>", $BITS, "</sup> − 1.")]
///
/// # Examples
///
@@ -839,12 +840,10 @@
without modifying the original"]
#[inline]
pub const fn checked_log2(self) -> Option<u32> {
- if self <= 0 {
- None
+ if let Some(x) = <$NonZeroT>::new(self) {
+ Some(x.log2())
} else {
- // SAFETY: We just checked that this number is positive
- let log = (Self::BITS - 1) - unsafe { intrinsics::ctlz_nonzero(self) as u32 };
- Some(log)
+ None
}
}
@@ -863,7 +862,11 @@
without modifying the original"]
#[inline]
pub const fn checked_log10(self) -> Option<u32> {
- int_log10::$ActualT(self as $ActualT)
+ if let Some(x) = <$NonZeroT>::new(self) {
+ Some(x.log10())
+ } else {
+ None
+ }
}
/// Checked negation. Computes `-self`, returning `None` unless `self ==
@@ -1129,6 +1132,7 @@
///
/// ```
#[stable(feature = "saturating_div", since = "1.58.0")]
+ #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1631,11 +1635,11 @@
/// Basic usage:
///
/// ```
- /// #![feature(int_abs_diff)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($SelfT), ");")]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($SelfT), ");")]
/// ```
- #[unstable(feature = "int_abs_diff", issue = "89492")]
+ #[stable(feature = "int_abs_diff", since = "1.60.0")]
+ #[rustc_const_stable(feature = "int_abs_diff", since = "1.60.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -2323,8 +2327,6 @@
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
@@ -2354,8 +2356,6 @@
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
@@ -2396,8 +2396,6 @@
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index a0e42c5..5353d90 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -239,6 +239,16 @@
}
forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const AddAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn add_assign(&mut self, other: $t) {
+ *self = *self + Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Sub for Wrapping<$t> {
@@ -262,6 +272,16 @@
}
forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const SubAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn sub_assign(&mut self, other: $t) {
+ *self = *self - Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Mul for Wrapping<$t> {
@@ -285,6 +305,16 @@
}
forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const MulAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn mul_assign(&mut self, other: $t) {
+ *self = *self * Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, $t }
+
#[stable(feature = "wrapping_div", since = "1.3.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Div for Wrapping<$t> {
@@ -308,6 +338,16 @@
}
forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const DivAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn div_assign(&mut self, other: $t) {
+ *self = *self / Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, $t }
+
#[stable(feature = "wrapping_impls", since = "1.7.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Rem for Wrapping<$t> {
@@ -331,6 +371,16 @@
}
forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const RemAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn rem_assign(&mut self, other: $t) {
+ *self = *self % Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Not for Wrapping<$t> {
@@ -367,6 +417,16 @@
}
forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXorAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn bitxor_assign(&mut self, other: $t) {
+ *self = *self ^ Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const BitOr for Wrapping<$t> {
@@ -390,6 +450,16 @@
}
forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn bitor_assign(&mut self, other: $t) {
+ *self = *self | Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const BitAnd for Wrapping<$t> {
@@ -413,6 +483,16 @@
}
forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAndAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn bitand_assign(&mut self, other: $t) {
+ *self = *self & Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, $t }
+
#[stable(feature = "wrapping_neg", since = "1.10.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Neg for Wrapping<$t> {
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index e954742..e367be8 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -65,11 +65,36 @@
/// ```
#[lang = "add"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
- on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
- on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
- message = "cannot add `{Rhs}` to `{Self}`",
- label = "no implementation for `{Self} + {Rhs}`"
+#[cfg_attr(
+ bootstrap,
+ rustc_on_unimplemented(
+ on(
+ all(_Self = "{integer}", Rhs = "{float}"),
+ message = "cannot add a float to an integer",
+ ),
+ on(
+ all(_Self = "{float}", Rhs = "{integer}"),
+ message = "cannot add an integer to a float",
+ ),
+ message = "cannot add `{Rhs}` to `{Self}`",
+ label = "no implementation for `{Self} + {Rhs}`"
+ )
+)]
+#[cfg_attr(
+ not(bootstrap),
+ rustc_on_unimplemented(
+ on(
+ all(_Self = "{integer}", Rhs = "{float}"),
+ message = "cannot add a float to an integer",
+ ),
+ on(
+ all(_Self = "{float}", Rhs = "{integer}"),
+ message = "cannot add an integer to a float",
+ ),
+ message = "cannot add `{Rhs}` to `{Self}`",
+ label = "no implementation for `{Self} + {Rhs}`",
+ append_const_msg,
+ )
)]
#[doc(alias = "+")]
pub trait Add<Rhs = Self> {
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index 255f6cb..7c66422 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -68,6 +68,17 @@
not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
+#[stable(feature = "not_never", since = "1.60.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+impl const Not for ! {
+ type Output = !;
+
+ #[inline]
+ fn not(self) -> ! {
+ match self {}
+ }
+}
+
/// The bitwise AND operator `&`.
///
/// Note that `Rhs` is `Self` by default, but this is not mandatory.
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index 10a24a5..e34e267 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -134,7 +134,6 @@
/// # Examples
///
/// ```
- /// #![feature(control_flow_enum)]
/// use std::ops::ControlFlow;
///
/// assert!(ControlFlow::<i32, String>::Break(3).is_break());
@@ -151,7 +150,6 @@
/// # Examples
///
/// ```
- /// #![feature(control_flow_enum)]
/// use std::ops::ControlFlow;
///
/// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 6a414ae..ba369e7 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -302,6 +302,7 @@
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
),
)]
+#[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type.
@@ -359,6 +360,14 @@
#[repr(transparent)]
pub(crate) struct NeverShortCircuit<T>(pub T);
+impl<T> NeverShortCircuit<T> {
+ /// Wrap a binary `FnMut` to return its result wrapped in a `NeverShortCircuit`.
+ #[inline]
+ pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
+ move |a, b| NeverShortCircuit(f(a, b))
+ }
+}
+
pub(crate) enum NeverShortCircuitResidual {}
impl<T> Try for NeverShortCircuit<T> {
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 1ec119a..508837f 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -270,7 +270,7 @@
//! let mut bt = BTreeMap::new();
//! bt.insert(20u8, "foo");
//! bt.insert(42u8, "bar");
-//! let res = vec![0u8, 1, 11, 200, 22]
+//! let res = [0u8, 1, 11, 200, 22]
//! .into_iter()
//! .map(|x| {
//! // `checked_sub()` returns `None` on error
@@ -390,10 +390,10 @@
//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E
//!
//! ```
-//! let v = vec![Some(2), Some(4), None, Some(8)];
+//! let v = [Some(2), Some(4), None, Some(8)];
//! let res: Option<Vec<_>> = v.into_iter().collect();
//! assert_eq!(res, None);
-//! let v = vec![Some(2), Some(4), Some(8)];
+//! let v = [Some(2), Some(4), Some(8)];
//! let res: Option<Vec<_>> = v.into_iter().collect();
//! assert_eq!(res, Some(vec![2, 4, 8]));
//! ```
@@ -407,10 +407,10 @@
//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E
//!
//! ```
-//! let v = vec![None, Some(1), Some(2), Some(3)];
+//! let v = [None, Some(1), Some(2), Some(3)];
//! let res: Option<i32> = v.into_iter().sum();
//! assert_eq!(res, None);
-//! let v = vec![Some(1), Some(2), Some(21)];
+//! let v = [Some(1), Some(2), Some(21)];
//! let res: Option<i32> = v.into_iter().product();
//! assert_eq!(res, Some(42));
//! ```
@@ -500,7 +500,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::iter::{FromIterator, FusedIterator, TrustedLen};
+use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
use crate::panicking::{panic, panic_str};
use crate::pin::Pin;
use crate::{
@@ -551,6 +551,29 @@
matches!(*self, Some(_))
}
+ /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_some_with)]
+ ///
+ /// let x: Option<u32> = Some(2);
+ /// assert_eq!(x.is_some_with(|&x| x > 1), true);
+ ///
+ /// let x: Option<u32> = Some(0);
+ /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+ ///
+ /// let x: Option<u32> = None;
+ /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "is_some_with", issue = "93050")]
+ pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+ matches!(self, Some(x) if f(x))
+ }
+
/// Returns `true` if the option is a [`None`] value.
///
/// # Examples
@@ -1184,13 +1207,25 @@
/// # Examples
///
/// ```
- /// fn sq(x: u32) -> Option<u32> { Some(x * x) }
- /// fn nope(_: u32) -> Option<u32> { None }
+ /// fn sq_then_to_string(x: u32) -> Option<String> {
+ /// x.checked_mul(x).map(|sq| sq.to_string())
+ /// }
///
- /// assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
- /// assert_eq!(Some(2).and_then(sq).and_then(nope), None);
- /// assert_eq!(Some(2).and_then(nope).and_then(sq), None);
- /// assert_eq!(None.and_then(sq).and_then(sq), None);
+ /// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
+ /// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
+ /// assert_eq!(None.and_then(sq_then_to_string), None);
+ /// ```
+ ///
+ /// Often used to chain fallible operations that may return [`None`].
+ ///
+ /// ```
+ /// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
+ ///
+ /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
+ /// assert_eq!(item_0_1, Some(&"A1"));
+ ///
+ /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
+ /// assert_eq!(item_2_0, None);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2210,7 +2245,7 @@
// FIXME(#11084): This could be replaced with Iterator::scan when this
// performance bug is closed.
- iter.into_iter().map(|x| x.ok_or(())).collect::<Result<_, _>>().ok()
+ iter::try_process(iter.into_iter(), |i| i.collect())
}
}
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index d8e421d..be8598f 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -31,6 +31,7 @@
payload: &'a (dyn Any + Send),
message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>,
+ can_unwind: bool,
}
impl<'a> PanicInfo<'a> {
@@ -44,9 +45,10 @@
pub fn internal_constructor(
message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>,
+ can_unwind: bool,
) -> Self {
struct NoPayload;
- PanicInfo { location, message, payload: &NoPayload }
+ PanicInfo { location, message, payload: &NoPayload, can_unwind }
}
#[unstable(
@@ -127,6 +129,22 @@
// deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
Some(&self.location)
}
+
+ /// Returns whether the panic handler is allowed to unwind the stack from
+ /// the point where the panic occurred.
+ ///
+ /// This is true for most kinds of panics with the exception of panics
+ /// caused by trying to unwind out of a `Drop` implementation or a function
+ /// whose ABI does not support unwinding.
+ ///
+ /// It is safe for a panic handler to unwind even when this function returns
+ /// true, however this will simply cause the panic handler to be called
+ /// again.
+ #[must_use]
+ #[unstable(feature = "panic_can_unwind", issue = "92988")]
+ pub fn can_unwind(&self) -> bool {
+ self.can_unwind
+ }
}
#[stable(feature = "panic_hook_display", since = "1.26.0")]
diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
index 092b7cf..95be879 100644
--- a/library/core/src/panic/unwind_safe.rs
+++ b/library/core/src/panic/unwind_safe.rs
@@ -1,10 +1,10 @@
+use crate::async_iter::AsyncIterator;
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::future::Future;
use crate::ops::{Deref, DerefMut};
use crate::pin::Pin;
use crate::ptr::{NonNull, Unique};
-use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A marker trait which represents "panic safe" types in Rust.
@@ -290,8 +290,8 @@
}
}
-#[unstable(feature = "async_stream", issue = "79024")]
-impl<S: Stream> Stream for AssertUnwindSafe<S> {
+#[unstable(feature = "async_iterator", issue = "79024")]
+impl<S: AsyncIterator> AsyncIterator for AssertUnwindSafe<S> {
type Item = S::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 422f0e1..0798076 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -68,6 +68,7 @@
#[track_caller]
#[lang = "panic_display"] // needed for const-evaluated panics
#[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("{}", *x));
}
@@ -84,6 +85,31 @@
panic!("index out of bounds: the len is {} but the index is {}", len, index)
}
+#[cfg(not(bootstrap))]
+#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[track_caller]
+#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
+fn panic_no_unwind() -> ! {
+ if cfg!(feature = "panic_immediate_abort") {
+ super::intrinsics::abort()
+ }
+
+ // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
+ // that gets resolved to the `#[panic_handler]` function.
+ extern "Rust" {
+ #[lang = "panic_impl"]
+ fn panic_impl(pi: &PanicInfo<'_>) -> !;
+ }
+
+ // PanicInfo with the `can_unwind` flag set to false forces an abort.
+ let fmt = format_args!("panic in a function that cannot unwind");
+ let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
+
+ // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
+ unsafe { panic_impl(&pi) }
+}
+
/// The entry point for panicking with a formatted message.
///
/// This is designed to reduce the amount of code required at the call
@@ -98,6 +124,7 @@
#[track_caller]
#[lang = "panic_fmt"] // needed for const-evaluated panics
#[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
@@ -110,7 +137,7 @@
fn panic_impl(pi: &PanicInfo<'_>) -> !;
}
- let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller());
+ let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
unsafe { panic_impl(&pi) }
@@ -118,6 +145,7 @@
/// This function is used instead of panic_fmt in const eval.
#[lang = "const_panic_fmt"]
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if let Some(msg) = fmt.as_str() {
panic_str(msg);
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 09fc6df..dec1b52 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -406,7 +406,14 @@
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct Pin<P> {
- pointer: P,
+ // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to:
+ // - deter downstream users from accessing it (which would be unsound!),
+ // - let the `pin!` macro access it (such a macro requires using struct
+ // literal syntax in order to benefit from lifetime extension).
+ // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives.
+ #[unstable(feature = "unsafe_pin_internals", issue = "none")]
+ #[doc(hidden)]
+ pub pointer: P,
}
// The following implementations aren't derived in order to avoid soundness
@@ -909,3 +916,243 @@
#[stable(feature = "pin", since = "1.33.0")]
impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
+
+/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2].
+///
+/// Unlike [`Box::pin`], this does not involve a heap allocation.
+///
+/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this
+/// effectively pins the `value` in memory, where it will be unable to be moved.
+/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such
+/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore,
+/// moving it.
+/// See [the `Unpin` section of the `pin` module][self#unpin] for more info.
+///
+/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located
+/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside
+/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing
+/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by
+/// the `Generator`—, and thus will be stored wherever that one is.
+///
+/// ## Examples
+///
+/// ### Basic usage
+///
+/// ```rust
+/// #![feature(pin_macro)]
+/// # use core::marker::PhantomPinned as Foo;
+/// use core::pin::{pin, Pin};
+///
+/// fn stuff(foo: Pin<&mut Foo>) {
+/// // …
+/// # let _ = foo;
+/// }
+///
+/// let pinned_foo = pin!(Foo { /* … */ });
+/// stuff(pinned_foo);
+/// // or, directly:
+/// stuff(pin!(Foo { /* … */ }));
+/// ```
+///
+/// ### Manually polling a `Future` (wihout `Unpin` bounds)
+///
+/// ```rust
+/// #![feature(pin_macro)]
+/// use std::{
+/// future::Future,
+/// pin::pin,
+/// task::{Context, Poll},
+/// thread,
+/// };
+/// # use std::{sync::Arc, task::Wake, thread::Thread};
+///
+/// # /// A waker that wakes up the current thread when called.
+/// # struct ThreadWaker(Thread);
+/// #
+/// # impl Wake for ThreadWaker {
+/// # fn wake(self: Arc<Self>) {
+/// # self.0.unpark();
+/// # }
+/// # }
+/// #
+/// /// Runs a future to completion.
+/// fn block_on<Fut: Future>(fut: Fut) -> Fut::Output {
+/// let waker_that_unparks_thread = // …
+/// # Arc::new(ThreadWaker(thread::current())).into();
+/// let mut cx = Context::from_waker(&waker_that_unparks_thread);
+/// // Pin the future so it can be polled.
+/// let mut pinned_fut = pin!(fut);
+/// loop {
+/// match pinned_fut.as_mut().poll(&mut cx) {
+/// Poll::Pending => thread::park(),
+/// Poll::Ready(res) => return res,
+/// }
+/// }
+/// }
+/// #
+/// # assert_eq!(42, block_on(async { 42 }));
+/// ```
+///
+/// ### With `Generator`s
+///
+/// ```rust
+/// #![feature(generators, generator_trait, pin_macro)]
+/// use core::{
+/// ops::{Generator, GeneratorState},
+/// pin::pin,
+/// };
+///
+/// fn generator_fn() -> impl Generator<Yield = usize, Return = ()> /* not Unpin */ {
+/// // Allow generator to be self-referential (not `Unpin`)
+/// // vvvvvv so that locals can cross yield points.
+/// static || {
+/// let foo = String::from("foo"); // --+
+/// yield 0; // | <- crosses yield point!
+/// println!("{}", &foo); // <----------+
+/// yield foo.len();
+/// }
+/// }
+///
+/// fn main() {
+/// let mut generator = pin!(generator_fn());
+/// match generator.as_mut().resume(()) {
+/// GeneratorState::Yielded(0) => {},
+/// _ => unreachable!(),
+/// }
+/// match generator.as_mut().resume(()) {
+/// GeneratorState::Yielded(3) => {},
+/// _ => unreachable!(),
+/// }
+/// match generator.resume(()) {
+/// GeneratorState::Yielded(_) => unreachable!(),
+/// GeneratorState::Complete(()) => {},
+/// }
+/// }
+/// ```
+///
+/// ## Remarks
+///
+/// Precisely because a value is pinned to local storage, the resulting <code>[Pin]<[&mut] T></code>
+/// reference ends up borrowing a local tied to that block: it can't escape it.
+///
+/// The following, for instance, fails to compile:
+///
+/// ```rust,compile_fail
+/// #![feature(pin_macro)]
+/// use core::pin::{pin, Pin};
+/// # use core::{marker::PhantomPinned as Foo, mem::drop as stuff};
+///
+/// let x: Pin<&mut Foo> = {
+/// let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
+/// x
+/// }; // <- Foo is dropped
+/// stuff(x); // Error: use of dropped value
+/// ```
+///
+/// <details><summary>Error message</summary>
+///
+/// ```console
+/// error[E0716]: temporary value dropped while borrowed
+/// --> src/main.rs:9:28
+/// |
+/// 8 | let x: Pin<&mut Foo> = {
+/// | - borrow later stored here
+/// 9 | let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
+/// | ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+/// 10 | x
+/// 11 | }; // <- Foo is dropped
+/// | - temporary value is freed at the end of this statement
+/// |
+/// = note: consider using a `let` binding to create a longer lived value
+/// ```
+///
+/// </details>
+///
+/// This makes [`pin!`] **unsuitable to pin values when intending to _return_ them**. Instead, the
+/// value is expected to be passed around _unpinned_ until the point where it is to be consumed,
+/// where it is then useful and even sensible to pin the value locally using [`pin!`].
+///
+/// If you really need to return a pinned value, consider using [`Box::pin`] instead.
+///
+/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be
+/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not
+/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`]
+/// constructor.
+///
+/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
+#[unstable(feature = "pin_macro", issue = "93178")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(unsafe_pin_internals)]
+pub macro pin($value:expr $(,)?) {
+ // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's
+ // review such a hypothetical macro (that any user-code could define):
+ //
+ // ```rust
+ // macro_rules! pin {( $value:expr ) => (
+ // match &mut { $value } { at_value => unsafe { // Do not wrap `$value` in an `unsafe` block.
+ // $crate::pin::Pin::<&mut _>::new_unchecked(at_value)
+ // }}
+ // )}
+ // ```
+ //
+ // Safety:
+ // - `type P = &mut _`. There are thus no pathological `Deref{,Mut}` impls
+ // that would break `Pin`'s invariants.
+ // - `{ $value }` is braced, making it a _block expression_, thus **moving**
+ // the given `$value`, and making it _become an **anonymous** temporary_.
+ // By virtue of being anonynomous, it can no longer be accessed, thus
+ // preventing any attemps to `mem::replace` it or `mem::forget` it, _etc._
+ //
+ // This gives us a `pin!` definition that is sound, and which works, but only
+ // in certain scenarios:
+ // - If the `pin!(value)` expression is _directly_ fed to a function call:
+ // `let poll = pin!(fut).poll(cx);`
+ // - If the `pin!(value)` expression is part of a scrutinee:
+ // ```rust
+ // match pin!(fut) { pinned_fut => {
+ // pinned_fut.as_mut().poll(...);
+ // pinned_fut.as_mut().poll(...);
+ // }} // <- `fut` is dropped here.
+ // ```
+ // Alas, it doesn't work for the more straight-forward use-case: `let` bindings.
+ // ```rust
+ // let pinned_fut = pin!(fut); // <- temporary value is freed at the end of this statement
+ // pinned_fut.poll(...) // error[E0716]: temporary value dropped while borrowed
+ // // note: consider using a `let` binding to create a longer lived value
+ // ```
+ // - Issues such as this one are the ones motivating https://github.com/rust-lang/rfcs/pull/66
+ //
+ // This makes such a macro incredibly unergonomic in practice, and the reason most macros
+ // out there had to take the path of being a statement/binding macro (_e.g._, `pin!(future);`)
+ // instead of featuring the more intuitive ergonomics of an expression macro.
+ //
+ // Luckily, there is a way to avoid the problem. Indeed, the problem stems from the fact that a
+ // temporary is dropped at the end of its enclosing statement when it is part of the parameters
+ // given to function call, which has precisely been the case with our `Pin::new_unchecked()`!
+ // For instance,
+ // ```rust
+ // let p = Pin::new_unchecked(&mut <temporary>);
+ // ```
+ // becomes:
+ // ```rust
+ // let p = { let mut anon = <temporary>; &mut anon };
+ // ```
+ //
+ // However, when using a literal braced struct to construct the value, references to temporaries
+ // can then be taken. This makes Rust change the lifespan of such temporaries so that they are,
+ // instead, dropped _at the end of the enscoping block_.
+ // For instance,
+ // ```rust
+ // let p = Pin { pointer: &mut <temporary> };
+ // ```
+ // becomes:
+ // ```rust
+ // let mut anon = <temporary>;
+ // let p = Pin { pointer: &mut anon };
+ // ```
+ // which is *exactly* what we want.
+ //
+ // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension
+ // for more info.
+ $crate::pin::Pin::<&mut _> { pointer: &mut { $value } }
+}
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 0fb8846..b566e21 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -56,8 +56,8 @@
#[doc(no_inline)]
pub use crate::{
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
- format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
- option_env, stringify, trace_macros,
+ format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
+ stringify, trace_macros,
};
#[unstable(
@@ -65,7 +65,6 @@
issue = "87555",
reason = "`concat_bytes` is not stable enough for use and is subject to change"
)]
-#[cfg(not(bootstrap))]
#[doc(no_inline)]
pub use crate::concat_bytes;
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 8fcd8cd..ebb1d89 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -275,20 +275,69 @@
mod prim_never {}
#[doc(primitive = "char")]
+#[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type.
///
/// The `char` type represents a single character. More specifically, since
/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
-/// scalar value]', which is similar to, but not the same as, a '[Unicode code
-/// point]'.
-///
-/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
-/// [Unicode code point]: https://www.unicode.org/glossary/#code_point
+/// scalar value]'.
///
/// This documentation describes a number of methods and trait implementations on the
/// `char` type. For technical reasons, there is additional, separate
/// documentation in [the `std::char` module](char/index.html) as well.
///
+/// # Validity
+///
+/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]'
+/// other than a [surrogate code point]. This has a fixed numerical definition:
+/// code points are in the range 0 to 0x10FFFF, inclusive.
+/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF.
+///
+/// No `char` may be constructed, whether as a literal or at runtime, that is not a
+/// Unicode scalar value:
+///
+/// ```compile_fail
+/// // Each of these is a compiler error
+/// ['\u{D800}', '\u{DFFF}', '\u{110000}'];
+/// ```
+///
+/// ```should_panic
+/// // Panics; from_u32 returns None.
+/// char::from_u32(0xDE01).unwrap();
+/// ```
+///
+/// ```no_run
+/// // Undefined behaviour
+/// unsafe { char::from_u32_unchecked(0x110000) };
+/// ```
+///
+/// USVs are also the exact set of values that may be encoded in UTF-8. Because
+/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store
+/// any `char` in a `str` or read any character from a `str` as a `char`.
+///
+/// The gap in valid `char` values is understood by the compiler, so in the
+/// below example the two ranges are understood to cover the whole range of
+/// possible `char` values and there is no error for a [non-exhaustive match].
+///
+/// ```
+/// let c: char = 'a';
+/// match c {
+/// '\0' ..= '\u{D7FF}' => false,
+/// '\u{E000}' ..= '\u{10FFFF}' => true,
+/// };
+/// ```
+///
+/// All USVs are valid `char` values, but not all of them represent a real
+/// character. Many USVs are not currently assigned to a character, but may be
+/// in the future ("reserved"); some will never be a character
+/// ("noncharacters"); and some may be given different meanings by different
+/// users ("private use").
+///
+/// [Unicode code point]: https://www.unicode.org/glossary/#code_point
+/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
+/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive
+/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point
+///
/// # Representation
///
/// `char` is always four bytes in size. This is a different representation than
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index a93327a..485a596 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -48,6 +48,16 @@
self as _
}
+ /// Changes constness without changing the type.
+ ///
+ /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
+ /// refactored.
+ #[unstable(feature = "ptr_const_cast", issue = "92675")]
+ #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+ pub const fn as_mut(self) -> *mut T {
+ self as _
+ }
+
/// Casts a pointer to its raw bits.
///
/// This is equivalent to `as usize`, but is more specific to enhance readability.
@@ -429,7 +439,7 @@
/// }
/// ```
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
+ #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
#[inline]
pub const unsafe fn offset_from(self, origin: *const T) -> isize
where
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 5fd3b2e..1412e83 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -47,6 +47,20 @@
self as _
}
+ /// Changes constness without changing the type.
+ ///
+ /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
+ /// refactored.
+ ///
+ /// While not strictly required (`*mut T` coerces to `*const T`), this is provided for symmetry
+ /// with `as_mut()` on `*const T` and may have documentation value if used instead of implicit
+ /// coercion.
+ #[unstable(feature = "ptr_const_cast", issue = "92675")]
+ #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+ pub const fn as_const(self) -> *const T {
+ self as _
+ }
+
/// Casts a pointer to its raw bits.
///
/// This is equivalent to `as usize`, but is more specific to enhance readability.
@@ -603,7 +617,7 @@
/// }
/// ```
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
+ #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
#[inline(always)]
pub const unsafe fn offset_from(self, origin: *const T) -> isize
where
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 3a7e99f..0aa8e99 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -211,8 +211,9 @@
/// }
/// ```
#[stable(feature = "nonnull", since = "1.25.0")]
+ #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")]
#[inline]
- pub fn new(ptr: *mut T) -> Option<Self> {
+ pub const fn new(ptr: *mut T) -> Option<Self> {
if !ptr.is_null() {
// SAFETY: The pointer is already checked and is not null
Some(unsafe { Self::new_unchecked(ptr) })
@@ -720,6 +721,9 @@
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T: ?Sized> const From<&mut T> for NonNull<T> {
+ /// Converts a `&mut T` to a `NonNull<T>`.
+ ///
+ /// This conversion is safe and infallible since references cannot be null.
#[inline]
fn from(reference: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null.
@@ -730,6 +734,9 @@
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T: ?Sized> const From<&T> for NonNull<T> {
+ /// Converts a `&T` to a `NonNull<T>`.
+ ///
+ /// This conversion is safe and infallible since references cannot be null.
#[inline]
fn from(reference: &T) -> Self {
// SAFETY: A reference cannot be null, so the conditions for
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index f5c624c..661d111 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -178,6 +178,9 @@
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: ?Sized> const From<&mut T> for Unique<T> {
+ /// Converts a `&mut T` to a `Unique<T>`.
+ ///
+ /// This conversion is infallible since references cannot be null.
#[inline]
fn from(reference: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 575fd2b..801e3a0 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -436,7 +436,7 @@
//! # use std::str::FromStr;
//! let mut results = vec![];
//! let mut errs = vec![];
-//! let nums: Vec<_> = vec!["17", "not a number", "99", "-27", "768"]
+//! let nums: Vec<_> = ["17", "not a number", "99", "-27", "768"]
//! .into_iter()
//! .map(u8::from_str)
//! // Save clones of the raw `Result` values to inspect
@@ -462,10 +462,10 @@
//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E
//!
//! ```
-//! let v = vec![Ok(2), Ok(4), Err("err!"), Ok(8)];
+//! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)];
//! let res: Result<Vec<_>, &str> = v.into_iter().collect();
//! assert_eq!(res, Err("err!"));
-//! let v = vec![Ok(2), Ok(4), Ok(8)];
+//! let v = [Ok(2), Ok(4), Ok(8)];
//! let res: Result<Vec<_>, &str> = v.into_iter().collect();
//! assert_eq!(res, Ok(vec![2, 4, 8]));
//! ```
@@ -479,10 +479,10 @@
//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E
//!
//! ```
-//! let v = vec![Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
+//! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
//! let res: Result<i32, &str> = v.into_iter().sum();
//! assert_eq!(res, Err("error!"));
-//! let v: Vec<Result<i32, &str>> = vec![Ok(1), Ok(2), Ok(21)];
+//! let v = [Ok(1), Ok(2), Ok(21)];
//! let res: Result<i32, &str> = v.into_iter().product();
//! assert_eq!(res, Ok(42));
//! ```
@@ -542,6 +542,29 @@
matches!(*self, Ok(_))
}
+ /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_some_with)]
+ ///
+ /// let x: Result<u32, &str> = Ok(2);
+ /// assert_eq!(x.is_ok_with(|&x| x > 1), true);
+ ///
+ /// let x: Result<u32, &str> = Ok(0);
+ /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+ ///
+ /// let x: Result<u32, &str> = Err("hey");
+ /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "is_some_with", issue = "93050")]
+ pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+ matches!(self, Ok(x) if f(x))
+ }
+
/// Returns `true` if the result is [`Err`].
///
/// # Examples
@@ -563,6 +586,30 @@
!self.is_ok()
}
+ /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_some_with)]
+ /// use std::io::{Error, ErrorKind};
+ ///
+ /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
+ /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true);
+ ///
+ /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));
+ /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+ ///
+ /// let x: Result<u32, Error> = Ok(123);
+ /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "is_some_with", issue = "93050")]
+ pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
+ matches!(self, Err(x) if f(x))
+ }
+
/////////////////////////////////////////////////////////////////////////
// Adapter for each variant
/////////////////////////////////////////////////////////////////////////
@@ -1234,16 +1281,28 @@
///
/// # Examples
///
- /// Basic usage:
+ /// ```
+ /// fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
+ /// x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
+ /// }
+ ///
+ /// assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
+ /// assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
+ /// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
+ /// ```
+ ///
+ /// Often used to chain fallible operations that may return [`Err`].
///
/// ```
- /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
- /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
+ /// use std::{io::ErrorKind, path::Path};
///
- /// assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
- /// assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
- /// assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
- /// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
+ /// // Note: on Windows "/" maps to "C:\"
+ /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
+ /// assert!(root_modified_time.is_ok());
+ ///
+ /// let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
+ /// assert!(should_fail.is_err());
+ /// assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1969,7 +2028,7 @@
// FIXME(#11084): This could be replaced with Iterator::scan when this
// performance bug is closed.
- iter::process_results(iter.into_iter(), |i| i.collect())
+ iter::try_process(iter.into_iter(), |i| i.collect())
}
}
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 080256f..304ba7e 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -68,7 +68,6 @@
/// # Examples
///
/// ```
- /// #![feature(inherent_ascii_escape)]
///
/// let s = b"0\t\r\n'\"\\\x9d";
/// let escaped = s.escape_ascii().to_string();
@@ -76,7 +75,7 @@
/// ```
#[must_use = "this returns the escaped bytes as an iterator, \
without modifying the original"]
- #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+ #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub fn escape_ascii(&self) -> EscapeAscii<'_> {
EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
}
@@ -93,13 +92,13 @@
///
/// This `struct` is created by the [`slice::escape_ascii`] method. See its
/// documentation for more information.
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
#[derive(Clone)]
pub struct EscapeAscii<'a> {
inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::Iterator for EscapeAscii<'a> {
type Item = u8;
#[inline]
@@ -131,23 +130,23 @@
}
}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
fn next_back(&mut self) -> Option<u8> {
self.inner.next_back()
}
}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> fmt::Display for EscapeAscii<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.clone().try_for_each(|b| f.write_char(b as char))
}
}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> fmt::Debug for EscapeAscii<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EscapeAscii").finish_non_exhaustive()
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 72af47c..27c6b6f 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -1,7 +1,6 @@
//! Comparison traits for `[T]`.
-use crate::cmp;
-use crate::cmp::Ordering::{self, Greater, Less};
+use crate::cmp::{self, Ordering};
use crate::mem;
use super::from_raw_parts;
@@ -189,18 +188,18 @@
impl SliceOrd for u8 {
#[inline]
fn compare(left: &[Self], right: &[Self]) -> Ordering {
- let order =
- // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
- // We use the minimum of both lengths which guarantees that both regions are
- // valid for reads in that interval.
- unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
+ // Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
+ let diff = left.len() as isize - right.len() as isize;
+ // This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
+ let len = if left.len() < right.len() { left.len() } else { right.len() };
+ // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
+ // We use the minimum of both lengths which guarantees that both regions are
+ // valid for reads in that interval.
+ let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize };
if order == 0 {
- left.len().cmp(&right.len())
- } else if order < 0 {
- Less
- } else {
- Greater
+ order = diff;
}
+ order.cmp(&0)
}
}
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 176820e..d260cc6 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -1476,7 +1476,21 @@
} else {
let remainder = self.v.len() % self.chunk_size;
let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
- let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
+ // SAFETY: split_at_unchecked requires the argument be less than or
+ // equal to the length. This is guaranteed, but subtle: `chunksz`
+ // will always either be `self.v.len() % self.chunk_size`, which
+ // will always evaluate to strictly less than `self.v.len()` (or
+ // panic, in the case that `self.chunk_size` is zero), or it can be
+ // `self.chunk_size`, in the case that the length is exactly
+ // divisible by the chunk size.
+ //
+ // While it seems like using `self.chunk_size` in this case could
+ // lead to a value greater than `self.v.len()`, it cannot: if
+ // `self.chunk_size` were greater than `self.v.len()`, then
+ // `self.v.len() % self.chunk_size` would return nonzero (note that
+ // in this branch of the `if`, we already know that `self.v` is
+ // non-empty).
+ let (fst, snd) = unsafe { self.v.split_at_unchecked(self.v.len() - chunksz) };
self.v = fst;
Some(snd)
}
@@ -1641,7 +1655,8 @@
let sz = if remainder != 0 { remainder } else { self.chunk_size };
let tmp = mem::replace(&mut self.v, &mut []);
let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - sz);
+ // SAFETY: Similar to `Chunks::next_back`
+ let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
self.v = head;
Some(tail)
}
@@ -2410,8 +2425,14 @@
if self.v.is_empty() {
None
} else {
- let chunksz = cmp::min(self.v.len(), self.chunk_size);
- let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
+ let len = self.v.len();
+ let chunksz = cmp::min(len, self.chunk_size);
+ // SAFETY: split_at_unchecked just requires the argument be less
+ // than the length. This could only happen if the expression `len -
+ // chunksz` overflows. This could only happen if `chunksz > len`,
+ // which is impossible as we initialize it as the `min` of `len` and
+ // `self.chunk_size`.
+ let (fst, snd) = unsafe { self.v.split_at_unchecked(len - chunksz) };
self.v = fst;
Some(snd)
}
@@ -2485,7 +2506,8 @@
} else {
let remainder = self.v.len() % self.chunk_size;
let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
- let (fst, snd) = self.v.split_at(chunksz);
+ // SAFETY: similar to Chunks::next_back
+ let (fst, snd) = unsafe { self.v.split_at_unchecked(chunksz) };
self.v = snd;
Some(fst)
}
@@ -2571,7 +2593,12 @@
let sz = cmp::min(self.v.len(), self.chunk_size);
let tmp = mem::replace(&mut self.v, &mut []);
let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - sz);
+ // SAFETY: split_at_mut_unchecked just requires the argument be less
+ // than the length. This could only happen if the expression
+ // `tmp_len - sz` overflows. This could only happen if `sz >
+ // tmp_len`, which is impossible as we initialize it as the `min` of
+ // `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`.
+ let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
self.v = head;
Some(tail)
}
@@ -2649,7 +2676,8 @@
let remainder = self.v.len() % self.chunk_size;
let sz = if remainder != 0 { remainder } else { self.chunk_size };
let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(sz);
+ // SAFETY: Similar to `Chunks::next_back`
+ let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) };
self.v = tail;
Some(head)
}
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 0599f27..cd38c3a 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -81,7 +81,7 @@
#[unstable(feature = "slice_range", issue = "76393")]
pub use index::range;
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub use ascii::EscapeAscii;
/// Calculates the direction and split point of a one-sided range.
@@ -2559,50 +2559,6 @@
}
/// Reorder the slice such that the element at `index` is at its final sorted position.
- #[unstable(feature = "slice_partition_at_index", issue = "55300")]
- #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable() instead")]
- #[inline]
- pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
- where
- T: Ord,
- {
- self.select_nth_unstable(index)
- }
-
- /// Reorder the slice with a comparator function such that the element at `index` is at its
- /// final sorted position.
- #[unstable(feature = "slice_partition_at_index", issue = "55300")]
- #[rustc_deprecated(since = "1.49.0", reason = "use select_nth_unstable_by() instead")]
- #[inline]
- pub fn partition_at_index_by<F>(
- &mut self,
- index: usize,
- compare: F,
- ) -> (&mut [T], &mut T, &mut [T])
- where
- F: FnMut(&T, &T) -> Ordering,
- {
- self.select_nth_unstable_by(index, compare)
- }
-
- /// Reorder the slice with a key extraction function such that the element at `index` is at its
- /// final sorted position.
- #[unstable(feature = "slice_partition_at_index", issue = "55300")]
- #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable_by_key() instead")]
- #[inline]
- pub fn partition_at_index_by_key<K, F>(
- &mut self,
- index: usize,
- f: F,
- ) -> (&mut [T], &mut T, &mut [T])
- where
- F: FnMut(&T) -> K,
- K: Ord,
- {
- self.select_nth_unstable_by_key(index, f)
- }
-
- /// Reorder the slice such that the element at `index` is at its final sorted position.
///
/// 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
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 8f58e88..2ba0e53 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -773,7 +773,7 @@
let mid = partition_equal(v, pivot, is_less);
// Continue sorting elements greater than the pivot.
- v = &mut { v }[mid..];
+ v = &mut v[mid..];
continue;
}
}
@@ -784,7 +784,7 @@
was_partitioned = was_p;
// Split the slice into `left`, `pivot`, and `right`.
- let (left, right) = { v }.split_at_mut(mid);
+ let (left, right) = v.split_at_mut(mid);
let (pivot, right) = right.split_at_mut(1);
let pivot = &pivot[0];
@@ -860,7 +860,7 @@
let (mid, _) = partition(v, pivot, is_less);
// Split the slice into `left`, `pivot`, and `right`.
- let (left, right) = { v }.split_at_mut(mid);
+ let (left, right) = v.split_at_mut(mid);
let (pivot, right) = right.split_at_mut(1);
let pivot = &pivot[0];
diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs
new file mode 100644
index 0000000..5abc2b3
--- /dev/null
+++ b/library/core/src/str/count.rs
@@ -0,0 +1,136 @@
+//! Code for efficiently counting the number of `char`s in a UTF-8 encoded
+//! string.
+//!
+//! Broadly, UTF-8 encodes `char`s as a "leading" byte which begins the `char`,
+//! followed by some number (possibly 0) of continuation bytes.
+//!
+//! The leading byte can have a number of bit-patterns (with the specific
+//! pattern indicating how many continuation bytes follow), but the continuation
+//! bytes are always in the format `0b10XX_XXXX` (where the `X`s can take any
+//! value). That is, the most significant bit is set, and the second most
+//! significant bit is unset.
+//!
+//! To count the number of characters, we can just count the number of bytes in
+//! the string which are not continuation bytes, which can be done many bytes at
+//! a time fairly easily.
+//!
+//! Note: Because the term "leading byte" can sometimes be ambiguous (for
+//! example, it could also refer to the first byte of a slice), we'll often use
+//! the term "non-continuation byte" to refer to these bytes in the code.
+use core::intrinsics::unlikely;
+
+const USIZE_SIZE: usize = core::mem::size_of::<usize>();
+const UNROLL_INNER: usize = 4;
+
+#[inline]
+pub(super) fn count_chars(s: &str) -> usize {
+ if s.len() < USIZE_SIZE * UNROLL_INNER {
+ // Avoid entering the optimized implementation for strings where the
+ // difference is not likely to matter, or where it might even be slower.
+ // That said, a ton of thought was not spent on the particular threshold
+ // here, beyond "this value seems to make sense".
+ char_count_general_case(s.as_bytes())
+ } else {
+ do_count_chars(s)
+ }
+}
+
+fn do_count_chars(s: &str) -> usize {
+ // For correctness, `CHUNK_SIZE` must be:
+ //
+ // - Less than or equal to 255, otherwise we'll overflow bytes in `counts`.
+ // - A multiple of `UNROLL_INNER`, otherwise our `break` inside the
+ // `body.chunks(CHUNK_SIZE)` loop is incorrect.
+ //
+ // For performance, `CHUNK_SIZE` should be:
+ // - Relatively cheap to `/` against (so some simple sum of powers of two).
+ // - Large enough to avoid paying for the cost of the `sum_bytes_in_usize`
+ // too often.
+ const CHUNK_SIZE: usize = 192;
+
+ // Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required
+ // for correctness.
+ const _: () = assert!(CHUNK_SIZE < 256);
+ const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0);
+
+ // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size
+ // differences which are handled by `align_to`.
+ let (head, body, tail) = unsafe { s.as_bytes().align_to::<usize>() };
+
+ // This should be quite rare, and basically exists to handle the degenerate
+ // cases where align_to fails (as well as miri under symbolic alignment
+ // mode).
+ //
+ // The `unlikely` helps discourage LLVM from inlining the body, which is
+ // nice, as we would rather not mark the `char_count_general_case` function
+ // as cold.
+ if unlikely(body.is_empty() || head.len() > USIZE_SIZE || tail.len() > USIZE_SIZE) {
+ return char_count_general_case(s.as_bytes());
+ }
+
+ let mut total = char_count_general_case(head) + char_count_general_case(tail);
+ // Split `body` into `CHUNK_SIZE` chunks to reduce the frequency with which
+ // we call `sum_bytes_in_usize`.
+ for chunk in body.chunks(CHUNK_SIZE) {
+ // We accumulate intermediate sums in `counts`, where each byte contains
+ // a subset of the sum of this chunk, like a `[u8; size_of::<usize>()]`.
+ let mut counts = 0;
+
+ let (unrolled_chunks, remainder) = chunk.as_chunks::<UNROLL_INNER>();
+ for unrolled in unrolled_chunks {
+ for &word in unrolled {
+ // Because `CHUNK_SIZE` is < 256, this addition can't cause the
+ // count in any of the bytes to overflow into a subsequent byte.
+ counts += contains_non_continuation_byte(word);
+ }
+ }
+
+ // Sum the values in `counts` (which, again, is conceptually a `[u8;
+ // size_of::<usize>()]`), and accumulate the result into `total`.
+ total += sum_bytes_in_usize(counts);
+
+ // If there's any data in `remainder`, then handle it. This will only
+ // happen for the last `chunk` in `body.chunks()` (because `CHUNK_SIZE`
+ // is divisible by `UNROLL_INNER`), so we explicitly break at the end
+ // (which seems to help LLVM out).
+ if !remainder.is_empty() {
+ // Accumulate all the data in the remainder.
+ let mut counts = 0;
+ for &word in remainder {
+ counts += contains_non_continuation_byte(word);
+ }
+ total += sum_bytes_in_usize(counts);
+ break;
+ }
+ }
+ total
+}
+
+// Checks each byte of `w` to see if it contains the first byte in a UTF-8
+// sequence. Bytes in `w` which are continuation bytes are left as `0x00` (e.g.
+// false), and bytes which are non-continuation bytes are left as `0x01` (e.g.
+// true)
+#[inline]
+fn contains_non_continuation_byte(w: usize) -> usize {
+ const LSB: usize = 0x0101_0101_0101_0101u64 as usize;
+ ((!w >> 7) | (w >> 6)) & LSB
+}
+
+// Morally equivalent to `values.to_ne_bytes().into_iter().sum::<usize>()`, but
+// more efficient.
+#[inline]
+fn sum_bytes_in_usize(values: usize) -> usize {
+ const LSB_SHORTS: usize = 0x0001_0001_0001_0001_u64 as usize;
+ const SKIP_BYTES: usize = 0x00ff_00ff_00ff_00ff_u64 as usize;
+
+ let pair_sum: usize = (values & SKIP_BYTES) + ((values >> 8) & SKIP_BYTES);
+ pair_sum.wrapping_mul(LSB_SHORTS) >> ((USIZE_SIZE - 2) * 8)
+}
+
+// This is the most direct implementation of the concept of "count the number of
+// bytes in the string which are not continuation bytes", and is used for the
+// head and tail of the input string (the first and last item in the tuple
+// returned by `slice::align_to`).
+fn char_count_general_case(s: &[u8]) -> usize {
+ s.iter().filter(|&&byte| !super::validations::utf8_is_cont_byte(byte)).count()
+}
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index de6e6d5..e529bcc 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -12,7 +12,7 @@
use super::from_utf8_unchecked;
use super::pattern::Pattern;
use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
-use super::validations::{next_code_point, next_code_point_reverse, utf8_is_cont_byte};
+use super::validations::{next_code_point, next_code_point_reverse};
use super::LinesAnyMap;
use super::{BytesIsNotEmpty, UnsafeBytesToStr};
use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode};
@@ -46,8 +46,7 @@
#[inline]
fn count(self) -> usize {
- // length in `char` is equal to the number of non-continuation bytes
- self.iter.filter(|&&byte| !utf8_is_cont_byte(byte)).count()
+ super::count::count_chars(self.as_str())
}
#[inline]
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 1d4600f..09709dc 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -7,6 +7,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
mod converts;
+mod count;
mod error;
mod iter;
mod traits;
@@ -75,15 +76,14 @@
use iter::SplitInternal;
use iter::{MatchesInternal, SplitNInternal};
-use validations::truncate_to_char_boundary;
-
#[inline(never)]
#[cold]
#[track_caller]
fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
const MAX_DISPLAY_LENGTH: usize = 256;
- let (truncated, s_trunc) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
- let ellipsis = if truncated { "[...]" } else { "" };
+ let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
+ let s_trunc = &s[..trunc_len];
+ let ellipsis = if trunc_len < s.len() { "[...]" } else { "" };
// 1. out of bounds
if begin > s.len() || end > s.len() {
@@ -104,10 +104,7 @@
// 3. character boundary
let index = if !s.is_char_boundary(begin) { begin } else { end };
// find the character
- let mut char_start = index;
- while !s.is_char_boundary(char_start) {
- char_start -= 1;
- }
+ let char_start = s.floor_char_boundary(index);
// `char_start` must be less than len and a char boundary
let ch = s[char_start..].chars().next().unwrap();
let char_range = char_start..char_start + ch.len_utf8();
@@ -214,8 +211,80 @@
// code on higher opt-levels. See PR #84751 for more details.
None => index == self.len(),
- // This is bit magic equivalent to: b < 128 || b >= 192
- Some(&b) => (b as i8) >= -0x40,
+ Some(&b) => b.is_utf8_char_boundary(),
+ }
+ }
+
+ /// Finds the closest `x` not exceeding `index` where `is_char_boundary(x)` is `true`.
+ ///
+ /// This method can help you truncate a string so that it's still valid UTF-8, but doesn't
+ /// exceed a given number of bytes. Note that this is done purely at the character level
+ /// and can still visually split graphemes, even though the underlying characters aren't
+ /// split. For example, the emoji 🧑🔬 (scientist) could be split so that the string only
+ /// includes 🧑 (person) instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(round_char_boundary)]
+ /// let s = "❤️🧡💛💚💙💜";
+ /// assert_eq!(s.len(), 26);
+ /// assert!(!s.is_char_boundary(13));
+ ///
+ /// let closest = s.floor_char_boundary(13);
+ /// assert_eq!(closest, 10);
+ /// assert_eq!(&s[..closest], "❤️🧡");
+ /// ```
+ #[unstable(feature = "round_char_boundary", issue = "93743")]
+ #[inline]
+ pub fn floor_char_boundary(&self, index: usize) -> usize {
+ if index >= self.len() {
+ self.len()
+ } else {
+ let lower_bound = index.saturating_sub(3);
+ let new_index = self.as_bytes()[lower_bound..=index]
+ .iter()
+ .rposition(|b| b.is_utf8_char_boundary());
+
+ // SAFETY: we know that the character boundary will be within four bytes
+ unsafe { lower_bound + new_index.unwrap_unchecked() }
+ }
+ }
+
+ /// Finds the closest `x` not below `index` where `is_char_boundary(x)` is `true`.
+ ///
+ /// This method is the natural complement to [`floor_char_boundary`]. See that method
+ /// for more details.
+ ///
+ /// [`floor_char_boundary`]: str::floor_char_boundary
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index > self.len()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(round_char_boundary)]
+ /// let s = "❤️🧡💛💚💙💜";
+ /// assert_eq!(s.len(), 26);
+ /// assert!(!s.is_char_boundary(13));
+ ///
+ /// let closest = s.ceil_char_boundary(13);
+ /// assert_eq!(closest, 14);
+ /// assert_eq!(&s[..closest], "❤️🧡💛");
+ /// ```
+ #[unstable(feature = "round_char_boundary", issue = "93743")]
+ #[inline]
+ pub fn ceil_char_boundary(&self, index: usize) -> usize {
+ if index > self.len() {
+ slice_error_fail(self, index, index)
+ } else {
+ let upper_bound = Ord::min(index + 4, self.len());
+ self.as_bytes()[index..upper_bound]
+ .iter()
+ .position(|b| b.is_utf8_char_boundary())
+ .map_or(upper_bound, |pos| pos + index)
}
}
diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
index b2ea86d..0d3dc85 100644
--- a/library/core/src/str/validations.rs
+++ b/library/core/src/str/validations.rs
@@ -273,16 +273,3 @@
/// Mask of the value bits of a continuation byte.
const CONT_MASK: u8 = 0b0011_1111;
-
-// truncate `&str` to length at most equal to `max`
-// return `true` if it were truncated, and the new str.
-pub(super) fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
- if max >= s.len() {
- (false, s)
- } else {
- while !s.is_char_boundary(max) {
- max -= 1;
- }
- (true, &s[..max])
- }
-}
diff --git a/library/core/src/stream/from_iter.rs b/library/core/src/stream/from_iter.rs
deleted file mode 100644
index eb9a0fd..0000000
--- a/library/core/src/stream/from_iter.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use crate::pin::Pin;
-
-use crate::stream::Stream;
-use crate::task::{Context, Poll};
-
-/// A stream that was created from iterator.
-///
-/// This stream is created by the [`from_iter`] function.
-/// See it documentation for more.
-///
-/// [`from_iter`]: fn.from_iter.html
-#[unstable(feature = "stream_from_iter", issue = "81798")]
-#[derive(Clone, Debug)]
-pub struct FromIter<I> {
- iter: I,
-}
-
-#[unstable(feature = "stream_from_iter", issue = "81798")]
-impl<I> Unpin for FromIter<I> {}
-
-/// Converts an iterator into a stream.
-#[unstable(feature = "stream_from_iter", issue = "81798")]
-pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> {
- FromIter { iter: iter.into_iter() }
-}
-
-#[unstable(feature = "stream_from_iter", issue = "81798")]
-impl<I: Iterator> Stream for FromIter<I> {
- type Item = I::Item;
-
- fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
- Poll::Ready(self.iter.next())
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
diff --git a/library/core/src/stream/mod.rs b/library/core/src/stream/mod.rs
deleted file mode 100644
index b59a46d..0000000
--- a/library/core/src/stream/mod.rs
+++ /dev/null
@@ -1,129 +0,0 @@
-//! Composable asynchronous iteration.
-//!
-//! If futures are asynchronous values, then streams are asynchronous
-//! iterators. If you've found yourself with an asynchronous collection of some kind,
-//! and needed to perform an operation on the elements of said collection,
-//! you'll quickly run into 'streams'. Streams are heavily used in idiomatic
-//! asynchronous Rust code, so it's worth becoming familiar with them.
-//!
-//! Before explaining more, let's talk about how this module is structured:
-//!
-//! # Organization
-//!
-//! This module is largely organized by type:
-//!
-//! * [Traits] are the core portion: these traits define what kind of streams
-//! exist and what you can do with them. The methods of these traits are worth
-//! putting some extra study time into.
-//! * Functions provide some helpful ways to create some basic streams.
-//! * Structs are often the return types of the various methods on this
-//! module's traits. You'll usually want to look at the method that creates
-//! the `struct`, rather than the `struct` itself. For more detail about why,
-//! see '[Implementing Stream](#implementing-stream)'.
-//!
-//! [Traits]: #traits
-//!
-//! That's it! Let's dig into streams.
-//!
-//! # Stream
-//!
-//! The heart and soul of this module is the [`Stream`] trait. The core of
-//! [`Stream`] looks like this:
-//!
-//! ```
-//! # use core::task::{Context, Poll};
-//! # use core::pin::Pin;
-//! trait Stream {
-//! type Item;
-//! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
-//! }
-//! ```
-//!
-//! Unlike `Iterator`, `Stream` makes a distinction between the [`poll_next`]
-//! method which is used when implementing a `Stream`, and a (to-be-implemented)
-//! `next` method which is used when consuming a stream. Consumers of `Stream`
-//! only need to consider `next`, which when called, returns a future which
-//! yields `Option<Stream::Item>`.
-//!
-//! The future returned by `next` will yield `Some(Item)` as long as there are
-//! elements, and once they've all been exhausted, will yield `None` to indicate
-//! that iteration is finished. If we're waiting on something asynchronous to
-//! resolve, the future will wait until the stream is ready to yield again.
-//!
-//! Individual streams may choose to resume iteration, and so calling `next`
-//! again may or may not eventually yield `Some(Item)` again at some point.
-//!
-//! [`Stream`]'s full definition includes a number of other methods as well,
-//! but they are default methods, built on top of [`poll_next`], and so you get
-//! them for free.
-//!
-//! [`Poll`]: super::task::Poll
-//! [`poll_next`]: Stream::poll_next
-//!
-//! # Implementing Stream
-//!
-//! Creating a stream of your own involves two steps: creating a `struct` to
-//! hold the stream's state, and then implementing [`Stream`] for that
-//! `struct`.
-//!
-//! Let's make a stream named `Counter` which counts from `1` to `5`:
-//!
-//! ```no_run
-//! #![feature(async_stream)]
-//! # use core::stream::Stream;
-//! # use core::task::{Context, Poll};
-//! # use core::pin::Pin;
-//!
-//! // First, the struct:
-//!
-//! /// A stream which counts from one to five
-//! struct Counter {
-//! count: usize,
-//! }
-//!
-//! // we want our count to start at one, so let's add a new() method to help.
-//! // This isn't strictly necessary, but is convenient. Note that we start
-//! // `count` at zero, we'll see why in `poll_next()`'s implementation below.
-//! impl Counter {
-//! fn new() -> Counter {
-//! Counter { count: 0 }
-//! }
-//! }
-//!
-//! // Then, we implement `Stream` for our `Counter`:
-//!
-//! impl Stream for Counter {
-//! // we will be counting with usize
-//! type Item = usize;
-//!
-//! // poll_next() is the only required method
-//! fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
-//! // Increment our count. This is why we started at zero.
-//! self.count += 1;
-//!
-//! // Check to see if we've finished counting or not.
-//! if self.count < 6 {
-//! Poll::Ready(Some(self.count))
-//! } else {
-//! Poll::Ready(None)
-//! }
-//! }
-//! }
-//! ```
-//!
-//! # Laziness
-//!
-//! Streams are *lazy*. This means that just creating a stream doesn't _do_ a
-//! whole lot. Nothing really happens until you call `poll_next`. This is
-//! sometimes a source of confusion when creating a stream solely for its side
-//! effects. The compiler will warn us about this kind of behavior:
-//!
-//! ```text
-//! warning: unused result that must be used: streams do nothing unless polled
-//! ```
-
-mod from_iter;
-mod stream;
-
-pub use from_iter::{from_iter, FromIter};
-pub use stream::Stream;
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 1dd3b2d..9ee88dd 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -131,6 +131,7 @@
/// loads and stores of `u8`.
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "AtomicBool"]
#[repr(C, align(1))]
pub struct AtomicBool {
v: UnsafeCell<u8>,
@@ -333,10 +334,10 @@
#[inline]
#[cfg(target_has_atomic_equal_alignment = "8")]
#[unstable(feature = "atomic_from_mut", issue = "76314")]
- pub fn from_mut(v: &mut bool) -> &Self {
+ pub fn from_mut(v: &mut bool) -> &mut Self {
// SAFETY: the mutable reference guarantees unique ownership, and
// alignment of both `bool` and `Self` is 1.
- unsafe { &*(v as *mut bool as *mut Self) }
+ unsafe { &mut *(v as *mut bool as *mut Self) }
}
/// Consumes the atomic and returns the contained value.
@@ -934,14 +935,14 @@
#[inline]
#[cfg(target_has_atomic_equal_alignment = "ptr")]
#[unstable(feature = "atomic_from_mut", issue = "76314")]
- pub fn from_mut(v: &mut *mut T) -> &Self {
+ pub fn from_mut(v: &mut *mut T) -> &mut Self {
use crate::mem::align_of;
let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()];
// SAFETY:
// - the mutable reference guarantees unique ownership.
// - the alignment of `*mut T` and `Self` is the same on all platforms
// supported by rust, as verified above.
- unsafe { &*(v as *mut *mut T as *mut Self) }
+ unsafe { &mut *(v as *mut *mut T as *mut Self) }
}
/// Consumes the atomic and returns the contained value.
@@ -1294,6 +1295,7 @@
#[stable(feature = "atomic_from", since = "1.23.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<*mut T> for AtomicPtr<T> {
+ /// Converts a `*mut T` into an `AtomicPtr<T>`.
#[inline]
fn from(p: *mut T) -> Self {
Self::new(p)
@@ -1447,14 +1449,14 @@
#[inline]
#[$cfg_align]
#[unstable(feature = "atomic_from_mut", issue = "76314")]
- pub fn from_mut(v: &mut $int_type) -> &Self {
+ pub fn from_mut(v: &mut $int_type) -> &mut Self {
use crate::mem::align_of;
let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
// SAFETY:
// - the mutable reference guarantees unique ownership.
// - the alignment of `$int_type` and `Self` is the
// same, as promised by $cfg_align and verified above.
- unsafe { &*(v as *mut $int_type as *mut Self) }
+ unsafe { &mut *(v as *mut $int_type as *mut Self) }
}
/// Consumes the atomic and returns the contained value.
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 72a0306..41f0a25 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -243,7 +243,7 @@
#[stable(feature = "futures_api", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for Poll<T> {
- /// Convert to a `Ready` variant.
+ /// Moves the value into a [`Poll::Ready`] to make a `Poll<T>`.
///
/// # Example
///
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 6cba781..27af227 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -43,6 +43,22 @@
pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
RawWaker { data, vtable }
}
+
+ /// Get the `data` pointer used to create this `RawWaker`.
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "waker_getters", issue = "87021")]
+ pub fn data(&self) -> *const () {
+ self.data
+ }
+
+ /// Get the `vtable` pointer used to create this `RawWaker`.
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "waker_getters", issue = "87021")]
+ pub fn vtable(&self) -> &'static RawWakerVTable {
+ self.vtable
+ }
}
/// A virtual function pointer table (vtable) that specifies the behavior
@@ -260,6 +276,14 @@
pub unsafe fn from_raw(waker: RawWaker) -> Waker {
Waker { waker }
}
+
+ /// Get a reference to the underlying [`RawWaker`].
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "waker_getters", issue = "87021")]
+ pub fn as_raw(&self) -> &RawWaker {
+ &self.waker
+ }
}
#[stable(feature = "futures_api", since = "1.36.0")]
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 746d1ca..243c044 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -711,14 +711,28 @@
/// as `f64`.
///
/// # Panics
- /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+ /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// use std::time::Duration;
///
- /// let dur = Duration::from_secs_f64(2.7);
- /// assert_eq!(dur, Duration::new(2, 700_000_000));
+ /// let res = Duration::from_secs_f64(0.0);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f64(1e-20);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f64(4.2e-7);
+ /// assert_eq!(res, Duration::new(0, 420));
+ /// let res = Duration::from_secs_f64(2.7);
+ /// assert_eq!(res, Duration::new(2, 700_000_000));
+ /// let res = Duration::from_secs_f64(3e10);
+ /// assert_eq!(res, Duration::new(30_000_000_000, 0));
+ /// // subnormal float
+ /// let res = Duration::from_secs_f64(f64::from_bits(1));
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::from_secs_f64(0.999e-9);
+ /// assert_eq!(res, Duration::new(0, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
@@ -731,55 +745,32 @@
}
}
- /// The checked version of [`from_secs_f64`].
- ///
- /// [`from_secs_f64`]: Duration::from_secs_f64
- ///
- /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
- ///
- /// # Examples
- /// ```
- /// #![feature(duration_checked_float)]
- /// use std::time::Duration;
- ///
- /// let dur = Duration::try_from_secs_f64(2.7);
- /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
- ///
- /// let negative = Duration::try_from_secs_f64(-5.0);
- /// assert!(negative.is_err());
- /// ```
- #[unstable(feature = "duration_checked_float", issue = "83400")]
- #[inline]
- pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
- const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
- let nanos = secs * (NANOS_PER_SEC as f64);
- if !nanos.is_finite() {
- Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
- } else if nanos >= MAX_NANOS_F64 {
- Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
- } else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Negative })
- } else {
- let nanos = nanos as u128;
- Ok(Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
- })
- }
- }
-
/// Creates a new `Duration` from the specified number of seconds represented
/// as `f32`.
///
/// # Panics
- /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+ /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// use std::time::Duration;
///
- /// let dur = Duration::from_secs_f32(2.7);
- /// assert_eq!(dur, Duration::new(2, 700_000_000));
+ /// let res = Duration::from_secs_f32(0.0);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f32(1e-20);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f32(4.2e-7);
+ /// assert_eq!(res, Duration::new(0, 419));
+ /// let res = Duration::from_secs_f32(2.7);
+ /// assert_eq!(res, Duration::new(2, 700_000_047));
+ /// let res = Duration::from_secs_f32(3e10);
+ /// assert_eq!(res, Duration::new(30_000_001_024, 0));
+ /// // subnormal float
+ /// let res = Duration::from_secs_f32(f32::from_bits(1));
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::from_secs_f32(0.999e-9);
+ /// assert_eq!(res, Duration::new(0, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
@@ -792,47 +783,10 @@
}
}
- /// The checked version of [`from_secs_f32`].
- ///
- /// [`from_secs_f32`]: Duration::from_secs_f32
- ///
- /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
- ///
- /// # Examples
- /// ```
- /// #![feature(duration_checked_float)]
- /// use std::time::Duration;
- ///
- /// let dur = Duration::try_from_secs_f32(2.7);
- /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
- ///
- /// let negative = Duration::try_from_secs_f32(-5.0);
- /// assert!(negative.is_err());
- /// ```
- #[unstable(feature = "duration_checked_float", issue = "83400")]
- #[inline]
- pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
- const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
- let nanos = secs * (NANOS_PER_SEC as f32);
- if !nanos.is_finite() {
- Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
- } else if nanos >= MAX_NANOS_F32 {
- Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
- } else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Negative })
- } else {
- let nanos = nanos as u128;
- Ok(Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
- })
- }
- }
-
/// Multiplies `Duration` by `f64`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
@@ -854,17 +808,15 @@
/// Multiplies `Duration` by `f32`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// use std::time::Duration;
///
/// let dur = Duration::new(2, 700_000_000);
- /// // note that due to rounding errors result is slightly different
- /// // from 8.478 and 847800.0
/// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
- /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
+ /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use = "this returns the result of the operation, \
@@ -878,7 +830,7 @@
/// Divide `Duration` by `f64`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
@@ -901,7 +853,7 @@
/// Divide `Duration` by `f32`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
@@ -910,7 +862,7 @@
/// let dur = Duration::new(2, 700_000_000);
/// // note that due to rounding errors result is slightly
/// // different from 0.859_872_611
- /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576));
+ /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579));
/// // note that truncation is used, not rounding
/// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
/// ```
@@ -1267,33 +1219,180 @@
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[unstable(feature = "duration_checked_float", issue = "83400")]
-pub struct FromSecsError {
- kind: FromSecsErrorKind,
+pub struct FromFloatSecsError {
+ kind: FromFloatSecsErrorKind,
}
-impl FromSecsError {
+impl FromFloatSecsError {
const fn description(&self) -> &'static str {
match self.kind {
- FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration",
- FromSecsErrorKind::Overflow => "overflow when converting float to duration",
- FromSecsErrorKind::Negative => "negative value when converting float to duration",
+ FromFloatSecsErrorKind::Negative => {
+ "can not convert float seconds to Duration: value is negative"
+ }
+ FromFloatSecsErrorKind::OverflowOrNan => {
+ "can not convert float seconds to Duration: value is either too big or NaN"
+ }
}
}
}
#[unstable(feature = "duration_checked_float", issue = "83400")]
-impl fmt::Display for FromSecsError {
+impl fmt::Display for FromFloatSecsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self.description(), f)
+ self.description().fmt(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
-enum FromSecsErrorKind {
- // Value is not a finite value (either + or - infinity or NaN).
- NonFinite,
- // Value is too large to store in a `Duration`.
- Overflow,
+enum FromFloatSecsErrorKind {
// Value is negative.
Negative,
+ // Value is either too big to be represented as `Duration` or `NaN`.
+ OverflowOrNan,
+}
+
+macro_rules! try_from_secs {
+ (
+ secs = $secs: expr,
+ mantissa_bits = $mant_bits: literal,
+ exponent_bits = $exp_bits: literal,
+ offset = $offset: literal,
+ bits_ty = $bits_ty:ty,
+ double_ty = $double_ty:ty,
+ ) => {{
+ const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
+ const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
+ const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
+
+ if $secs.is_sign_negative() {
+ return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::Negative });
+ }
+
+ let bits = $secs.to_bits();
+ let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
+ let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
+
+ let (secs, nanos) = if exp < -30 {
+ // the input represents less than 1ns.
+ (0u64, 0u32)
+ } else if exp < 0 {
+ // the input is less than 1 second
+ let t = <$double_ty>::from(mant) << ($offset + exp);
+ let nanos = (u128::from(NANOS_PER_SEC) * u128::from(t)) >> ($mant_bits + $offset);
+ (0, nanos as u32)
+ } else if exp < $mant_bits {
+ let secs = mant >> ($mant_bits - exp);
+ let t = <$double_ty>::from((mant << exp) & MANT_MASK);
+ let nanos = (<$double_ty>::from(NANOS_PER_SEC) * t) >> $mant_bits;
+ (u64::from(secs), nanos as u32)
+ } else if exp < 64 {
+ // the input has no fractional part
+ let secs = u64::from(mant) << (exp - $mant_bits);
+ (secs, 0)
+ } else {
+ return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan });
+ };
+
+ Ok(Duration { secs, nanos })
+ }};
+}
+
+impl Duration {
+ /// The checked version of [`from_secs_f32`].
+ ///
+ /// [`from_secs_f32`]: Duration::from_secs_f32
+ ///
+ /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_checked_float)]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// let res = Duration::try_from_secs_f32(0.0);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f32(1e-20);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f32(4.2e-7);
+ /// assert_eq!(res, Ok(Duration::new(0, 419)));
+ /// let res = Duration::try_from_secs_f32(2.7);
+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_047)));
+ /// let res = Duration::try_from_secs_f32(3e10);
+ /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
+ /// // subnormal float:
+ /// let res = Duration::try_from_secs_f32(f32::from_bits(1));
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::try_from_secs_f32(0.999e-9);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ ///
+ /// let res = Duration::try_from_secs_f32(-5.0);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f32(f32::NAN);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f32(2e19);
+ /// assert!(res.is_err());
+ /// ```
+ #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[inline]
+ pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromFloatSecsError> {
+ try_from_secs!(
+ secs = secs,
+ mantissa_bits = 23,
+ exponent_bits = 8,
+ offset = 41,
+ bits_ty = u32,
+ double_ty = u64,
+ )
+ }
+
+ /// The checked version of [`from_secs_f64`].
+ ///
+ /// [`from_secs_f64`]: Duration::from_secs_f64
+ ///
+ /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_checked_float)]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// let res = Duration::try_from_secs_f64(0.0);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f64(1e-20);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f64(4.2e-7);
+ /// assert_eq!(res, Ok(Duration::new(0, 420)));
+ /// let res = Duration::try_from_secs_f64(2.7);
+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_000)));
+ /// let res = Duration::try_from_secs_f64(3e10);
+ /// assert_eq!(res, Ok(Duration::new(30_000_000_000, 0)));
+ /// // subnormal float
+ /// let res = Duration::try_from_secs_f64(f64::from_bits(1));
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::try_from_secs_f32(0.999e-9);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ ///
+ /// let res = Duration::try_from_secs_f64(-5.0);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f64(f64::NAN);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f64(2e19);
+ /// assert!(res.is_err());
+ /// ```
+ #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[inline]
+ pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromFloatSecsError> {
+ try_from_secs!(
+ secs = secs,
+ mantissa_bits = 52,
+ exponent_bits = 11,
+ offset = 44,
+ bits_ty = u64,
+ double_ty = u128,
+ )
+ }
}
diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs
index 2b857a6..4c899b6 100644
--- a/library/core/tests/char.rs
+++ b/library/core/tests/char.rs
@@ -309,6 +309,33 @@
}
#[test]
+fn test_decode_utf16_size_hint() {
+ fn check(s: &[u16]) {
+ let mut iter = char::decode_utf16(s.iter().cloned());
+
+ loop {
+ let count = iter.clone().count();
+ let (lower, upper) = iter.size_hint();
+
+ assert!(
+ lower <= count && count <= upper.unwrap(),
+ "lower = {lower}, count = {count}, upper = {upper:?}"
+ );
+
+ if let None = iter.next() {
+ break;
+ }
+ }
+ }
+
+ check(&[0xD800, 0xD800, 0xDC00]);
+ check(&[0xD800, 0xD800, 0x0]);
+ check(&[0xD800, 0x41, 0x42]);
+ check(&[0xD800, 0]);
+ check(&[0xD834, 0x006d]);
+}
+
+#[test]
fn ed_iterator_specializations() {
// Check counting
assert_eq!('\n'.escape_default().count(), 2);
diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs
index 58fee19..2b234de 100644
--- a/library/core/tests/cmp.rs
+++ b/library/core/tests/cmp.rs
@@ -204,7 +204,6 @@
assert_eq!(Fool(false), Fool(true));
}
-#[cfg(not(bootstrap))]
mod const_cmp {
use super::*;
diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs
index 0ed8c52..74b6f74 100644
--- a/library/core/tests/future.rs
+++ b/library/core/tests/future.rs
@@ -118,3 +118,11 @@
}
}
}
+
+// just tests by whether or not this compiles
+fn _pending_impl_all_auto_traits<T>() {
+ use std::panic::{RefUnwindSafe, UnwindSafe};
+ fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+ all_auto_traits::<std::future::Pending<T>>();
+}
diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs
index 72ccdd4..a173e46 100644
--- a/library/core/tests/hash/mod.rs
+++ b/library/core/tests/hash/mod.rs
@@ -146,3 +146,11 @@
let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new();
}
+
+// just tests by whether or not this compiles
+fn _build_hasher_default_impl_all_auto_traits<T>() {
+ use std::panic::{RefUnwindSafe, UnwindSafe};
+ fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+ all_auto_traits::<std::hash::BuildHasherDefault<T>>();
+}
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
index 7a2e4e2..e050e81 100644
--- a/library/core/tests/intrinsics.rs
+++ b/library/core/tests/intrinsics.rs
@@ -37,7 +37,6 @@
}
#[test]
-#[cfg(not(bootstrap))]
const fn test_write_bytes_in_const_contexts() {
use core::intrinsics::write_bytes;
@@ -80,3 +79,25 @@
assert!(42u32 == core::hint::black_box(42u32));
}
}
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_const_allocate_at_runtime() {
+ use core::intrinsics::const_allocate;
+ unsafe {
+ assert!(const_allocate(4, 4).is_null());
+ }
+}
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_const_deallocate_at_runtime() {
+ use core::intrinsics::const_deallocate;
+ const X: &u32 = &42u32;
+ let x = &0u32;
+ unsafe {
+ const_deallocate(X as *const _ as *mut u8, 4, 4); // nop
+ const_deallocate(x as *const _ as *mut u8, 4, 4); // nop
+ const_deallocate(core::ptr::null_mut(), 1, 1); // nop
+ }
+}
diff --git a/library/core/tests/iter/adapters/intersperse.rs b/library/core/tests/iter/adapters/intersperse.rs
index b336c03..72ae59b 100644
--- a/library/core/tests/iter/adapters/intersperse.rs
+++ b/library/core/tests/iter/adapters/intersperse.rs
@@ -74,7 +74,7 @@
struct NotClone {
u: u32,
}
- let r = vec![NotClone { u: 0 }, NotClone { u: 1 }]
+ let r = [NotClone { u: 0 }, NotClone { u: 1 }]
.into_iter()
.intersperse_with(|| NotClone { u: 2 })
.collect::<Vec<_>>();
@@ -120,7 +120,7 @@
#[test]
fn test_intersperse_collect_string() {
- let contents = vec![1, 2, 3];
+ let contents = [1, 2, 3];
let contents_string = contents
.into_iter()
diff --git a/library/core/tests/iter/adapters/peekable.rs b/library/core/tests/iter/adapters/peekable.rs
index 390414d..c1a1c29 100644
--- a/library/core/tests/iter/adapters/peekable.rs
+++ b/library/core/tests/iter/adapters/peekable.rs
@@ -144,7 +144,7 @@
#[test]
fn test_iterator_peekable_next_if_eq() {
// first, try on references
- let xs = vec!["Heart", "of", "Gold"];
+ let xs = ["Heart", "of", "Gold"];
let mut it = xs.into_iter().peekable();
// try before `peek()`
assert_eq!(it.next_if_eq(&"trillian"), None);
@@ -157,7 +157,7 @@
assert_eq!(it.next(), Some("Gold"));
// make sure comparison works for owned values
- let xs = vec![String::from("Ludicrous"), "speed".into()];
+ let xs = [String::from("Ludicrous"), "speed".into()];
let mut it = xs.into_iter().peekable();
// make sure basic functionality works
assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
@@ -167,7 +167,7 @@
#[test]
fn test_iterator_peekable_mut() {
- let mut it = vec![1, 2, 3].into_iter().peekable();
+ let mut it = [1, 2, 3].into_iter().peekable();
if let Some(p) = it.peek_mut() {
if *p == 1 {
*p = 5;
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index d38bca1..cf69f0a 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -456,25 +456,25 @@
#[test]
fn test_try_reduce() {
- let v: Vec<usize> = vec![1, 2, 3, 4, 5];
+ let v = [1usize, 2, 3, 4, 5];
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
assert_eq!(sum, Some(Some(15)));
- let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
+ let v = [1, 2, 3, 4, 5, usize::MAX];
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
assert_eq!(sum, None);
- let v: Vec<usize> = Vec::new();
+ let v: [usize; 0] = [];
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
assert_eq!(sum, Some(None));
- let v = vec!["1", "2", "3", "4", "5"];
+ let v = ["1", "2", "3", "4", "5"];
let max = v.into_iter().try_reduce(|x, y| {
if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
});
assert_eq!(max, Some(Some("5")));
- let v = vec!["1", "2", "3", "4", "5"];
+ let v = ["1", "2", "3", "4", "5"];
let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
v.into_iter().try_reduce(|x, y| {
if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
@@ -496,3 +496,57 @@
let b: Vec<isize> = a.iter().cloned().collect();
assert!(a == b);
}
+
+#[test]
+fn test_try_collect() {
+ use core::ops::ControlFlow::{Break, Continue};
+
+ let u = vec![Some(1), Some(2), Some(3)];
+ let v = u.into_iter().try_collect::<Vec<i32>>();
+ assert_eq!(v, Some(vec![1, 2, 3]));
+
+ let u = vec![Some(1), Some(2), None, Some(3)];
+ let mut it = u.into_iter();
+ let v = it.try_collect::<Vec<i32>>();
+ assert_eq!(v, None);
+ let v = it.try_collect::<Vec<i32>>();
+ assert_eq!(v, Some(vec![3]));
+
+ let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
+ let v = u.into_iter().try_collect::<Vec<i32>>();
+ assert_eq!(v, Ok(vec![1, 2, 3]));
+
+ let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
+ let v = u.into_iter().try_collect::<Vec<i32>>();
+ assert_eq!(v, Err(()));
+
+ let numbers = vec![1, 2, 3, 4, 5];
+ let all_positive = numbers
+ .iter()
+ .cloned()
+ .map(|n| if n > 0 { Some(n) } else { None })
+ .try_collect::<Vec<i32>>();
+ assert_eq!(all_positive, Some(numbers));
+
+ let numbers = vec![-2, -1, 0, 1, 2];
+ let all_positive =
+ numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::<Vec<i32>>();
+ assert_eq!(all_positive, None);
+
+ let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
+ let mut it = u.into_iter();
+
+ let v = it.try_collect::<Vec<_>>();
+ assert_eq!(v, Break(3));
+
+ let v = it.try_collect::<Vec<_>>();
+ assert_eq!(v, Continue(vec![4, 5]));
+}
+
+// just tests by whether or not this compiles
+fn _empty_impl_all_auto_traits<T>() {
+ use std::panic::{RefUnwindSafe, UnwindSafe};
+ fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+ all_auto_traits::<std::iter::Empty<T>>();
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index ec70034..06c7be0 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -6,16 +6,20 @@
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(cell_update)]
-#![feature(cfg_panic)]
-#![feature(cfg_target_has_atomic)]
+#![cfg_attr(bootstrap, feature(cfg_panic))]
+#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))]
#![feature(const_assume)]
#![feature(const_black_box)]
#![feature(const_bool_to_option)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
+#![feature(const_heap)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
+#![feature(const_maybe_uninit_assume_init_read)]
+#![feature(const_nonnull_new)]
#![feature(const_num_from_num)]
+#![feature(const_ptr_as_ref)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_ptr_offset)]
@@ -41,12 +45,11 @@
#![feature(inline_const)]
#![feature(is_sorted)]
#![feature(pattern)]
+#![feature(pin_macro)]
#![feature(sort_internals)]
-#![feature(slice_partition_at_index)]
#![feature(slice_take)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_array_assume_init)]
-#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(numfmt)]
@@ -64,6 +67,7 @@
#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
+#![feature(iterator_try_collect)]
#![feature(iterator_try_reduce)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
@@ -88,6 +92,7 @@
#![feature(unzip_option)]
#![feature(const_array_from_ref)]
#![feature(const_slice_from_ref)]
+#![feature(waker_getters)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate test;
@@ -119,6 +124,7 @@
mod option;
mod pattern;
mod pin;
+mod pin_macro;
mod ptr;
mod result;
mod simd;
@@ -129,3 +135,4 @@
mod time;
mod tuple;
mod unicode;
+mod waker;
diff --git a/library/core/tests/num/bignum.rs b/library/core/tests/num/bignum.rs
index 1457064..416e7ce 100644
--- a/library/core/tests/num/bignum.rs
+++ b/library/core/tests/num/bignum.rs
@@ -1,4 +1,5 @@
use core::num::bignum::tests::Big8x3 as Big;
+use core::num::bignum::Big32x40;
#[test]
#[should_panic]
@@ -215,6 +216,16 @@
#[test]
fn test_bit_length() {
+ for i in 0..8 * 3 {
+ // 010000...000
+ assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1);
+ }
+ for i in 1..8 * 3 - 1 {
+ // 010000...001
+ assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1);
+ // 110000...000
+ assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2);
+ }
assert_eq!(Big::from_small(0).bit_length(), 0);
assert_eq!(Big::from_small(1).bit_length(), 1);
assert_eq!(Big::from_small(5).bit_length(), 3);
@@ -224,6 +235,30 @@
}
#[test]
+fn test_bit_length_32x40() {
+ for i in 0..32 * 40 {
+ // 010000...000
+ assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1);
+ }
+ for i in 1..32 * 40 - 1 {
+ // 010000...001
+ assert_eq!(
+ Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(),
+ i + 1
+ );
+ // 110000...000
+ assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2);
+ }
+ assert_eq!(Big32x40::from_small(0).bit_length(), 0);
+ assert_eq!(Big32x40::from_small(1).bit_length(), 1);
+ assert_eq!(Big32x40::from_small(5).bit_length(), 3);
+ assert_eq!(Big32x40::from_small(0x18).bit_length(), 5);
+ assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15);
+ assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24);
+ assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64);
+}
+
+#[test]
fn test_ord() {
assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
assert!(Big::from_u64(0x102) < Big::from_u64(0x201));
diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs
index aa79dba..0c81cba 100644
--- a/library/core/tests/ops.rs
+++ b/library/core/tests/ops.rs
@@ -232,3 +232,9 @@
let y = deref(&mut x);
assert_eq!(y, 4);
}
+
+#[test]
+#[allow(unreachable_code)]
+fn test_not_never() {
+ if !return () {}
+}
diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs
new file mode 100644
index 0000000..79c8c16
--- /dev/null
+++ b/library/core/tests/pin_macro.rs
@@ -0,0 +1,33 @@
+// edition:2021
+use core::{
+ marker::PhantomPinned,
+ mem::{drop as stuff, transmute},
+ pin::{pin, Pin},
+};
+
+#[test]
+fn basic() {
+ let it: Pin<&mut PhantomPinned> = pin!(PhantomPinned);
+ stuff(it);
+}
+
+#[test]
+fn extension_works_through_block() {
+ let it: Pin<&mut PhantomPinned> = { pin!(PhantomPinned) };
+ stuff(it);
+}
+
+#[test]
+fn extension_works_through_unsafe_block() {
+ // "retro-type-inference" works as well.
+ let it: Pin<&mut PhantomPinned> = unsafe { pin!(transmute(())) };
+ stuff(it);
+}
+
+#[test]
+fn unsize_coercion() {
+ let slice: Pin<&mut [PhantomPinned]> = pin!([PhantomPinned; 2]);
+ stuff(slice);
+ let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]);
+ stuff(dyn_obj);
+}
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index b9c0d75..9c65871 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -251,7 +251,6 @@
}
#[test]
-#[cfg(not(bootstrap))]
fn test_set_memory_const() {
const XS: [u8; 20] = {
let mut xs = [0u8; 20];
@@ -275,6 +274,21 @@
}
#[test]
+fn test_const_nonnull_new() {
+ const {
+ assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none());
+
+ let value = &mut 0u32;
+ let mut ptr = NonNull::new(value).unwrap();
+ unsafe { *ptr.as_mut() = 42 };
+
+ let reference = unsafe { &*ptr.as_ref() };
+ assert!(*reference == *value);
+ assert!(*reference == 42);
+ };
+}
+
+#[test]
#[allow(warnings)]
// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
// ABI, or even point to an actual executable code, because the function itself is never invoked.
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 20e2d8d..88cbd73 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -252,6 +252,40 @@
}
#[test]
+fn test_chunks_next() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks(2);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next().unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+ assert_eq!(c.next(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.chunks(3);
+ assert_eq!(c.next().unwrap(), &[0, 1, 2]);
+ assert_eq!(c.next().unwrap(), &[3, 4, 5]);
+ assert_eq!(c.next().unwrap(), &[6, 7]);
+ assert_eq!(c.next(), None);
+}
+
+#[test]
+fn test_chunks_next_back() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks(2);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+ assert_eq!(c.next_back().unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[0, 1]);
+ assert_eq!(c.next_back(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.chunks(3);
+ assert_eq!(c.next_back().unwrap(), &[6, 7]);
+ assert_eq!(c.next_back().unwrap(), &[3, 4, 5]);
+ assert_eq!(c.next_back().unwrap(), &[0, 1, 2]);
+ assert_eq!(c.next_back(), None);
+}
+
+#[test]
fn test_chunks_nth_back() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
let mut c = v.chunks(2);
@@ -810,6 +844,40 @@
}
#[test]
+fn test_rchunks_next() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks(2);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+ assert_eq!(c.next().unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks(3);
+ assert_eq!(c.next().unwrap(), &[5, 6, 7]);
+ assert_eq!(c.next().unwrap(), &[2, 3, 4]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+}
+
+#[test]
+fn test_rchunks_next_back() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks(2);
+ assert_eq!(c.next_back().unwrap(), &[0, 1]);
+ assert_eq!(c.next_back().unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+ assert_eq!(c.next_back(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks(3);
+ assert_eq!(c.next_back().unwrap(), &[0, 1]);
+ assert_eq!(c.next_back().unwrap(), &[2, 3, 4]);
+ assert_eq!(c.next_back().unwrap(), &[5, 6, 7]);
+ assert_eq!(c.next_back(), None);
+}
+
+#[test]
fn test_rchunks_last() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
let c = v.rchunks(2);
@@ -875,6 +943,40 @@
}
#[test]
+fn test_rchunks_mut_next() {
+ let mut v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_mut(2);
+ assert_eq!(c.next().unwrap(), &mut [4, 5]);
+ assert_eq!(c.next().unwrap(), &mut [2, 3]);
+ assert_eq!(c.next().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next(), None);
+
+ let mut v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks_mut(3);
+ assert_eq!(c.next().unwrap(), &mut [5, 6, 7]);
+ assert_eq!(c.next().unwrap(), &mut [2, 3, 4]);
+ assert_eq!(c.next().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next(), None);
+}
+
+#[test]
+fn test_rchunks_mut_next_back() {
+ let mut v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_mut(2);
+ assert_eq!(c.next_back().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next_back().unwrap(), &mut [2, 3]);
+ assert_eq!(c.next_back().unwrap(), &mut [4, 5]);
+ assert_eq!(c.next_back(), None);
+
+ let mut v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks_mut(3);
+ assert_eq!(c.next_back().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next_back().unwrap(), &mut [2, 3, 4]);
+ assert_eq!(c.next_back().unwrap(), &mut [5, 6, 7]);
+ assert_eq!(c.next_back(), None);
+}
+
+#[test]
fn test_rchunks_mut_last() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
let c = v.rchunks_mut(2);
diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs
new file mode 100644
index 0000000..6602ab3
--- /dev/null
+++ b/library/core/tests/waker.rs
@@ -0,0 +1,22 @@
+use std::ptr;
+use std::task::{RawWaker, RawWakerVTable, Waker};
+
+#[test]
+fn test_waker_getters() {
+ let raw_waker = RawWaker::new(42usize as *mut (), &WAKER_VTABLE);
+ assert_eq!(raw_waker.data() as usize, 42);
+ assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE));
+
+ let waker = unsafe { Waker::from_raw(raw_waker) };
+ let waker2 = waker.clone();
+ let raw_waker2 = waker2.as_raw();
+ assert_eq!(raw_waker2.data() as usize, 43);
+ assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE));
+}
+
+static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
+ |data| RawWaker::new((data as usize + 1) as *mut (), &WAKER_VTABLE),
+ |_| {},
+ |_| {},
+ |_| {},
+);
diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml
index 6dec0e6..46183d1 100644
--- a/library/panic_abort/Cargo.toml
+++ b/library/panic_abort/Cargo.toml
@@ -4,7 +4,7 @@
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Implementation of Rust panics via process aborts"
-edition = "2018"
+edition = "2021"
[lib]
test = false
diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml
index 6740546..d720cc7 100644
--- a/library/panic_unwind/Cargo.toml
+++ b/library/panic_unwind/Cargo.toml
@@ -4,7 +4,7 @@
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Implementation of Rust panics via stack unwinding"
-edition = "2018"
+edition = "2021"
[lib]
test = false
diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs
index 9d6ede7..a0297b4 100644
--- a/library/panic_unwind/src/gcc.rs
+++ b/library/panic_unwind/src/gcc.rs
@@ -105,6 +105,9 @@
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
+#[cfg(target_arch = "m68k")]
+const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1
+
#[cfg(any(target_arch = "mips", target_arch = "mips64"))]
const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index e5753cc..7f05c82 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -39,6 +39,10 @@
} else if #[cfg(target_os = "hermit")] {
#[path = "hermit.rs"]
mod real_imp;
+ } else if #[cfg(target_os = "l4re")] {
+ // L4Re is unix family but does not yet support unwinding.
+ #[path = "dummy.rs"]
+ mod real_imp;
} else if #[cfg(target_env = "msvc")] {
#[path = "seh.rs"]
mod real_imp;
diff --git a/library/portable-simd/Cargo.toml b/library/portable-simd/Cargo.toml
index 3f1abd7..9802386 100644
--- a/library/portable-simd/Cargo.toml
+++ b/library/portable-simd/Cargo.toml
@@ -2,5 +2,6 @@
members = [
"crates/core_simd",
+ "crates/std_float",
"crates/test_helpers",
]
diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml
index a103ef1..d2ff5f3 100644
--- a/library/portable-simd/crates/core_simd/Cargo.toml
+++ b/library/portable-simd/crates/core_simd/Cargo.toml
@@ -26,3 +26,6 @@
[dev-dependencies.test_helpers]
path = "../test_helpers"
+
+[dev-dependencies]
+std_float = { path = "../std_float/", features = ["as_crate"] }
diff --git a/library/portable-simd/crates/core_simd/examples/nbody.rs b/library/portable-simd/crates/core_simd/examples/nbody.rs
index 43280fe..7b1e684 100644
--- a/library/portable-simd/crates/core_simd/examples/nbody.rs
+++ b/library/portable-simd/crates/core_simd/examples/nbody.rs
@@ -1,11 +1,13 @@
-#![cfg_attr(feature = "std", feature(portable_simd))]
+#![feature(portable_simd)]
+extern crate std_float;
/// Benchmarks game nbody code
/// Taken from the `packed_simd` crate
/// Run this benchmark with `cargo test --example nbody`
-#[cfg(feature = "std")]
mod nbody {
- use core_simd::*;
+ use core_simd::simd::*;
+ #[allow(unused)] // False positive?
+ use std_float::StdFloat;
use std::f64::consts::PI;
const SOLAR_MASS: f64 = 4.0 * PI * PI;
@@ -167,7 +169,6 @@
}
}
-#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
// Good enough for demonstration purposes, not going for strictness here.
@@ -184,7 +185,6 @@
}
fn main() {
- #[cfg(feature = "std")]
{
let (energy_before, energy_after) = nbody::run(1000);
println!("Energy before: {}", energy_before);
diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs
index 6a6d26d..2336572 100644
--- a/library/portable-simd/crates/core_simd/src/intrinsics.rs
+++ b/library/portable-simd/crates/core_simd/src/intrinsics.rs
@@ -39,6 +39,10 @@
/// fptoui/fptosi/uitofp/sitofp
pub(crate) fn simd_cast<T, U>(x: T) -> U;
+ /// follows Rust's `T as U` semantics, including saturating float casts
+ /// which amounts to the same as `simd_cast` for many cases
+ #[cfg(not(bootstrap))]
+ pub(crate) fn simd_as<T, U>(x: T) -> U;
/// neg/fneg
pub(crate) fn simd_neg<T>(x: T) -> T;
@@ -46,6 +50,10 @@
/// fabs
pub(crate) fn simd_fabs<T>(x: T) -> T;
+ // minnum/maxnum
+ pub(crate) fn simd_fmin<T>(x: T, y: T) -> T;
+ pub(crate) fn simd_fmax<T>(x: T, y: T) -> T;
+
pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
pub(crate) fn simd_ne<T, U>(x: T, y: T) -> U;
pub(crate) fn simd_lt<T, U>(x: T, y: T) -> U;
@@ -87,29 +95,3 @@
#[allow(unused)]
pub(crate) fn simd_select_bitmask<M, T>(m: M, a: T, b: T) -> T;
}
-
-#[cfg(feature = "std")]
-mod std {
- extern "platform-intrinsic" {
- // ceil
- pub(crate) fn simd_ceil<T>(x: T) -> T;
-
- // floor
- pub(crate) fn simd_floor<T>(x: T) -> T;
-
- // round
- pub(crate) fn simd_round<T>(x: T) -> T;
-
- // trunc
- pub(crate) fn simd_trunc<T>(x: T) -> T;
-
- // fsqrt
- pub(crate) fn simd_fsqrt<T>(x: T) -> T;
-
- // fma
- pub(crate) fn simd_fma<T>(x: T, y: T, z: T) -> T;
- }
-}
-
-#[cfg(feature = "std")]
-pub(crate) use crate::simd::intrinsics::std::*;
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index 191e969..ae1fef5 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -12,9 +12,10 @@
)]
mod mask_impl;
+use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
use core::cmp::Ordering;
-use core::fmt;
+use core::{fmt, mem};
mod sealed {
use super::*;
@@ -105,22 +106,39 @@
Self(mask_impl::Mask::splat(value))
}
- /// Converts an array to a SIMD vector.
+ /// Converts an array of bools to a SIMD mask.
pub fn from_array(array: [bool; LANES]) -> Self {
- let mut vector = Self::splat(false);
- for (i, v) in array.iter().enumerate() {
- vector.set(i, *v);
+ // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of
+ // true: 0b_0000_0001
+ // false: 0b_0000_0000
+ // Thus, an array of bools is also a valid array of bytes: [u8; N]
+ // This would be hypothetically valid as an "in-place" transmute,
+ // but these are "dependently-sized" types, so copy elision it is!
+ unsafe {
+ let bytes: [u8; LANES] = mem::transmute_copy(&array);
+ let bools: Simd<i8, LANES> =
+ intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8));
+ Mask::from_int_unchecked(intrinsics::simd_cast(bools))
}
- vector
}
- /// Converts a SIMD vector to an array.
+ /// Converts a SIMD mask to an array of bools.
pub fn to_array(self) -> [bool; LANES] {
- let mut array = [false; LANES];
- for (i, v) in array.iter_mut().enumerate() {
- *v = self.test(i);
+ // This follows mostly the same logic as from_array.
+ // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of
+ // true: 0b_0000_0001
+ // false: 0b_0000_0000
+ // Thus, an array of bools is also a valid array of bytes: [u8; N]
+ // Since our masks are equal to integers where all bits are set,
+ // we can simply convert them to i8s, and then bitand them by the
+ // bitpattern for Rust's "true" bool.
+ // This would be hypothetically valid as an "in-place" transmute,
+ // but these are "dependently-sized" types, so copy elision it is!
+ unsafe {
+ let mut bytes: Simd<i8, LANES> = intrinsics::simd_cast(self.to_int());
+ bytes &= Simd::splat(1i8);
+ mem::transmute_copy(&bytes)
}
- array
}
/// Converts a vector of integers to a mask, where 0 represents `false` and -1
@@ -516,7 +534,7 @@
pub type mask16x16 = Mask<i16, 16>;
/// Vector of 32 16-bit masks
-pub type mask16x32 = Mask<i32, 32>;
+pub type mask16x32 = Mask<i16, 32>;
/// Vector of two 32-bit masks
pub type mask32x2 = Mask<i32, 2>;
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index 3582c57..b650389 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -1,4 +1,3 @@
-use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
use core::ops::{Add, Mul};
use core::ops::{BitAnd, BitOr, BitXor};
@@ -32,232 +31,211 @@
}
}
-/// Checks if the right-hand side argument of a left- or right-shift would cause overflow.
-fn invalid_shift_rhs<T>(rhs: T) -> bool
-where
- T: Default + PartialOrd + core::convert::TryFrom<usize>,
- <T as core::convert::TryFrom<usize>>::Error: core::fmt::Debug,
-{
- let bits_in_type = T::try_from(8 * core::mem::size_of::<T>()).unwrap();
- rhs < T::default() || rhs >= bits_in_type
+macro_rules! unsafe_base {
+ ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
+ unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) }
+ };
}
-/// Automatically implements operators over references in addition to the provided operator.
-macro_rules! impl_ref_ops {
- // binary op
- {
- impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
- where
- LaneCount<$lanes2:ident>: SupportedLaneCount,
+/// SAFETY: This macro should not be used for anything except Shl or Shr, and passed the appropriate shift intrinsic.
+/// It handles performing a bitand in addition to calling the shift operator, so that the result
+/// is well-defined: LLVM can return a poison value if you shl, lshr, or ashr if rhs >= <Int>::BITS
+/// At worst, this will maybe add another instruction and cycle,
+/// at best, it may open up more optimization opportunities,
+/// or simply be elided entirely, especially for SIMD ISAs which default to this.
+///
+// FIXME: Consider implementing this in cg_llvm instead?
+// cg_clif defaults to this, and scalar MIR shifts also default to wrapping
+macro_rules! wrap_bitshift {
+ ($lhs:ident, $rhs:ident, {$simd_call:ident}, $int:ident) => {
+ unsafe {
+ $crate::simd::intrinsics::$simd_call(
+ $lhs,
+ $rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)),
+ )
+ }
+ };
+}
+
+// Division by zero is poison, according to LLVM.
+// So is dividing the MIN value of a signed integer by -1,
+// since that would return MAX + 1.
+// FIXME: Rust allows <SInt>::MIN / -1,
+// so we should probably figure out how to make that safe.
+macro_rules! int_divrem_guard {
+ ( $lhs:ident,
+ $rhs:ident,
+ { const PANIC_ZERO: &'static str = $zero:literal;
+ const PANIC_OVERFLOW: &'static str = $overflow:literal;
+ $simd_call:ident
+ },
+ $int:ident ) => {
+ if $rhs.lanes_eq(Simd::splat(0)).any() {
+ panic!($zero);
+ } else if <$int>::MIN != 0
+ && ($lhs.lanes_eq(Simd::splat(<$int>::MIN))
+ // type inference can break here, so cut an SInt to size
+ & $rhs.lanes_eq(Simd::splat(-1i64 as _))).any()
{
- type Output = $output:ty;
-
- $(#[$attrs:meta])*
- fn $fn:ident($self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) -> Self::Output $body:tt
- }
- } => {
- impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- type Output = $output;
-
- $(#[$attrs])*
- fn $fn($self_tok, $rhs_arg: $rhs_arg_ty) -> Self::Output $body
+ panic!($overflow);
+ } else {
+ unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) }
}
};
}
-/// Automatically implements operators over vectors and scalars for a particular vector.
-macro_rules! impl_op {
- { impl Add for $scalar:ty } => {
- impl_op! { @binary $scalar, Add::add, simd_add }
- };
- { impl Sub for $scalar:ty } => {
- impl_op! { @binary $scalar, Sub::sub, simd_sub }
- };
- { impl Mul for $scalar:ty } => {
- impl_op! { @binary $scalar, Mul::mul, simd_mul }
- };
- { impl Div for $scalar:ty } => {
- impl_op! { @binary $scalar, Div::div, simd_div }
- };
- { impl Rem for $scalar:ty } => {
- impl_op! { @binary $scalar, Rem::rem, simd_rem }
- };
- { impl Shl for $scalar:ty } => {
- impl_op! { @binary $scalar, Shl::shl, simd_shl }
- };
- { impl Shr for $scalar:ty } => {
- impl_op! { @binary $scalar, Shr::shr, simd_shr }
- };
- { impl BitAnd for $scalar:ty } => {
- impl_op! { @binary $scalar, BitAnd::bitand, simd_and }
- };
- { impl BitOr for $scalar:ty } => {
- impl_op! { @binary $scalar, BitOr::bitor, simd_or }
- };
- { impl BitXor for $scalar:ty } => {
- impl_op! { @binary $scalar, BitXor::bitxor, simd_xor }
- };
+macro_rules! for_base_types {
+ ( T = ($($scalar:ident),*);
+ type Lhs = Simd<T, N>;
+ type Rhs = Simd<T, N>;
+ type Output = $out:ty;
- // generic binary op with assignment when output is `Self`
- { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $intrinsic:ident } => {
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::$trait<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
+ impl $op:ident::$call:ident {
+ $macro_impl:ident $inner:tt
+ }) => {
+ $(
+ impl<const N: usize> $op<Self> for Simd<$scalar, N>
+ where
+ $scalar: SimdElement,
+ LaneCount<N>: SupportedLaneCount,
+ {
+ type Output = $out;
- #[inline]
- fn $trait_fn(self, rhs: Self) -> Self::Output {
- unsafe {
- intrinsics::$intrinsic(self, rhs)
+ #[inline]
+ #[must_use = "operator returns a new vector without mutating the inputs"]
+ fn $call(self, rhs: Self) -> Self::Output {
+ $macro_impl!(self, rhs, $inner, $scalar)
}
- }
- }
+ })*
+ }
+}
+
+// A "TokenTree muncher": takes a set of scalar types `T = {};`
+// type parameters for the ops it implements, `Op::fn` names,
+// and a macro that expands into an expr, substituting in an intrinsic.
+// It passes that to for_base_types, which expands an impl for the types,
+// using the expanded expr in the function, and recurses with itself.
+//
+// tl;dr impls a set of ops::{Traits} for a set of types
+macro_rules! for_base_ops {
+ (
+ T = $types:tt;
+ type Lhs = Simd<T, N>;
+ type Rhs = Simd<T, N>;
+ type Output = $out:ident;
+ impl $op:ident::$call:ident
+ $inner:tt
+ $($rest:tt)*
+ ) => {
+ for_base_types! {
+ T = $types;
+ type Lhs = Simd<T, N>;
+ type Rhs = Simd<T, N>;
+ type Output = $out;
+ impl $op::$call
+ $inner
+ }
+ for_base_ops! {
+ T = $types;
+ type Lhs = Simd<T, N>;
+ type Rhs = Simd<T, N>;
+ type Output = $out;
+ $($rest)*
}
};
+ ($($done:tt)*) => {
+ // Done.
+ }
}
-/// Implements floating-point operators for the provided types.
-macro_rules! impl_float_ops {
- { $($scalar:ty),* } => {
- $(
- impl_op! { impl Add for $scalar }
- impl_op! { impl Sub for $scalar }
- impl_op! { impl Mul for $scalar }
- impl_op! { impl Div for $scalar }
- impl_op! { impl Rem for $scalar }
- )*
- };
+// Integers can always accept add, mul, sub, bitand, bitor, and bitxor.
+// For all of these operations, simd_* intrinsics apply wrapping logic.
+for_base_ops! {
+ T = (i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
+ type Lhs = Simd<T, N>;
+ type Rhs = Simd<T, N>;
+ type Output = Self;
+
+ impl Add::add {
+ unsafe_base { simd_add }
+ }
+
+ impl Mul::mul {
+ unsafe_base { simd_mul }
+ }
+
+ impl Sub::sub {
+ unsafe_base { simd_sub }
+ }
+
+ impl BitAnd::bitand {
+ unsafe_base { simd_and }
+ }
+
+ impl BitOr::bitor {
+ unsafe_base { simd_or }
+ }
+
+ impl BitXor::bitxor {
+ unsafe_base { simd_xor }
+ }
+
+ impl Div::div {
+ int_divrem_guard {
+ const PANIC_ZERO: &'static str = "attempt to divide by zero";
+ const PANIC_OVERFLOW: &'static str = "attempt to divide with overflow";
+ simd_div
+ }
+ }
+
+ impl Rem::rem {
+ int_divrem_guard {
+ const PANIC_ZERO: &'static str = "attempt to calculate the remainder with a divisor of zero";
+ const PANIC_OVERFLOW: &'static str = "attempt to calculate the remainder with overflow";
+ simd_rem
+ }
+ }
+
+ // The only question is how to handle shifts >= <Int>::BITS?
+ // Our current solution uses wrapping logic.
+ impl Shl::shl {
+ wrap_bitshift { simd_shl }
+ }
+
+ impl Shr::shr {
+ wrap_bitshift {
+ // This automatically monomorphizes to lshr or ashr, depending,
+ // so it's fine to use it for both UInts and SInts.
+ simd_shr
+ }
+ }
}
-/// Implements unsigned integer operators for the provided types.
-macro_rules! impl_unsigned_int_ops {
- { $($scalar:ty),* } => {
- $(
- impl_op! { impl Add for $scalar }
- impl_op! { impl Sub for $scalar }
- impl_op! { impl Mul for $scalar }
- impl_op! { impl BitAnd for $scalar }
- impl_op! { impl BitOr for $scalar }
- impl_op! { impl BitXor for $scalar }
+// We don't need any special precautions here:
+// Floats always accept arithmetic ops, but may become NaN.
+for_base_ops! {
+ T = (f32, f64);
+ type Lhs = Simd<T, N>;
+ type Rhs = Simd<T, N>;
+ type Output = Self;
- // Integers panic on divide by 0
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Div<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
+ impl Add::add {
+ unsafe_base { simd_add }
+ }
- #[inline]
- fn div(self, rhs: Self) -> Self::Output {
- if rhs.as_array()
- .iter()
- .any(|x| *x == 0)
- {
- panic!("attempt to divide by zero");
- }
+ impl Mul::mul {
+ unsafe_base { simd_mul }
+ }
- // Guards for div(MIN, -1),
- // this check only applies to signed ints
- if <$scalar>::MIN != 0 && self.as_array().iter()
- .zip(rhs.as_array().iter())
- .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
- panic!("attempt to divide with overflow");
- }
- unsafe { intrinsics::simd_div(self, rhs) }
- }
- }
- }
+ impl Sub::sub {
+ unsafe_base { simd_sub }
+ }
- // remainder panics on zero divisor
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Rem<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
+ impl Div::div {
+ unsafe_base { simd_div }
+ }
- #[inline]
- fn rem(self, rhs: Self) -> Self::Output {
- if rhs.as_array()
- .iter()
- .any(|x| *x == 0)
- {
- panic!("attempt to calculate the remainder with a divisor of zero");
- }
-
- // Guards for rem(MIN, -1)
- // this branch applies the check only to signed ints
- if <$scalar>::MIN != 0 && self.as_array().iter()
- .zip(rhs.as_array().iter())
- .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
- panic!("attempt to calculate the remainder with overflow");
- }
- unsafe { intrinsics::simd_rem(self, rhs) }
- }
- }
- }
-
- // shifts panic on overflow
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Shl<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn shl(self, rhs: Self) -> Self::Output {
- // TODO there is probably a better way of doing this
- if rhs.as_array()
- .iter()
- .copied()
- .any(invalid_shift_rhs)
- {
- panic!("attempt to shift left with overflow");
- }
- unsafe { intrinsics::simd_shl(self, rhs) }
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Shr<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn shr(self, rhs: Self) -> Self::Output {
- // TODO there is probably a better way of doing this
- if rhs.as_array()
- .iter()
- .copied()
- .any(invalid_shift_rhs)
- {
- panic!("attempt to shift with overflow");
- }
- unsafe { intrinsics::simd_shr(self, rhs) }
- }
- }
- }
- )*
- };
+ impl Rem::rem {
+ unsafe_base { simd_rem }
+ }
}
-
-/// Implements unsigned integer operators for the provided types.
-macro_rules! impl_signed_int_ops {
- { $($scalar:ty),* } => {
- impl_unsigned_int_ops! { $($scalar),* }
- };
-}
-
-impl_unsigned_int_ops! { u8, u16, u32, u64, usize }
-impl_signed_int_ops! { i8, i16, i32, i64, isize }
-impl_float_ops! { f32, f64 }
diff --git a/library/portable-simd/crates/core_simd/src/round.rs b/library/portable-simd/crates/core_simd/src/round.rs
index 09789e1..06ccab3 100644
--- a/library/portable-simd/crates/core_simd/src/round.rs
+++ b/library/portable-simd/crates/core_simd/src/round.rs
@@ -5,47 +5,6 @@
{
$type:ty, $int_type:ty
} => {
- #[cfg(feature = "std")]
- impl<const LANES: usize> Simd<$type, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- /// Returns the smallest integer greater than or equal to each lane.
- #[must_use = "method returns a new vector and does not mutate the original value"]
- #[inline]
- pub fn ceil(self) -> Self {
- unsafe { intrinsics::simd_ceil(self) }
- }
-
- /// Returns the largest integer value less than or equal to each lane.
- #[must_use = "method returns a new vector and does not mutate the original value"]
- #[inline]
- pub fn floor(self) -> Self {
- unsafe { intrinsics::simd_floor(self) }
- }
-
- /// Rounds to the nearest integer value. Ties round toward zero.
- #[must_use = "method returns a new vector and does not mutate the original value"]
- #[inline]
- pub fn round(self) -> Self {
- unsafe { intrinsics::simd_round(self) }
- }
-
- /// Returns the floating point's integer value, with its fractional part removed.
- #[must_use = "method returns a new vector and does not mutate the original value"]
- #[inline]
- pub fn trunc(self) -> Self {
- unsafe { intrinsics::simd_trunc(self) }
- }
-
- /// Returns the floating point's fractional value, with its integer part removed.
- #[must_use = "method returns a new vector and does not mutate the original value"]
- #[inline]
- pub fn fract(self) -> Self {
- self - self.trunc()
- }
- }
-
impl<const LANES: usize> Simd<$type, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index 7c5ec2b..b7ef7a5 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -75,6 +75,36 @@
Self(array)
}
+ /// Performs lanewise conversion of a SIMD vector's elements to another SIMD-valid type.
+ /// This follows the semantics of Rust's `as` conversion for casting
+ /// integers to unsigned integers (interpreting as the other type, so `-1` to `MAX`),
+ /// and from floats to integers (truncating, or saturating at the limits) for each lane,
+ /// or vice versa.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ /// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]);
+ /// let ints = floats.cast::<i32>();
+ /// 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]
+ #[cfg(not(bootstrap))]
+ pub fn cast<U: SimdElement>(self) -> Simd<U, LANES> {
+ unsafe { intrinsics::simd_as(self) }
+ }
+
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
/// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
///
diff --git a/library/portable-simd/crates/core_simd/src/vector/float.rs b/library/portable-simd/crates/core_simd/src/vector/float.rs
index 4a4b232..fcc7f6d 100644
--- a/library/portable-simd/crates/core_simd/src/vector/float.rs
+++ b/library/portable-simd/crates/core_simd/src/vector/float.rs
@@ -38,29 +38,6 @@
unsafe { intrinsics::simd_fabs(self) }
}
- /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error,
- /// yielding a more accurate result than an unfused multiply-add.
- ///
- /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
- /// architecture has a dedicated `fma` CPU instruction. However, this is not always
- /// true, and will be heavily dependent on designing algorithms with specific target
- /// hardware in mind.
- #[cfg(feature = "std")]
- #[inline]
- #[must_use = "method returns a new vector and does not mutate the original value"]
- pub fn mul_add(self, a: Self, b: Self) -> Self {
- unsafe { intrinsics::simd_fma(self, a, b) }
- }
-
- /// Produces a vector where every lane has the square root value
- /// of the equivalently-indexed lane in `self`
- #[inline]
- #[must_use = "method returns a new vector and does not mutate the original value"]
- #[cfg(feature = "std")]
- pub fn sqrt(self) -> Self {
- unsafe { intrinsics::simd_fsqrt(self) }
- }
-
/// Takes the reciprocal (inverse) of each lane, `1/x`.
#[inline]
#[must_use = "method returns a new vector and does not mutate the original value"]
@@ -128,8 +105,8 @@
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
}
- /// Returns true for each lane if its value is neither neither zero, infinite,
- /// subnormal, or `NaN`.
+ /// Returns true for each lane if its value is neither zero, infinite,
+ /// subnormal, nor `NaN`.
#[inline]
#[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
@@ -164,11 +141,7 @@
#[inline]
#[must_use = "method returns a new vector and does not mutate the original value"]
pub fn min(self, other: Self) -> Self {
- // TODO consider using an intrinsic
- self.is_nan().select(
- other,
- self.lanes_ge(other).select(other, self)
- )
+ unsafe { intrinsics::simd_fmin(self, other) }
}
/// Returns the maximum of each lane.
@@ -177,11 +150,7 @@
#[inline]
#[must_use = "method returns a new vector and does not mutate the original value"]
pub fn max(self, other: Self) -> Self {
- // TODO consider using an intrinsic
- self.is_nan().select(
- other,
- self.lanes_le(other).select(other, self)
- )
+ unsafe { intrinsics::simd_fmax(self, other) }
}
/// Restrict each lane to a certain interval unless it is NaN.
diff --git a/library/portable-simd/crates/core_simd/tests/cast.rs b/library/portable-simd/crates/core_simd/tests/cast.rs
new file mode 100644
index 0000000..ab5650f
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/tests/cast.rs
@@ -0,0 +1,37 @@
+#![feature(portable_simd)]
+macro_rules! cast_types {
+ ($start:ident, $($target:ident),*) => {
+ mod $start {
+ use core_simd::simd::Simd;
+ type Vector<const N: usize> = Simd<$start, N>;
+ $(
+ mod $target {
+ use super::*;
+ test_helpers::test_lanes! {
+ fn cast_as<const N: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<N>::cast::<$target>,
+ &|x| x as $target,
+ &|_| true,
+ )
+ }
+ }
+ }
+ )*
+ }
+ };
+}
+
+// The hypothesis is that widening conversions aren't terribly interesting.
+cast_types!(f32, f64, i8, u8, usize, isize);
+cast_types!(f64, f32, i8, u8, usize, isize);
+cast_types!(i8, u8, f32);
+cast_types!(u8, i8, f32);
+cast_types!(i16, u16, i8, u8, f32);
+cast_types!(u16, i16, i8, u8, f32);
+cast_types!(i32, u32, i8, u8, f32, f64);
+cast_types!(u32, i32, i8, u8, f32, f64);
+cast_types!(i64, u64, i8, u8, isize, usize, f32, f64);
+cast_types!(u64, i64, i8, u8, isize, usize, f32, f64);
+cast_types!(isize, usize, i8, u8, f32, f64);
+cast_types!(usize, isize, i8, u8, f32, f64);
diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
index 43ddde4..4fb9de1 100644
--- a/library/portable-simd/crates/core_simd/tests/ops_macros.rs
+++ b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
@@ -546,6 +546,8 @@
#[cfg(feature = "std")]
mod std {
+ use std_float::StdFloat;
+
use super::*;
test_helpers::test_lanes! {
fn sqrt<const LANES: usize>() {
diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs
index 11d617a..1a1bc9e 100644
--- a/library/portable-simd/crates/core_simd/tests/round.rs
+++ b/library/portable-simd/crates/core_simd/tests/round.rs
@@ -3,6 +3,8 @@
macro_rules! float_rounding_test {
{ $scalar:tt, $int_scalar:tt } => {
mod $scalar {
+ use std_float::StdFloat;
+
type Vector<const LANES: usize> = core_simd::Simd<$scalar, LANES>;
type Scalar = $scalar;
type IntScalar = $int_scalar;
diff --git a/library/portable-simd/crates/std_float/Cargo.toml b/library/portable-simd/crates/std_float/Cargo.toml
new file mode 100644
index 0000000..82f66b8
--- /dev/null
+++ b/library/portable-simd/crates/std_float/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "std_float"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+core_simd = { path = "../core_simd" }
+
+[features]
+default = ["as_crate"]
+as_crate = []
diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs
new file mode 100644
index 0000000..4bd4d4c
--- /dev/null
+++ b/library/portable-simd/crates/std_float/src/lib.rs
@@ -0,0 +1,165 @@
+#![cfg_attr(feature = "as_crate", no_std)] // We are std!
+#![cfg_attr(
+ feature = "as_crate",
+ feature(platform_intrinsics),
+ feature(portable_simd)
+)]
+#[cfg(not(feature = "as_crate"))]
+use core::simd;
+#[cfg(feature = "as_crate")]
+use core_simd::simd;
+
+use simd::{LaneCount, Simd, SupportedLaneCount};
+
+#[cfg(feature = "as_crate")]
+mod experimental {
+ pub trait Sealed {}
+}
+
+#[cfg(feature = "as_crate")]
+use experimental as sealed;
+
+use crate::sealed::Sealed;
+
+// "platform intrinsics" are essentially "codegen intrinsics"
+// each of these may be scalarized and lowered to a libm call
+extern "platform-intrinsic" {
+ // ceil
+ fn simd_ceil<T>(x: T) -> T;
+
+ // floor
+ fn simd_floor<T>(x: T) -> T;
+
+ // round
+ fn simd_round<T>(x: T) -> T;
+
+ // trunc
+ fn simd_trunc<T>(x: T) -> T;
+
+ // fsqrt
+ fn simd_fsqrt<T>(x: T) -> T;
+
+ // fma
+ fn simd_fma<T>(x: T, y: T, z: T) -> T;
+}
+
+/// This trait provides a possibly-temporary implementation of float functions
+/// that may, in the absence of hardware support, canonicalize to calling an
+/// operating system's `math.h` dynamically-loaded library (also known as a
+/// shared object). As these conditionally require runtime support, they
+/// should only appear in binaries built assuming OS support: `std`.
+///
+/// However, there is no reason SIMD types, in general, need OS support,
+/// as for many architectures an embedded binary may simply configure that
+/// support itself. This means these types must be visible in `core`
+/// but have these functions available in `std`.
+///
+/// [`f32`] and [`f64`] achieve a similar trick by using "lang items", but
+/// due to compiler limitations, it is harder to implement this approach for
+/// abstract data types like [`Simd`]. From that need, this trait is born.
+///
+/// It is possible this trait will be replaced in some manner in the future,
+/// when either the compiler or its supporting runtime functions are improved.
+/// For now this trait is available to permit experimentation with SIMD float
+/// operations that may lack hardware support, such as `mul_add`.
+pub trait StdFloat: Sealed + Sized {
+ /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error,
+ /// yielding a more accurate result than an unfused multiply-add.
+ ///
+ /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
+ /// architecture has a dedicated `fma` CPU instruction. However, this is not always
+ /// true, and will be heavily dependent on designing algorithms with specific target
+ /// hardware in mind.
+ #[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ fn mul_add(self, a: Self, b: Self) -> Self {
+ unsafe { simd_fma(self, a, b) }
+ }
+
+ /// Produces a vector where every lane has the square root value
+ /// of the equivalently-indexed lane in `self`
+ #[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ fn sqrt(self) -> Self {
+ unsafe { simd_fsqrt(self) }
+ }
+
+ /// Returns the smallest integer greater than or equal to each lane.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ fn ceil(self) -> Self {
+ unsafe { simd_ceil(self) }
+ }
+
+ /// Returns the largest integer value less than or equal to each lane.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ fn floor(self) -> Self {
+ unsafe { simd_floor(self) }
+ }
+
+ /// Rounds to the nearest integer value. Ties round toward zero.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ fn round(self) -> Self {
+ unsafe { simd_round(self) }
+ }
+
+ /// Returns the floating point's integer value, with its fractional part removed.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ fn trunc(self) -> Self {
+ unsafe { simd_trunc(self) }
+ }
+
+ /// Returns the floating point's fractional value, with its integer part removed.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ fn fract(self) -> Self;
+}
+
+impl<const N: usize> Sealed for Simd<f32, N> where LaneCount<N>: SupportedLaneCount {}
+impl<const N: usize> Sealed for Simd<f64, N> where LaneCount<N>: SupportedLaneCount {}
+
+// We can safely just use all the defaults.
+impl<const N: usize> StdFloat for Simd<f32, N>
+where
+ LaneCount<N>: SupportedLaneCount,
+{
+ /// Returns the floating point's fractional value, with its integer part removed.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ fn fract(self) -> Self {
+ self - self.trunc()
+ }
+}
+
+impl<const N: usize> StdFloat for Simd<f64, N>
+where
+ LaneCount<N>: SupportedLaneCount,
+{
+ /// Returns the floating point's fractional value, with its integer part removed.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ fn fract(self) -> Self {
+ self - self.trunc()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use simd::*;
+
+ #[test]
+ fn everything_works() {
+ let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]);
+ let x2 = x + x;
+ let _xc = x.ceil();
+ let _xf = x.floor();
+ let _xr = x.round();
+ let _xt = x.trunc();
+ let _xfma = x.mul_add(x, x);
+ let _xsqrt = x.sqrt();
+ let _ = x2.abs() * x2;
+ }
+}
diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml
index faf460e..db5e2e4 100644
--- a/library/proc_macro/Cargo.toml
+++ b/library/proc_macro/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "proc_macro"
version = "0.0.0"
-edition = "2018"
+edition = "2021"
[dependencies]
std = { path = "../std" }
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index 83a2ac6..9e9750e 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -310,8 +310,7 @@
// NB. the server can't do this because it may use a different libstd.
static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
- let prev = panic::take_hook();
- panic::set_hook(Box::new(move |info| {
+ panic::update_hook(move |prev, info| {
let show = BridgeState::with(|state| match state {
BridgeState::NotConnected => true,
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
@@ -319,7 +318,7 @@
if show {
prev(info)
}
- }));
+ });
});
BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 69af598..c5afca6 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -30,6 +30,7 @@
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
+#![feature(panic_update_hook)]
#![recursion_limit = "256"]
#[unstable(feature = "proc_macro_internals", issue = "27812")]
diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml
index 0f7f006..3371dfa 100644
--- a/library/profiler_builtins/Cargo.toml
+++ b/library/profiler_builtins/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "profiler_builtins"
version = "0.0.0"
-edition = "2018"
+edition = "2021"
[lib]
test = false
diff --git a/library/rustc-std-workspace-alloc/Cargo.toml b/library/rustc-std-workspace-alloc/Cargo.toml
index 1ea4218..049ca3e 100644
--- a/library/rustc-std-workspace-alloc/Cargo.toml
+++ b/library/rustc-std-workspace-alloc/Cargo.toml
@@ -5,7 +5,7 @@
description = """
Hack for the compiler's own build system
"""
-edition = "2018"
+edition = "2021"
[lib]
path = "lib.rs"
diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml
index 01e8b92..ff5cfcb 100644
--- a/library/rustc-std-workspace-core/Cargo.toml
+++ b/library/rustc-std-workspace-core/Cargo.toml
@@ -5,7 +5,7 @@
description = """
Hack for the compiler's own build system
"""
-edition = "2018"
+edition = "2021"
[lib]
path = "lib.rs"
diff --git a/library/rustc-std-workspace-std/Cargo.toml b/library/rustc-std-workspace-std/Cargo.toml
index 811bc78..3a1dc2a 100644
--- a/library/rustc-std-workspace-std/Cargo.toml
+++ b/library/rustc-std-workspace-std/Cargo.toml
@@ -5,7 +5,7 @@
description = """
Hack for the compiler's own build system
"""
-edition = "2018"
+edition = "2021"
[lib]
path = "lib.rs"
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index bf54004..1460965 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -15,11 +15,11 @@
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.67" }
+libc = { version = "0.2.116", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.69" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
-hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.12", 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
@@ -45,7 +45,7 @@
hermit-abi = { version = "0.1.19", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
-wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
+wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
[features]
backtrace = [
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index efd5785..53b4345 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -371,6 +371,7 @@
/// assert_eq!(vec, ["a", "b", "c"]);
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
@@ -448,6 +449,7 @@
/// assert_eq!(vec, [1, 2, 3]);
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
@@ -471,6 +473,7 @@
/// println!("key: {} val: {}", key, val);
/// }
/// ```
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<'_, K, V> {
Iter { base: self.base.iter() }
@@ -500,6 +503,7 @@
/// println!("key: {} val: {}", key, val);
/// }
/// ```
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut { base: self.base.iter_mut() }
@@ -543,6 +547,10 @@
/// Clears the map, returning all key-value pairs as an iterator. Keeps the
/// allocated memory for reuse.
///
+ /// If the returned iterator is dropped before being fully consumed, it
+ /// drops the remaining key-value pairs. The returned iterator keeps a
+ /// mutable borrow on the vector to optimize its implementation.
+ ///
/// # Examples
///
/// ```
@@ -560,6 +568,7 @@
/// assert!(a.is_empty());
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "drain", since = "1.6.0")]
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain { base: self.base.drain() }
@@ -601,6 +610,7 @@
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[unstable(feature = "hash_drain_filter", issue = "59618")]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
where
@@ -624,6 +634,7 @@
/// assert_eq!(map.len(), 4);
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
pub fn retain<F>(&mut self, f: F)
where
@@ -1990,6 +2001,7 @@
type IntoIter = Iter<'a, K, V>;
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> Iter<'a, K, V> {
self.iter()
}
@@ -2001,6 +2013,7 @@
type IntoIter = IterMut<'a, K, V>;
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> IterMut<'a, K, V> {
self.iter_mut()
}
@@ -2030,6 +2043,7 @@
/// let vec: Vec<(&str, i32)> = map.into_iter().collect();
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> IntoIter<K, V> {
IntoIter { base: self.base.into_iter() }
}
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index d9b20ae..30da22b 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -420,8 +420,8 @@
#[test]
fn test_keys() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let keys: Vec<_> = map.keys().cloned().collect();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
@@ -431,8 +431,8 @@
#[test]
fn test_values() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let values: Vec<_> = map.values().cloned().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
@@ -442,8 +442,8 @@
#[test]
fn test_values_mut() {
- let vec = vec![(1, 1), (2, 2), (3, 3)];
- let mut map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 1), (2, 2), (3, 3)];
+ let mut map: HashMap<_, _> = pairs.into_iter().collect();
for value in map.values_mut() {
*value = (*value) * 2
}
@@ -456,8 +456,8 @@
#[test]
fn test_into_keys() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();
assert_eq!(keys.len(), 3);
@@ -468,8 +468,8 @@
#[test]
fn test_into_values() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let values: Vec<_> = map.into_values().collect();
assert_eq!(values.len(), 3);
@@ -817,6 +817,7 @@
}
#[test]
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
fn test_try_reserve() {
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
@@ -828,11 +829,21 @@
"usize::MAX should trigger an overflow!"
);
- assert_matches!(
- empty_bytes.try_reserve(MAX_USIZE / 8).map_err(|e| e.kind()),
- Err(AllocError { .. }),
- "usize::MAX / 8 should trigger an OOM!"
- );
+ if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 16).map_err(|e| e.kind()) {
+ } else {
+ // This may succeed if there is enough free memory. Attempt to
+ // allocate a few more hashmaps to ensure the allocation will fail.
+ let mut empty_bytes2: HashMap<u8, u8> = HashMap::new();
+ let _ = empty_bytes2.try_reserve(MAX_USIZE / 16);
+ let mut empty_bytes3: HashMap<u8, u8> = HashMap::new();
+ let _ = empty_bytes3.try_reserve(MAX_USIZE / 16);
+ let mut empty_bytes4: HashMap<u8, u8> = HashMap::new();
+ assert_matches!(
+ empty_bytes4.try_reserve(MAX_USIZE / 16).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "usize::MAX / 16 should trigger an OOM!"
+ );
+ }
}
#[test]
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 0d08777..200667a 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -185,6 +185,7 @@
/// }
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<'_, T> {
Iter { base: self.base.iter() }
@@ -226,7 +227,12 @@
self.base.is_empty()
}
- /// Clears the set, returning all elements in an iterator.
+ /// Clears the set, returning all elements as an iterator. Keeps the
+ /// allocated memory for reuse.
+ ///
+ /// If the returned iterator is dropped before being fully consumed, it
+ /// drops the remaining elements. The returned iterator keeps a mutable
+ /// borrow on the vector to optimize its implementation.
///
/// # Examples
///
@@ -244,6 +250,7 @@
/// assert!(set.is_empty());
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "drain", since = "1.6.0")]
pub fn drain(&mut self) -> Drain<'_, T> {
Drain { base: self.base.drain() }
@@ -282,6 +289,7 @@
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[unstable(feature = "hash_drain_filter", issue = "59618")]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
where
@@ -304,6 +312,7 @@
/// set.retain(|&k| k % 2 == 0);
/// assert_eq!(set.len(), 3);
/// ```
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
pub fn retain<F>(&mut self, f: F)
where
@@ -528,6 +537,7 @@
/// assert_eq!(diff, [4].iter().collect());
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
Difference { iter: self.iter(), other }
@@ -555,6 +565,7 @@
/// assert_eq!(diff1, [1, 4].iter().collect());
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn symmetric_difference<'a>(
&'a self,
@@ -582,6 +593,7 @@
/// assert_eq!(intersection, [2, 3].iter().collect());
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
if self.len() <= other.len() {
@@ -610,6 +622,7 @@
/// assert_eq!(union, [1, 2, 3, 4].iter().collect());
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
if self.len() >= other.len() {
@@ -1410,6 +1423,7 @@
type IntoIter = Iter<'a, T>;
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
@@ -1441,6 +1455,7 @@
/// }
/// ```
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> IntoIter<T> {
IntoIter { base: self.base.into_iter() }
}
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index 8b00452..b5e81de 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -232,7 +232,7 @@
//! ```
//! use std::collections::VecDeque;
//!
-//! let vec = vec![1, 2, 3, 4];
+//! let vec = [1, 2, 3, 4];
//! let buf: VecDeque<_> = vec.into_iter().collect();
//! ```
//!
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index c069286..5ed9fa9 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -23,6 +23,11 @@
/// Returns the current working directory as a [`PathBuf`].
///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `getcwd` function on Unix
+/// and the `GetCurrentDirectoryW` function on Windows.
+///
/// # Errors
///
/// Returns an [`Err`] if the current working directory value is invalid.
@@ -49,6 +54,11 @@
/// Changes the current working directory to the specified path.
///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `chdir` function on Unix
+/// and the `SetCurrentDirectoryW` function on Windows.
+///
/// Returns an [`Err`] if the operation fails.
///
/// # Examples
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index ea0c230..1a96b9c 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -25,7 +25,7 @@
use crate::borrow::Cow;
use crate::cell;
use crate::char;
-use crate::fmt::{self, Debug, Display};
+use crate::fmt::{self, Debug, Display, Write};
use crate::mem::transmute;
use crate::num;
use crate::str;
@@ -63,7 +63,7 @@
///
/// #[derive(Debug)]
/// struct SuperError {
- /// side: SuperErrorSideKick,
+ /// source: SuperErrorSideKick,
/// }
///
/// impl fmt::Display for SuperError {
@@ -74,7 +74,7 @@
///
/// impl Error for SuperError {
/// fn source(&self) -> Option<&(dyn Error + 'static)> {
- /// Some(&self.side)
+ /// Some(&self.source)
/// }
/// }
///
@@ -90,7 +90,7 @@
/// impl Error for SuperErrorSideKick {}
///
/// fn get_super_error() -> Result<(), SuperError> {
- /// Err(SuperError { side: SuperErrorSideKick })
+ /// Err(SuperError { source: SuperErrorSideKick })
/// }
///
/// fn main() {
@@ -602,25 +602,25 @@
impl Error for alloc::collections::TryReserveError {}
#[unstable(feature = "duration_checked_float", issue = "83400")]
-impl Error for time::FromSecsError {}
+impl Error for time::FromFloatSecsError {}
// Copied from `any.rs`.
impl dyn Error + 'static {
- /// Returns `true` if the boxed type is the same as `T`
+ /// Returns `true` if the inner type is the same as `T`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
// Get `TypeId` of the type this function is instantiated with.
let t = TypeId::of::<T>();
- // Get `TypeId` of the type in the trait object.
- let boxed = self.type_id(private::Internal);
+ // Get `TypeId` of the type in the trait object (`self`).
+ let concrete = self.type_id(private::Internal);
// Compare both `TypeId`s on equality.
- t == boxed
+ t == concrete
}
- /// Returns some reference to the boxed value if it is of type `T`, or
+ /// Returns some reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
@@ -632,7 +632,7 @@
}
}
- /// Returns some mutable reference to the boxed value if it is of type `T`, or
+ /// Returns some mutable reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
@@ -810,3 +810,642 @@
})
}
}
+
+/// An error reporter that print's an error and its sources.
+///
+/// Report also exposes configuration options for formatting the error chain, either entirely on a
+/// single line, or in multi-line format with each cause in the error chain on a new line.
+///
+/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
+/// wrapped error be `Send`, `Sync`, or `'static`.
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(error_reporter)]
+/// use std::error::{Error, Report};
+/// use std::fmt;
+///
+/// #[derive(Debug)]
+/// struct SuperError {
+/// source: SuperErrorSideKick,
+/// }
+///
+/// impl fmt::Display for SuperError {
+/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// write!(f, "SuperError is here!")
+/// }
+/// }
+///
+/// impl Error for SuperError {
+/// fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// Some(&self.source)
+/// }
+/// }
+///
+/// #[derive(Debug)]
+/// struct SuperErrorSideKick;
+///
+/// impl fmt::Display for SuperErrorSideKick {
+/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// write!(f, "SuperErrorSideKick is here!")
+/// }
+/// }
+///
+/// impl Error for SuperErrorSideKick {}
+///
+/// fn get_super_error() -> Result<(), SuperError> {
+/// Err(SuperError { source: SuperErrorSideKick })
+/// }
+///
+/// fn main() {
+/// match get_super_error() {
+/// Err(e) => println!("Error: {}", Report::new(e)),
+/// _ => println!("No error"),
+/// }
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!: SuperErrorSideKick is here!
+/// ```
+///
+/// ## Output consistency
+///
+/// Report prints the same output via `Display` and `Debug`, so it works well with
+/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`:
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// # source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// # write!(f, "SuperError is here!")
+/// # }
+/// # }
+/// # impl Error for SuperError {
+/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// # Some(&self.source)
+/// # }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// # write!(f, "SuperErrorSideKick is here!")
+/// # }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// # Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// get_super_error().map_err(Report::new).unwrap();
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
+/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+/// ```
+///
+/// ## Return from `main`
+///
+/// `Report` also implements `From` for all types that implement [`Error`], this when combined with
+/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
+/// from `main`.
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// # source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// # write!(f, "SuperError is here!")
+/// # }
+/// # }
+/// # impl Error for SuperError {
+/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// # Some(&self.source)
+/// # }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// # write!(f, "SuperErrorSideKick is here!")
+/// # }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// # Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// fn main() -> Result<(), Report> {
+/// get_super_error()?;
+/// Ok(())
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!: SuperErrorSideKick is here!
+/// ```
+///
+/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
+/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
+/// you will need to manually convert and enable those flags.
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// # source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// # write!(f, "SuperError is here!")
+/// # }
+/// # }
+/// # impl Error for SuperError {
+/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// # Some(&self.source)
+/// # }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// # write!(f, "SuperErrorSideKick is here!")
+/// # }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// # Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// fn main() -> Result<(), Report> {
+/// get_super_error()
+/// .map_err(Report::from)
+/// .map_err(|r| r.pretty(true).show_backtrace(true))?;
+/// Ok(())
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!
+///
+/// Caused by:
+/// SuperErrorSideKick is here!
+/// ```
+#[unstable(feature = "error_reporter", issue = "90172")]
+pub struct Report<E = Box<dyn Error>> {
+ /// The error being reported.
+ error: E,
+ /// Whether a backtrace should be included as part of the report.
+ show_backtrace: bool,
+ /// Whether the report should be pretty-printed.
+ pretty: bool,
+}
+
+impl<E> Report<E>
+where
+ Report<E>: From<E>,
+{
+ /// Create a new `Report` from an input error.
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ pub fn new(error: E) -> Report<E> {
+ Self::from(error)
+ }
+}
+
+impl<E> Report<E> {
+ /// Enable pretty-printing the report across multiple lines.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(error_reporter)]
+ /// use std::error::Report;
+ /// # use std::error::Error;
+ /// # use std::fmt;
+ /// # #[derive(Debug)]
+ /// # struct SuperError {
+ /// # source: SuperErrorSideKick,
+ /// # }
+ /// # impl fmt::Display for SuperError {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperError is here!")
+ /// # }
+ /// # }
+ /// # impl Error for SuperError {
+ /// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// # Some(&self.source)
+ /// # }
+ /// # }
+ /// # #[derive(Debug)]
+ /// # struct SuperErrorSideKick;
+ /// # impl fmt::Display for SuperErrorSideKick {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperErrorSideKick is here!")
+ /// # }
+ /// # }
+ /// # impl Error for SuperErrorSideKick {}
+ ///
+ /// let error = SuperError { source: SuperErrorSideKick };
+ /// let report = Report::new(error).pretty(true);
+ /// eprintln!("Error: {:?}", report);
+ /// ```
+ ///
+ /// This example produces the following output:
+ ///
+ /// ```console
+ /// Error: SuperError is here!
+ ///
+ /// Caused by:
+ /// SuperErrorSideKick is here!
+ /// ```
+ ///
+ /// When there are multiple source errors the causes will be numbered in order of iteration
+ /// starting from the outermost error.
+ ///
+ /// ```rust
+ /// #![feature(error_reporter)]
+ /// use std::error::Report;
+ /// # use std::error::Error;
+ /// # use std::fmt;
+ /// # #[derive(Debug)]
+ /// # struct SuperError {
+ /// # source: SuperErrorSideKick,
+ /// # }
+ /// # impl fmt::Display for SuperError {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperError is here!")
+ /// # }
+ /// # }
+ /// # impl Error for SuperError {
+ /// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// # Some(&self.source)
+ /// # }
+ /// # }
+ /// # #[derive(Debug)]
+ /// # struct SuperErrorSideKick {
+ /// # source: SuperErrorSideKickSideKick,
+ /// # }
+ /// # impl fmt::Display for SuperErrorSideKick {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperErrorSideKick is here!")
+ /// # }
+ /// # }
+ /// # impl Error for SuperErrorSideKick {
+ /// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// # Some(&self.source)
+ /// # }
+ /// # }
+ /// # #[derive(Debug)]
+ /// # struct SuperErrorSideKickSideKick;
+ /// # impl fmt::Display for SuperErrorSideKickSideKick {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperErrorSideKickSideKick is here!")
+ /// # }
+ /// # }
+ /// # impl Error for SuperErrorSideKickSideKick { }
+ ///
+ /// let source = SuperErrorSideKickSideKick;
+ /// let source = SuperErrorSideKick { source };
+ /// let error = SuperError { source };
+ /// let report = Report::new(error).pretty(true);
+ /// eprintln!("Error: {:?}", report);
+ /// ```
+ ///
+ /// This example produces the following output:
+ ///
+ /// ```console
+ /// Error: SuperError is here!
+ ///
+ /// Caused by:
+ /// 0: SuperErrorSideKick is here!
+ /// 1: SuperErrorSideKickSideKick is here!
+ /// ```
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ pub fn pretty(mut self, pretty: bool) -> Self {
+ self.pretty = pretty;
+ self
+ }
+
+ /// Display backtrace if available when using pretty output format.
+ ///
+ /// # Examples
+ ///
+ /// **Note**: Report will search for the first `Backtrace` it can find starting from the
+ /// outermost error. In this example it will display the backtrace from the second error in the
+ /// chain, `SuperErrorSideKick`.
+ ///
+ /// ```rust
+ /// #![feature(error_reporter)]
+ /// #![feature(backtrace)]
+ /// # use std::error::Error;
+ /// # use std::fmt;
+ /// use std::error::Report;
+ /// use std::backtrace::Backtrace;
+ ///
+ /// # #[derive(Debug)]
+ /// # struct SuperError {
+ /// # source: SuperErrorSideKick,
+ /// # }
+ /// # impl fmt::Display for SuperError {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperError is here!")
+ /// # }
+ /// # }
+ /// # impl Error for SuperError {
+ /// # fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// # Some(&self.source)
+ /// # }
+ /// # }
+ /// #[derive(Debug)]
+ /// struct SuperErrorSideKick {
+ /// backtrace: Backtrace,
+ /// }
+ ///
+ /// impl SuperErrorSideKick {
+ /// fn new() -> SuperErrorSideKick {
+ /// SuperErrorSideKick { backtrace: Backtrace::force_capture() }
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperErrorSideKick {
+ /// fn backtrace(&self) -> Option<&Backtrace> {
+ /// Some(&self.backtrace)
+ /// }
+ /// }
+ ///
+ /// // The rest of the example is unchanged ...
+ /// # impl fmt::Display for SuperErrorSideKick {
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # write!(f, "SuperErrorSideKick is here!")
+ /// # }
+ /// # }
+ ///
+ /// let source = SuperErrorSideKick::new();
+ /// let error = SuperError { source };
+ /// let report = Report::new(error).pretty(true).show_backtrace(true);
+ /// eprintln!("Error: {:?}", report);
+ /// ```
+ ///
+ /// This example produces something similar to the following output:
+ ///
+ /// ```console
+ /// Error: SuperError is here!
+ ///
+ /// Caused by:
+ /// SuperErrorSideKick is here!
+ ///
+ /// Stack backtrace:
+ /// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new
+ /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0
+ /// 2: rust_out::main
+ /// 3: core::ops::function::FnOnce::call_once
+ /// 4: std::sys_common::backtrace::__rust_begin_short_backtrace
+ /// 5: std::rt::lang_start::{{closure}}
+ /// 6: std::panicking::try
+ /// 7: std::rt::lang_start_internal
+ /// 8: std::rt::lang_start
+ /// 9: main
+ /// 10: __libc_start_main
+ /// 11: _start
+ /// ```
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ pub fn show_backtrace(mut self, show_backtrace: bool) -> Self {
+ self.show_backtrace = show_backtrace;
+ self
+ }
+}
+
+impl<E> Report<E>
+where
+ E: Error,
+{
+ fn backtrace(&self) -> Option<&Backtrace> {
+ // have to grab the backtrace on the first error directly since that error may not be
+ // 'static
+ let backtrace = self.error.backtrace();
+ let backtrace = backtrace.or_else(|| {
+ self.error
+ .source()
+ .map(|source| source.chain().find_map(|source| source.backtrace()))
+ .flatten()
+ });
+ backtrace
+ }
+
+ /// Format the report as a single line.
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.error)?;
+
+ let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+
+ for cause in sources {
+ write!(f, ": {}", cause)?;
+ }
+
+ Ok(())
+ }
+
+ /// Format the report as multiple lines, with each error cause on its own line.
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let error = &self.error;
+
+ write!(f, "{}", error)?;
+
+ if let Some(cause) = error.source() {
+ write!(f, "\n\nCaused by:")?;
+
+ let multiple = cause.source().is_some();
+
+ for (ind, error) in cause.chain().enumerate() {
+ writeln!(f)?;
+ let mut indented = Indented { inner: f };
+ if multiple {
+ write!(indented, "{: >4}: {}", ind, error)?;
+ } else {
+ write!(indented, " {}", error)?;
+ }
+ }
+ }
+
+ if self.show_backtrace {
+ let backtrace = self.backtrace();
+
+ if let Some(backtrace) = backtrace {
+ let backtrace = backtrace.to_string();
+
+ f.write_str("\n\nStack backtrace:\n")?;
+ f.write_str(backtrace.trim_end())?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl Report<Box<dyn Error>> {
+ fn backtrace(&self) -> Option<&Backtrace> {
+ // have to grab the backtrace on the first error directly since that error may not be
+ // 'static
+ let backtrace = self.error.backtrace();
+ let backtrace = backtrace.or_else(|| {
+ self.error
+ .source()
+ .map(|source| source.chain().find_map(|source| source.backtrace()))
+ .flatten()
+ });
+ backtrace
+ }
+
+ /// Format the report as a single line.
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.error)?;
+
+ let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+
+ for cause in sources {
+ write!(f, ": {}", cause)?;
+ }
+
+ Ok(())
+ }
+
+ /// Format the report as multiple lines, with each error cause on its own line.
+ #[unstable(feature = "error_reporter", issue = "90172")]
+ fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let error = &self.error;
+
+ write!(f, "{}", error)?;
+
+ if let Some(cause) = error.source() {
+ write!(f, "\n\nCaused by:")?;
+
+ let multiple = cause.source().is_some();
+
+ for (ind, error) in cause.chain().enumerate() {
+ writeln!(f)?;
+ let mut indented = Indented { inner: f };
+ if multiple {
+ write!(indented, "{: >4}: {}", ind, error)?;
+ } else {
+ write!(indented, " {}", error)?;
+ }
+ }
+ }
+
+ if self.show_backtrace {
+ let backtrace = self.backtrace();
+
+ if let Some(backtrace) = backtrace {
+ let backtrace = backtrace.to_string();
+
+ f.write_str("\n\nStack backtrace:\n")?;
+ f.write_str(backtrace.trim_end())?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<E> From<E> for Report<E>
+where
+ E: Error,
+{
+ fn from(error: E) -> Self {
+ Report { error, show_backtrace: false, pretty: false }
+ }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<'a, E> From<E> for Report<Box<dyn Error + 'a>>
+where
+ E: Error + 'a,
+{
+ fn from(error: E) -> Self {
+ let error = box error;
+ Report { error, show_backtrace: false, pretty: false }
+ }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<E> fmt::Display for Report<E>
+where
+ E: Error,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
+ }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl fmt::Display for Report<Box<dyn Error>> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
+ }
+}
+
+// This type intentionally outputs the same format for `Display` and `Debug`for
+// situations where you unwrap a `Report` or return it from main.
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<E> fmt::Debug for Report<E>
+where
+ Report<E>: fmt::Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/// Wrapper type for indenting the inner source.
+struct Indented<'a, D> {
+ inner: &'a mut D,
+}
+
+impl<T> Write for Indented<'_, T>
+where
+ T: Write,
+{
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ for (i, line) in s.split('\n').enumerate() {
+ if i > 0 {
+ self.inner.write_char('\n')?;
+ self.inner.write_str(" ")?;
+ }
+
+ self.inner.write_str(line)?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs
index 66d6924..eae5f43 100644
--- a/library/std/src/error/tests.rs
+++ b/library/std/src/error/tests.rs
@@ -35,3 +35,408 @@
Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
}
}
+
+use crate::backtrace::Backtrace;
+use crate::error::Report;
+
+#[derive(Debug)]
+struct SuperError {
+ source: SuperErrorSideKick,
+}
+
+impl fmt::Display for SuperError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "SuperError is here!")
+ }
+}
+
+impl Error for SuperError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Some(&self.source)
+ }
+}
+
+#[derive(Debug)]
+struct SuperErrorSideKick;
+
+impl fmt::Display for SuperErrorSideKick {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "SuperErrorSideKick is here!")
+ }
+}
+
+impl Error for SuperErrorSideKick {}
+
+#[test]
+fn single_line_formatting() {
+ let error = SuperError { source: SuperErrorSideKick };
+ let report = Report::new(&error);
+ let actual = report.to_string();
+ let expected = String::from("SuperError is here!: SuperErrorSideKick is here!");
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn multi_line_formatting() {
+ let error = SuperError { source: SuperErrorSideKick };
+ let report = Report::new(&error).pretty(true);
+ let actual = report.to_string();
+ let expected = String::from(
+ "\
+SuperError is here!
+
+Caused by:
+ SuperErrorSideKick is here!",
+ );
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_no_sources_formats_single_line_correctly() {
+ let report = Report::new(SuperErrorSideKick);
+ let actual = report.to_string();
+ let expected = String::from("SuperErrorSideKick is here!");
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_no_sources_formats_multi_line_correctly() {
+ let report = Report::new(SuperErrorSideKick).pretty(true);
+ let actual = report.to_string();
+ let expected = String::from("SuperErrorSideKick is here!");
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_backtrace_outputs_correctly_with_one_source() {
+ let trace = Backtrace::force_capture();
+ let expected = format!(
+ "\
+The source of the error
+
+Caused by:
+ Error with backtrace
+
+Stack backtrace:
+{}",
+ trace
+ );
+ let error = GenericError::new("Error with backtrace");
+ let mut error = GenericError::new_with_source("The source of the error", error);
+ error.backtrace = Some(trace);
+ let report = Report::new(error).pretty(true).show_backtrace(true);
+
+ println!("Error: {}", report);
+ assert_eq!(expected.trim_end(), report.to_string());
+}
+
+#[test]
+fn error_with_backtrace_outputs_correctly_with_two_sources() {
+ let trace = Backtrace::force_capture();
+ let expected = format!(
+ "\
+Error with two sources
+
+Caused by:
+ 0: The source of the error
+ 1: Error with backtrace
+
+Stack backtrace:
+{}",
+ trace
+ );
+ let mut error = GenericError::new("Error with backtrace");
+ error.backtrace = Some(trace);
+ let error = GenericError::new_with_source("The source of the error", error);
+ let error = GenericError::new_with_source("Error with two sources", error);
+ let report = Report::new(error).pretty(true).show_backtrace(true);
+
+ println!("Error: {}", report);
+ assert_eq!(expected.trim_end(), report.to_string());
+}
+
+#[derive(Debug)]
+struct GenericError<D> {
+ message: D,
+ backtrace: Option<Backtrace>,
+ source: Option<Box<dyn Error + 'static>>,
+}
+
+impl<D> GenericError<D> {
+ fn new(message: D) -> GenericError<D> {
+ Self { message, backtrace: None, source: None }
+ }
+
+ fn new_with_source<E>(message: D, source: E) -> GenericError<D>
+ where
+ E: Error + 'static,
+ {
+ let source: Box<dyn Error + 'static> = Box::new(source);
+ let source = Some(source);
+ GenericError { message, backtrace: None, source }
+ }
+}
+
+impl<D> fmt::Display for GenericError<D>
+where
+ D: fmt::Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.message, f)
+ }
+}
+
+impl<D> Error for GenericError<D>
+where
+ D: fmt::Debug + fmt::Display,
+{
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ self.source.as_deref()
+ }
+
+ fn backtrace(&self) -> Option<&Backtrace> {
+ self.backtrace.as_ref()
+ }
+}
+
+#[test]
+fn error_formats_single_line_with_rude_display_impl() {
+ #[derive(Debug)]
+ struct MyMessage;
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("line 1\nline 2")?;
+ f.write_str("\nline 3\nline 4\n")?;
+ f.write_str("line 5\nline 6")?;
+ Ok(())
+ }
+ }
+
+ let error = GenericError::new(MyMessage);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let report = Report::new(error);
+ let expected = "\
+line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6";
+
+ let actual = report.to_string();
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_formats_multi_line_with_rude_display_impl() {
+ #[derive(Debug)]
+ struct MyMessage;
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("line 1\nline 2")?;
+ f.write_str("\nline 3\nline 4\n")?;
+ f.write_str("line 5\nline 6")?;
+ Ok(())
+ }
+ }
+
+ let error = GenericError::new(MyMessage);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let report = Report::new(error).pretty(true);
+ let expected = "line 1
+line 2
+line 3
+line 4
+line 5
+line 6
+
+Caused by:
+ 0: line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ line 6
+ 1: line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ line 6
+ 2: line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ line 6";
+
+ let actual = report.to_string();
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_that_start_with_newline_formats_correctly() {
+ #[derive(Debug)]
+ struct MyMessage;
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("\nThe message\n")
+ }
+ }
+
+ let error = GenericError::new(MyMessage);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let report = Report::new(error).pretty(true);
+ let expected = "
+The message
+
+
+Caused by:
+ 0: \
+\n The message
+ \
+\n 1: \
+\n The message
+ ";
+
+ let actual = report.to_string();
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() {
+ #[derive(Debug)]
+ struct MyMessage;
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("The message")?;
+ f.write_str(" goes on")?;
+ f.write_str(" and on.")
+ }
+ }
+
+ let error = GenericError::new(MyMessage);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let report = Report::new(error).pretty(true);
+ let expected = "\
+The message goes on and on.
+
+Caused by:
+ 0: The message goes on and on.
+ 1: The message goes on and on.";
+
+ let actual = report.to_string();
+ println!("{}", actual);
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_with_string_interpolation_formats_correctly() {
+ #[derive(Debug)]
+ struct MyMessage(usize);
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Got an error code: ({}). ", self.0)?;
+ write!(f, "What would you like to do in response?")
+ }
+ }
+
+ let error = GenericError::new(MyMessage(10));
+ let error = GenericError::new_with_source(MyMessage(20), error);
+ let report = Report::new(error).pretty(true);
+ let expected = "\
+Got an error code: (20). What would you like to do in response?
+
+Caused by:
+ Got an error code: (10). What would you like to do in response?";
+ let actual = report.to_string();
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn empty_lines_mid_message() {
+ #[derive(Debug)]
+ struct MyMessage;
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("line 1\n\nline 2")
+ }
+ }
+
+ let error = GenericError::new(MyMessage);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let report = Report::new(error).pretty(true);
+ let expected = "\
+line 1
+
+line 2
+
+Caused by:
+ 0: line 1
+ \
+\n line 2
+ 1: line 1
+ \
+\n line 2";
+
+ let actual = report.to_string();
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn only_one_source() {
+ #[derive(Debug)]
+ struct MyMessage;
+
+ impl fmt::Display for MyMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("line 1\nline 2")
+ }
+ }
+
+ let error = GenericError::new(MyMessage);
+ let error = GenericError::new_with_source(MyMessage, error);
+ let report = Report::new(error).pretty(true);
+ let expected = "\
+line 1
+line 2
+
+Caused by:
+ line 1
+ line 2";
+
+ let actual = report.to_string();
+ assert_eq!(expected, actual);
+}
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 9c1b79d..1678367 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -373,38 +373,61 @@
/// the position of the nul byte.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
- trait SpecIntoVec {
- fn into_vec(self) -> Vec<u8>;
+ trait SpecNewImpl {
+ fn spec_new_impl(self) -> Result<CString, NulError>;
}
- impl<T: Into<Vec<u8>>> SpecIntoVec for T {
- default fn into_vec(self) -> Vec<u8> {
- self.into()
- }
- }
- // Specialization for avoiding reallocation.
- impl SpecIntoVec for &'_ [u8] {
- fn into_vec(self) -> Vec<u8> {
- let mut v = Vec::with_capacity(self.len() + 1);
- v.extend(self);
- v
- }
- }
- impl SpecIntoVec for &'_ str {
- fn into_vec(self) -> Vec<u8> {
- let mut v = Vec::with_capacity(self.len() + 1);
- v.extend(self.as_bytes());
- v
+
+ impl<T: Into<Vec<u8>>> SpecNewImpl for T {
+ default fn spec_new_impl(self) -> Result<CString, NulError> {
+ let bytes: Vec<u8> = self.into();
+ match memchr::memchr(0, &bytes) {
+ Some(i) => Err(NulError(i, bytes)),
+ None => Ok(unsafe { CString::_from_vec_unchecked(bytes) }),
+ }
}
}
- Self::_new(SpecIntoVec::into_vec(t))
- }
+ // Specialization for avoiding reallocation
+ #[inline(always)] // Without that it is not inlined into specializations
+ fn spec_new_impl_bytes(bytes: &[u8]) -> Result<CString, NulError> {
+ // We cannot have such large slice that we would overflow here
+ // but using `checked_add` allows LLVM to assume that capacity never overflows
+ // and generate twice shorter code.
+ // `saturating_add` doesn't help for some reason.
+ let capacity = bytes.len().checked_add(1).unwrap();
- fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
- match memchr::memchr(0, &bytes) {
- Some(i) => Err(NulError(i, bytes)),
- None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+ // Allocate before validation to avoid duplication of allocation code.
+ // We still need to allocate and copy memory even if we get an error.
+ let mut buffer = Vec::with_capacity(capacity);
+ buffer.extend(bytes);
+
+ // Check memory of self instead of new buffer.
+ // This allows better optimizations if lto enabled.
+ match memchr::memchr(0, bytes) {
+ Some(i) => Err(NulError(i, buffer)),
+ None => Ok(unsafe { CString::_from_vec_unchecked(buffer) }),
+ }
}
+
+ impl SpecNewImpl for &'_ [u8] {
+ fn spec_new_impl(self) -> Result<CString, NulError> {
+ spec_new_impl_bytes(self)
+ }
+ }
+
+ impl SpecNewImpl for &'_ str {
+ fn spec_new_impl(self) -> Result<CString, NulError> {
+ spec_new_impl_bytes(self.as_bytes())
+ }
+ }
+
+ impl SpecNewImpl for &'_ mut [u8] {
+ fn spec_new_impl(self) -> Result<CString, NulError> {
+ spec_new_impl_bytes(self)
+ }
+ }
+
+ t.spec_new_impl()
}
/// Creates a C-compatible string by consuming a byte vector,
@@ -428,10 +451,15 @@
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+ pub unsafe fn from_vec_unchecked(v: Vec<u8>) -> Self {
+ debug_assert!(memchr::memchr(0, &v).is_none());
+ unsafe { Self::_from_vec_unchecked(v) }
+ }
+
+ unsafe fn _from_vec_unchecked(mut v: Vec<u8>) -> Self {
v.reserve_exact(1);
v.push(0);
- CString { inner: v.into_boxed_slice() }
+ Self { inner: v.into_boxed_slice() }
}
/// Retakes ownership of a `CString` that was transferred to C via
@@ -555,7 +583,7 @@
pub fn into_string(self) -> Result<String, IntoStringError> {
String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError {
error: e.utf8_error(),
- inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) },
+ inner: unsafe { Self::_from_vec_unchecked(e.into_bytes()) },
})
}
@@ -712,6 +740,11 @@
#[must_use]
#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
+ debug_assert!(memchr::memchr(0, &v).unwrap() + 1 == v.len());
+ unsafe { Self::_from_vec_with_nul_unchecked(v) }
+ }
+
+ unsafe fn _from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
Self { inner: v.into_boxed_slice() }
}
@@ -755,7 +788,7 @@
Some(nul_pos) if nul_pos + 1 == v.len() => {
// SAFETY: We know there is only one nul byte, at the end
// of the vec.
- Ok(unsafe { Self::from_vec_with_nul_unchecked(v) })
+ Ok(unsafe { Self::_from_vec_with_nul_unchecked(v) })
}
Some(nul_pos) => Err(FromVecWithNulError {
error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos),
@@ -788,7 +821,7 @@
#[inline]
fn deref(&self) -> &CStr {
- unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+ unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
}
}
@@ -848,6 +881,8 @@
#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")]
impl<'a> From<Cow<'a, CStr>> for CString {
+ /// Converts a `Cow<'a, CStr>` into a `CString`, by copying the contents if they are
+ /// borrowed.
#[inline]
fn from(s: Cow<'a, CStr>) -> Self {
s.into_owned()
@@ -856,6 +891,8 @@
#[stable(feature = "box_from_c_str", since = "1.17.0")]
impl From<&CStr> for Box<CStr> {
+ /// Converts a `&CStr` into a `Box<CStr>`,
+ /// by copying the contents into a newly allocated [`Box`].
fn from(s: &CStr) -> Box<CStr> {
let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
@@ -864,6 +901,8 @@
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, CStr>> for Box<CStr> {
+ /// Converts a `Cow<'a, CStr>` into a `Box<CStr>`,
+ /// by copying the contents if they are borrowed.
#[inline]
fn from(cow: Cow<'_, CStr>) -> Box<CStr> {
match cow {
@@ -899,7 +938,7 @@
};
// SAFETY: `v` cannot contain null bytes, given the type-level
// invariant of `NonZeroU8`.
- CString::from_vec_unchecked(v)
+ Self::_from_vec_unchecked(v)
}
}
}
@@ -950,7 +989,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Arc<CStr> {
- /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> without copying or allocating.
+ /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> by moving the [`CString`]
+ /// data into a new [`Arc`] buffer.
#[inline]
fn from(s: CString) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner());
@@ -960,6 +1000,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<&CStr> for Arc<CStr> {
+ /// Converts a `&CStr` into a `Arc<CStr>`,
+ /// by copying the contents into a newly allocated [`Arc`].
#[inline]
fn from(s: &CStr) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
@@ -969,7 +1011,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Rc<CStr> {
- /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> without copying or allocating.
+ /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> by moving the [`CString`]
+ /// data into a new [`Arc`] buffer.
#[inline]
fn from(s: CString) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner());
@@ -979,6 +1022,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<&CStr> for Rc<CStr> {
+ /// Converts a `&CStr` into a `Rc<CStr>`,
+ /// by copying the contents into a newly allocated [`Rc`].
#[inline]
fn from(s: &CStr) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
@@ -1052,7 +1097,7 @@
impl From<NulError> for io::Error {
/// Converts a [`NulError`] into a [`io::Error`].
fn from(_: NulError) -> io::Error {
- io::Error::new_const(io::ErrorKind::InvalidInput, &"data provided contains a nul byte")
+ io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
}
}
@@ -1190,7 +1235,7 @@
unsafe {
let len = sys::strlen(ptr);
let ptr = ptr as *const u8;
- CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+ Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
}
}
@@ -1227,15 +1272,16 @@
/// assert!(cstr.is_err());
/// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
+ pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
let nul_pos = memchr::memchr(0, bytes);
- if let Some(nul_pos) = nul_pos {
- if nul_pos + 1 != bytes.len() {
- return Err(FromBytesWithNulError::interior_nul(nul_pos));
+ match nul_pos {
+ Some(nul_pos) if nul_pos + 1 == bytes.len() => {
+ // SAFETY: We know there is only one nul byte, at the end
+ // of the byte slice.
+ Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) })
}
- Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
- } else {
- Err(FromBytesWithNulError::not_nul_terminated())
+ Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
+ None => Err(FromBytesWithNulError::not_nul_terminated()),
}
}
@@ -1261,12 +1307,19 @@
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
#[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ // We're in a const fn, so this is the best we can do
+ debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
+ unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
+ }
+
+ #[inline]
+ const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
// SAFETY: Casting to CStr is safe because its internal representation
// is a [u8] too (safe only inside std).
// Dereferencing the obtained pointer is safe because it comes from a
// reference. Making a reference is then safe because its lifetime
// is bound by the lifetime of the given `bytes`.
- unsafe { &*(bytes as *const [u8] as *const CStr) }
+ unsafe { &*(bytes as *const [u8] as *const Self) }
}
/// Returns the inner pointer to this C string.
@@ -1504,6 +1557,7 @@
#[stable(feature = "cstring_asref", since = "1.7.0")]
impl From<&CStr> for CString {
+ /// Copies the contents of the `&CStr` into a newly allocated `CString`.
fn from(s: &CStr) -> CString {
s.to_owned()
}
@@ -1529,7 +1583,7 @@
// byte, since otherwise we could get an empty string that doesn't end
// in a null.
if index.start < bytes.len() {
- unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
+ unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) }
} else {
panic!(
"index out of bounds: the len is {} but the index is {}",
diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs
index 4f7ba9a..00ba546 100644
--- a/library/std/src/ffi/c_str/tests.rs
+++ b/library/std/src/ffi/c_str/tests.rs
@@ -33,14 +33,6 @@
}
#[test]
-fn build_with_zero3() {
- unsafe {
- let s = CString::from_vec_unchecked(vec![0]);
- assert_eq!(s.as_bytes(), b"\0");
- }
-}
-
-#[test]
fn formatted() {
let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 982ad18..9b5e5d6 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -452,6 +452,8 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
+ /// Copies any value implementing <code>[AsRef]<[OsStr]></code>
+ /// into a newly allocated [`OsString`].
fn from(s: &T) -> OsString {
s.as_ref().to_os_string()
}
@@ -942,6 +944,7 @@
#[stable(feature = "box_from_os_str", since = "1.17.0")]
impl From<&OsStr> for Box<OsStr> {
+ /// Copies the string into a newly allocated <code>[Box]<[OsStr]></code>.
#[inline]
fn from(s: &OsStr) -> Box<OsStr> {
let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
@@ -951,6 +954,8 @@
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, OsStr>> for Box<OsStr> {
+ /// Converts a `Cow<'a, OsStr>` into a <code>[Box]<[OsStr]></code>,
+ /// by copying the contents if they are borrowed.
#[inline]
fn from(cow: Cow<'_, OsStr>) -> Box<OsStr> {
match cow {
@@ -989,7 +994,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Arc<OsStr> {
- /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> without copying or allocating.
+ /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`]
+ /// data into a new [`Arc`] buffer.
#[inline]
fn from(s: OsString) -> Arc<OsStr> {
let arc = s.inner.into_arc();
@@ -999,6 +1005,7 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<&OsStr> for Arc<OsStr> {
+ /// Copies the string into a newly allocated <code>[Arc]<[OsStr]></code>.
#[inline]
fn from(s: &OsStr) -> Arc<OsStr> {
let arc = s.inner.into_arc();
@@ -1008,7 +1015,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Rc<OsStr> {
- /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> without copying or allocating.
+ /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> by moving the [`OsString`]
+ /// data into a new [`Rc`] buffer.
#[inline]
fn from(s: OsString) -> Rc<OsStr> {
let rc = s.inner.into_rc();
@@ -1018,6 +1026,7 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<&OsStr> for Rc<OsStr> {
+ /// Copies the string into a newly allocated <code>[Rc]<[OsStr]></code>.
#[inline]
fn from(s: &OsStr) -> Rc<OsStr> {
let rc = s.inner.into_rc();
@@ -1027,6 +1036,7 @@
#[stable(feature = "cow_from_osstr", since = "1.28.0")]
impl<'a> From<OsString> for Cow<'a, OsStr> {
+ /// Moves the string into a [`Cow::Owned`].
#[inline]
fn from(s: OsString) -> Cow<'a, OsStr> {
Cow::Owned(s)
@@ -1035,6 +1045,7 @@
#[stable(feature = "cow_from_osstr", since = "1.28.0")]
impl<'a> From<&'a OsStr> for Cow<'a, OsStr> {
+ /// Converts the string reference into a [`Cow::Borrowed`].
#[inline]
fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
Cow::Borrowed(s)
@@ -1043,6 +1054,7 @@
#[stable(feature = "cow_from_osstr", since = "1.28.0")]
impl<'a> From<&'a OsString> for Cow<'a, OsStr> {
+ /// Converts the string reference into a [`Cow::Borrowed`].
#[inline]
fn from(s: &'a OsString) -> Cow<'a, OsStr> {
Cow::Borrowed(s.as_os_str())
@@ -1051,6 +1063,8 @@
#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")]
impl<'a> From<Cow<'a, OsStr>> for OsString {
+ /// Converts a `Cow<'a, OsStr>` into an [`OsString`],
+ /// by copying the contents if they are borrowed.
#[inline]
fn from(s: Cow<'a, OsStr>) -> Self {
s.into_owned()
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 0e136332..0b65336 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -356,9 +356,10 @@
/// open or create a file with specific options if `open()` or `create()`
/// are not appropriate.
///
- /// It is equivalent to `OpenOptions::new()` but allows you to write more
- /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")`
- /// you can write `File::options().read(true).open("foo.txt")`. This
+ /// It is equivalent to `OpenOptions::new()`, but allows you to write more
+ /// readable code. Instead of
+ /// `OpenOptions::new().append(true).open("example.log")`,
+ /// you can write `File::options().append(true).open("example.log")`. This
/// also avoids the need to import `OpenOptions`.
///
/// See the [`OpenOptions::new`] function for more details.
@@ -369,7 +370,7 @@
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
- /// let mut f = File::options().read(true).open("foo.txt")?;
+ /// let mut f = File::options().append(true).open("example.log")?;
/// Ok(())
/// }
/// ```
@@ -1049,7 +1050,7 @@
///
/// fn main() -> std::io::Result<()> {
/// let link_path = Path::new("link");
- /// symlink("/origin_does_not_exists/", link_path)?;
+ /// symlink("/origin_does_not_exist/", link_path)?;
///
/// let metadata = fs::symlink_metadata(link_path)?;
///
@@ -2043,7 +2044,7 @@
///
/// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions
/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`,
-/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtOpenFile` functions on
+/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile` functions on
/// Windows. Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
@@ -2262,9 +2263,9 @@
match path.parent() {
Some(p) => self.create_dir_all(p)?,
None => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"failed to create whole tree",
+ "failed to create whole tree",
));
}
}
@@ -2287,7 +2288,7 @@
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `Ok(false)`.
///
-/// As opposed to the `exists()` method, this one doesn't silently ignore errors
+/// As opposed to the [`Path::exists`] method, this one doesn't silently ignore errors
/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
/// denied on some of the parent directories.)
///
@@ -2300,6 +2301,8 @@
/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt"));
/// assert!(fs::try_exists("/root/secret_file.txt").is_err());
/// ```
+///
+/// [`Path::exists`]: crate::path::Path::exists
// FIXME: stabilization should modify documentation of `exists()` to recommend this method
// instead.
#[unstable(feature = "path_try_exists", issue = "83186")]
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index a62c01e..16b8bf6 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1504,3 +1504,19 @@
let path = Path::new("");
assert_eq!(path.canonicalize().unwrap_err().kind(), crate::io::ErrorKind::NotFound);
}
+
+/// Ensure ReadDir works on large directories.
+/// Regression test for https://github.com/rust-lang/rust/issues/93384.
+#[test]
+fn read_large_dir() {
+ let tmpdir = tmpdir();
+
+ let count = 32 * 1024;
+ for i in 0..count {
+ check!(fs::File::create(tmpdir.join(&i.to_string())));
+ }
+
+ for entry in fs::read_dir(tmpdir.path()).unwrap() {
+ entry.unwrap();
+ }
+}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index b56dc65..e7eee44 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -357,9 +357,9 @@
let mut bytes = Vec::new();
self.read_to_end(&mut bytes)?;
let string = crate::str::from_utf8(&bytes).map_err(|_| {
- io::Error::new_const(
+ io::const_io_error!(
io::ErrorKind::InvalidData,
- &"stream did not contain valid UTF-8",
+ "stream did not contain valid UTF-8",
)
})?;
*buf += string;
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index c7423e4..2d3a0f3 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -1,7 +1,7 @@
use crate::error;
use crate::fmt;
use crate::io::{
- self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+ self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
};
use crate::mem;
use crate::ptr;
@@ -168,9 +168,9 @@
match r {
Ok(0) => {
- return Err(Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::WriteZero,
- &"failed to write the buffered data",
+ "failed to write the buffered data",
));
}
Ok(n) => guard.consume(n),
diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs
index 179bdf7..100dab1 100644
--- a/library/std/src/io/buffered/mod.rs
+++ b/library/std/src/io/buffered/mod.rs
@@ -12,12 +12,12 @@
use crate::fmt;
use crate::io::Error;
-pub use bufreader::BufReader;
-pub use bufwriter::BufWriter;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter};
+use linewritershim::LineWriterShim;
+
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use bufwriter::WriterPanicked;
-pub use linewriter::LineWriter;
-use linewritershim::LineWriterShim;
/// An error returned by [`BufWriter::into_inner`] which combines an error that
/// happened while writing out the buffer, and the buffered writer object
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 416cc90..fc19704 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -4,7 +4,7 @@
use crate::io::prelude::*;
use crate::cmp;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use core::convert::TryInto;
@@ -297,9 +297,9 @@
self.pos = n;
Ok(self.pos)
}
- None => Err(Error::new_const(
+ None => Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid seek to a negative or overflowing position",
+ "invalid seek to a negative or overflowing position",
)),
}
}
@@ -400,9 +400,9 @@
// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
- Error::new_const(
+ io::const_io_error!(
ErrorKind::InvalidInput,
- &"cursor position exceeds maximum possible vector length",
+ "cursor position exceeds maximum possible vector length",
)
})?;
// Make sure the internal buffer is as least as big as where we
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 210a9ec..1aa6d65 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -1,6 +1,16 @@
#[cfg(test)]
mod tests;
+#[cfg(target_pointer_width = "64")]
+mod repr_bitpacked;
+#[cfg(target_pointer_width = "64")]
+use repr_bitpacked::Repr;
+
+#[cfg(not(target_pointer_width = "64"))]
+mod repr_unpacked;
+#[cfg(not(target_pointer_width = "64"))]
+use repr_unpacked::Repr;
+
use crate::convert::From;
use crate::error;
use crate::fmt;
@@ -66,15 +76,58 @@
}
}
-enum Repr {
+// Only derive debug in tests, to make sure it
+// doesn't accidentally get printed.
+#[cfg_attr(test, derive(Debug))]
+enum ErrorData<C> {
Os(i32),
Simple(ErrorKind),
- // &str is a fat pointer, but &&str is a thin pointer.
- SimpleMessage(ErrorKind, &'static &'static str),
- Custom(Box<Custom>),
+ SimpleMessage(&'static SimpleMessage),
+ Custom(C),
}
+// `#[repr(align(4))]` is probably redundant, it should have that value or
+// higher already. We include it just because repr_bitpacked.rs's encoding
+// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
+// alignment required by the struct, only increase it).
+//
+// If we add more variants to ErrorData, this can be increased to 8, but it
+// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
+// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
+// that version needs the alignment, and 8 is higher than the alignment we'll
+// have on 32 bit platforms.
+//
+// (For the sake of being explicit: the alignment requirement here only matters
+// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
+// matter at all)
+#[repr(align(4))]
#[derive(Debug)]
+pub(crate) struct SimpleMessage {
+ kind: ErrorKind,
+ message: &'static str,
+}
+
+impl SimpleMessage {
+ pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
+ Self { kind, message }
+ }
+}
+
+/// Create and return an `io::Error` for a given `ErrorKind` and constant
+/// message. This doesn't allocate.
+pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) {
+ $crate::io::error::Error::from_static_message({
+ const MESSAGE_DATA: $crate::io::error::SimpleMessage =
+ $crate::io::error::SimpleMessage::new($kind, $message);
+ &MESSAGE_DATA
+ })
+}
+
+// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
+// repr_bitpacked's encoding requires it. In practice it almost certainly be
+// already be this high or higher.
+#[derive(Debug)]
+#[repr(align(4))]
struct Custom {
kind: ErrorKind,
error: Box<dyn error::Error + Send + Sync>,
@@ -243,12 +296,11 @@
/// The filesystem does not support making so many hardlinks to the same file.
#[unstable(feature = "io_error_more", issue = "86442")]
TooManyLinks,
- /// Filename too long.
+ /// A filename was invalid.
///
- /// The limit might be from the underlying filesystem or API, or an administratively imposed
- /// resource limit.
+ /// This error can also cause if it exceeded the filename length limit.
#[unstable(feature = "io_error_more", issue = "86442")]
- FilenameTooLong,
+ InvalidFilename,
/// Program argument list too long.
///
/// When trying to run an external program, a system or process limit on the size of the
@@ -329,12 +381,12 @@
DirectoryNotEmpty => "directory not empty",
ExecutableFileBusy => "executable file busy",
FileTooLarge => "file too large",
- FilenameTooLong => "filename too long",
FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
FilesystemQuotaExceeded => "filesystem quota exceeded",
HostUnreachable => "host unreachable",
Interrupted => "operation interrupted",
InvalidData => "invalid data",
+ InvalidFilename => "invalid filename",
InvalidInput => "invalid input parameter",
IsADirectory => "is a directory",
NetworkDown => "network down",
@@ -361,13 +413,29 @@
}
}
+#[stable(feature = "io_errorkind_display", since = "1.60.0")]
+impl fmt::Display for ErrorKind {
+ /// Shows a human-readable description of the `ErrorKind`.
+ ///
+ /// This is similar to `impl Display for Error`, but doesn't require first converting to Error.
+ ///
+ /// # Examples
+ /// ```
+ /// use std::io::ErrorKind;
+ /// assert_eq!("entity not found", ErrorKind::NotFound.to_string());
+ /// ```
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.write_str(self.as_str())
+ }
+}
+
/// Intended for use for errors not exposed to the user, where allocating onto
/// the heap (for normal construction via Error::new) is too costly.
#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
impl From<ErrorKind> for Error {
/// Converts an [`ErrorKind`] into an [`Error`].
///
- /// This conversion allocates a new error with a simple representation of error kind.
+ /// This conversion creates a new error with a simple representation of error kind.
///
/// # Examples
///
@@ -380,7 +448,7 @@
/// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
- Error { repr: Repr::Simple(kind) }
+ Error { repr: Repr::new_simple(kind) }
}
}
@@ -445,20 +513,22 @@
}
fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
- Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
+ Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) }
}
- /// Creates a new I/O error from a known kind of error as well as a
- /// constant message.
+ /// Creates a new I/O error from a known kind of error as well as a constant
+ /// message.
///
/// This function does not allocate.
///
- /// This function should maybe change to
- /// `new_const<const MSG: &'static str>(kind: ErrorKind)`
- /// in the future, when const generics allow that.
+ /// You should not use this directly, and instead use the `const_io_error!`
+ /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`.
+ ///
+ /// This function should maybe change to `from_static_message<const MSG: &'static
+ /// str>(kind: ErrorKind)` in the future, when const generics allow that.
#[inline]
- pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -> Error {
- Self { repr: Repr::SimpleMessage(kind, message) }
+ pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
+ Self { repr: Repr::new_simple_message(msg) }
}
/// Returns an error representing the last OS error which occurred.
@@ -516,7 +586,7 @@
#[must_use]
#[inline]
pub fn from_raw_os_error(code: i32) -> Error {
- Error { repr: Repr::Os(code) }
+ Error { repr: Repr::new_os(code) }
}
/// Returns the OS error that this error represents (if any).
@@ -552,11 +622,11 @@
#[must_use]
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
- match self.repr {
- Repr::Os(i) => Some(i),
- Repr::Custom(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
+ match self.repr.data() {
+ ErrorData::Os(i) => Some(i),
+ ErrorData::Custom(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
}
}
@@ -591,11 +661,11 @@
#[must_use]
#[inline]
pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref c) => Some(&*c.error),
+ match self.repr.data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => Some(&*c.error),
}
}
@@ -665,11 +735,11 @@
#[must_use]
#[inline]
pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref mut c) => Some(&mut *c.error),
+ match self.repr.data_mut() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => Some(&mut *c.error),
}
}
@@ -704,11 +774,11 @@
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(c) => Some(c.error),
+ match self.repr.into_data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => Some(c.error),
}
}
@@ -734,29 +804,31 @@
#[must_use]
#[inline]
pub fn kind(&self) -> ErrorKind {
- match self.repr {
- Repr::Os(code) => sys::decode_error_kind(code),
- Repr::Custom(ref c) => c.kind,
- Repr::Simple(kind) => kind,
- Repr::SimpleMessage(kind, _) => kind,
+ match self.repr.data() {
+ ErrorData::Os(code) => sys::decode_error_kind(code),
+ ErrorData::Custom(c) => c.kind,
+ ErrorData::Simple(kind) => kind,
+ ErrorData::SimpleMessage(m) => m.kind,
}
}
}
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Repr::Os(code) => fmt
+ match self.data() {
+ ErrorData::Os(code) => fmt
.debug_struct("Os")
.field("code", &code)
.field("kind", &sys::decode_error_kind(code))
.field("message", &sys::os::error_string(code))
.finish(),
- Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
- Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
- Repr::SimpleMessage(kind, &message) => {
- fmt.debug_struct("Error").field("kind", &kind).field("message", &message).finish()
- }
+ ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
+ ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+ ErrorData::SimpleMessage(msg) => fmt
+ .debug_struct("Error")
+ .field("kind", &msg.kind)
+ .field("message", &msg.message)
+ .finish(),
}
}
}
@@ -764,14 +836,14 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.repr {
- Repr::Os(code) => {
+ match self.repr.data() {
+ ErrorData::Os(code) => {
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
- Repr::Custom(ref c) => c.error.fmt(fmt),
- Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
- Repr::SimpleMessage(_, &msg) => msg.fmt(fmt),
+ ErrorData::Custom(ref c) => c.error.fmt(fmt),
+ ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+ ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
}
}
}
@@ -780,29 +852,29 @@
impl error::Error for Error {
#[allow(deprecated, deprecated_in_future)]
fn description(&self) -> &str {
- match self.repr {
- Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
- Repr::SimpleMessage(_, &msg) => msg,
- Repr::Custom(ref c) => c.error.description(),
+ match self.repr.data() {
+ ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(),
+ ErrorData::SimpleMessage(msg) => msg.message,
+ ErrorData::Custom(c) => c.error.description(),
}
}
#[allow(deprecated)]
fn cause(&self) -> Option<&dyn error::Error> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref c) => c.error.cause(),
+ match self.repr.data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => c.error.cause(),
}
}
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref c) => c.error.source(),
+ match self.repr.data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => c.error.source(),
}
}
}
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
new file mode 100644
index 0000000..17d07ff
--- /dev/null
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -0,0 +1,401 @@
+//! This is a densely packed error representation which is used on targets with
+//! 64-bit pointers.
+//!
+//! (Note that `bitpacked` vs `unpacked` here has no relationship to
+//! `#[repr(packed)]`, it just refers to attempting to use any available bits in
+//! a more clever manner than `rustc`'s default layout algorithm would).
+//!
+//! Conceptually, it stores the same data as the "unpacked" equivalent we use on
+//! other targets. Specifically, you can imagine it as an optimized version of
+//! the following enum (which is roughly equivalent to what's stored by
+//! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`):
+//!
+//! ```ignore (exposition-only)
+//! enum ErrorData {
+//! Os(i32),
+//! Simple(ErrorKind),
+//! SimpleMessage(&'static SimpleMessage),
+//! Custom(Box<Custom>),
+//! }
+//! ```
+//!
+//! However, it packs this data into a 64bit non-zero value.
+//!
+//! This optimization not only allows `io::Error` to occupy a single pointer,
+//! but improves `io::Result` as well, especially for situations like
+//! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now
+//! 128 bits), which are quite common.
+//!
+//! # Layout
+//! Tagged values are 64 bits, with the 2 least significant bits used for the
+//! tag. This means there are there are 4 "variants":
+//!
+//! - **Tag 0b00**: The first variant is equivalent to
+//! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly.
+//!
+//! `SimpleMessage` has an alignment >= 4 (which is requested with
+//! `#[repr(align)]` and checked statically at the bottom of this file), which
+//! means every `&'static SimpleMessage` should have the both tag bits as 0,
+//! meaning its tagged and untagged representation are equivalent.
+//!
+//! This means we can skip tagging it, which is necessary as this variant can
+//! be constructed from a `const fn`, which probably cannot tag pointers (or
+//! at least it would be difficult).
+//!
+//! - **Tag 0b01**: The other pointer variant holds the data for
+//! `ErrorData::Custom` and the remaining 62 bits are used to store a
+//! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
+//! are free to use for the tag.
+//!
+//! The only important thing to note is that `ptr::wrapping_add` and
+//! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise
+//! operations. This should preserve the pointer's provenance, which would
+//! otherwise be lost.
+//!
+//! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
+//! in the pointer's most significant 32 bits, and don't use the bits `2..32`
+//! for anything. Using the top 32 bits is just to let us easily recover the
+//! `i32` code with the correct sign.
+//!
+//! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This
+//! stores the `ErrorKind` in the top 32 bits as well, although it doesn't
+//! occupy nearly that many. Most of the bits are unused here, but it's not
+//! like we need them for anything else yet.
+//!
+//! # Use of `NonNull<()>`
+//!
+//! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a
+//! purpose.
+//!
+//! Conceptually you might think of this more like:
+//!
+//! ```ignore (exposition-only)
+//! union Repr {
+//! // holds integer (Simple/Os) variants, and
+//! // provides access to the tag bits.
+//! bits: NonZeroU64,
+//! // Tag is 0, so this is stored untagged.
+//! msg: &'static SimpleMessage,
+//! // Tagged (offset) `Box<Custom>` pointer.
+//! tagged_custom: NonNull<()>,
+//! }
+//! ```
+//!
+//! But there are a few problems with this:
+//!
+//! 1. Union access is equivalent to a transmute, so this representation would
+//! require we transmute between integers and pointers in at least one
+//! direction, which may be UB (and even if not, it is likely harder for a
+//! compiler to reason about than explicit ptr->int operations).
+//!
+//! 2. Even if all fields of a union have a niche, the union itself doesn't,
+//! although this may change in the future. This would make things like
+//! `io::Result<()>` and `io::Result<usize>` larger, which defeats part of
+//! the motivation of this bitpacking.
+//!
+//! Storing everything in a `NonZeroUsize` (or some other integer) would be a
+//! bit more traditional for pointer tagging, but it would lose provenance
+//! information, couldn't be constructed from a `const fn`, and would probably
+//! run into other issues as well.
+//!
+//! The `NonNull<()>` seems like the only alternative, even if it's fairly odd
+//! to use a pointer type to store something that may hold an integer, some of
+//! the time.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc::boxed::Box;
+use core::marker::PhantomData;
+use core::mem::{align_of, size_of};
+use core::ptr::NonNull;
+
+// The 2 least-significant bits are used as tag.
+const TAG_MASK: usize = 0b11;
+const TAG_SIMPLE_MESSAGE: usize = 0b00;
+const TAG_CUSTOM: usize = 0b01;
+const TAG_OS: usize = 0b10;
+const TAG_SIMPLE: usize = 0b11;
+
+/// The internal representation.
+///
+/// See the module docs for more, this is just a way to hack in a check that we
+/// indeed are not unwind-safe.
+///
+/// ```compile_fail,E0277
+/// fn is_unwind_safe<T: core::panic::UnwindSafe>() {}
+/// is_unwind_safe::<std::io::Error>();
+/// ```
+#[repr(transparent)]
+pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
+
+// All the types `Repr` stores internally are Send + Sync, and so is it.
+unsafe impl Send for Repr {}
+unsafe impl Sync for Repr {}
+
+impl Repr {
+ pub(super) fn new_custom(b: Box<Custom>) -> Self {
+ let p = Box::into_raw(b).cast::<u8>();
+ // Should only be possible if an allocator handed out a pointer with
+ // wrong alignment.
+ debug_assert_eq!((p as usize & TAG_MASK), 0);
+ // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
+ // end of file), and both the start and end of the expression must be
+ // valid without address space wraparound due to `Box`'s semantics.
+ //
+ // This means it would be correct to implement this using `ptr::add`
+ // (rather than `ptr::wrapping_add`), but it's unclear this would give
+ // any benefit, so we just use `wrapping_add` instead.
+ let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>();
+ // Safety: `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`,
+ // because `p`'s alignment means it isn't allowed to have any of the
+ // `TAG_BITS` set (you can verify that addition and bitwise-or are the
+ // same when the operands have no bits in common using a truth table).
+ //
+ // Then, `TAG_CUSTOM | p` is not zero, as that would require
+ // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a
+ // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
+ // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
+ // `new_unchecked` is safe.
+ let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
+ // quickly smoke-check we encoded the right thing (This generally will
+ // only run in libstd's tests, unless the user uses -Zbuild-std)
+ debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
+ res
+ }
+
+ #[inline]
+ pub(super) fn new_os(code: i32) -> Self {
+ let utagged = ((code as usize) << 32) | TAG_OS;
+ // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
+ let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
+ // quickly smoke-check we encoded the right thing (This generally will
+ // only run in libstd's tests, unless the user uses -Zbuild-std)
+ debug_assert!(
+ matches!(res.data(), ErrorData::Os(c) if c == code),
+ "repr(os) encoding failed for {}",
+ code,
+ );
+ res
+ }
+
+ #[inline]
+ pub(super) fn new_simple(kind: ErrorKind) -> Self {
+ let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
+ // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
+ let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
+ // quickly smoke-check we encoded the right thing (This generally will
+ // only run in libstd's tests, unless the user uses -Zbuild-std)
+ debug_assert!(
+ matches!(res.data(), ErrorData::Simple(k) if k == kind),
+ "repr(simple) encoding failed {:?}",
+ kind,
+ );
+ res
+ }
+
+ #[inline]
+ pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+ // Safety: References are never null.
+ Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData)
+ }
+
+ #[inline]
+ pub(super) fn data(&self) -> ErrorData<&Custom> {
+ // Safety: We're a Repr, decode_repr is fine.
+ unsafe { decode_repr(self.0, |c| &*c) }
+ }
+
+ #[inline]
+ pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+ // Safety: We're a Repr, decode_repr is fine.
+ unsafe { decode_repr(self.0, |c| &mut *c) }
+ }
+
+ #[inline]
+ pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+ let this = core::mem::ManuallyDrop::new(self);
+ // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
+ // safe because we prevent double-drop using `ManuallyDrop`.
+ unsafe { decode_repr(this.0, |p| Box::from_raw(p)) }
+ }
+}
+
+impl Drop for Repr {
+ #[inline]
+ fn drop(&mut self) {
+ // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
+ // safe because we're being dropped.
+ unsafe {
+ let _ = decode_repr(self.0, |p| Box::<Custom>::from_raw(p));
+ }
+ }
+}
+
+// Shared helper to decode a `Repr`'s internal pointer into an ErrorData.
+//
+// Safety: `ptr`'s bits should be encoded as described in the document at the
+// top (it should `some_repr.0`)
+#[inline]
+unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
+where
+ F: FnOnce(*mut Custom) -> C,
+{
+ let bits = ptr.as_ptr() as usize;
+ match bits & TAG_MASK {
+ TAG_OS => {
+ let code = ((bits as i64) >> 32) as i32;
+ ErrorData::Os(code)
+ }
+ TAG_SIMPLE => {
+ let kind_bits = (bits >> 32) as u32;
+ let kind = kind_from_prim(kind_bits).unwrap_or_else(|| {
+ debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits);
+ // This means the `ptr` passed in was not valid, which violates
+ // the unsafe contract of `decode_repr`.
+ //
+ // Using this rather than unwrap meaningfully improves the code
+ // for callers which only care about one variant (usually
+ // `Custom`)
+ core::hint::unreachable_unchecked();
+ });
+ ErrorData::Simple(kind)
+ }
+ TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
+ TAG_CUSTOM => {
+ // It would be correct for us to use `ptr::sub` here (see the
+ // comment above the `wrapping_add` call in `new_custom` for why),
+ // but it isn't clear that it makes a difference, so we don't.
+ let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
+ ErrorData::Custom(make_custom(custom))
+ }
+ _ => {
+ // Can't happen, and compiler can tell
+ unreachable!();
+ }
+ }
+}
+
+// This compiles to the same code as the check+transmute, but doesn't require
+// unsafe, or to hard-code max ErrorKind or its size in a way the compiler
+// couldn't verify.
+#[inline]
+fn kind_from_prim(ek: u32) -> Option<ErrorKind> {
+ macro_rules! from_prim {
+ ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{
+ // Force a compile error if the list gets out of date.
+ const _: fn(e: $Enum) = |e: $Enum| match e {
+ $($Enum::$Variant => ()),*
+ };
+ match $prim {
+ $(v if v == ($Enum::$Variant as _) => Some($Enum::$Variant),)*
+ _ => None,
+ }
+ }}
+ }
+ from_prim!(ek => ErrorKind {
+ NotFound,
+ PermissionDenied,
+ ConnectionRefused,
+ ConnectionReset,
+ HostUnreachable,
+ NetworkUnreachable,
+ ConnectionAborted,
+ NotConnected,
+ AddrInUse,
+ AddrNotAvailable,
+ NetworkDown,
+ BrokenPipe,
+ AlreadyExists,
+ WouldBlock,
+ NotADirectory,
+ IsADirectory,
+ DirectoryNotEmpty,
+ ReadOnlyFilesystem,
+ FilesystemLoop,
+ StaleNetworkFileHandle,
+ InvalidInput,
+ InvalidData,
+ TimedOut,
+ WriteZero,
+ StorageFull,
+ NotSeekable,
+ FilesystemQuotaExceeded,
+ FileTooLarge,
+ ResourceBusy,
+ ExecutableFileBusy,
+ Deadlock,
+ CrossesDevices,
+ TooManyLinks,
+ InvalidFilename,
+ ArgumentListTooLong,
+ Interrupted,
+ Other,
+ UnexpectedEof,
+ Unsupported,
+ OutOfMemory,
+ Uncategorized,
+ })
+}
+
+// Some static checking to alert us if a change breaks any of the assumptions
+// that our encoding relies on for correctness and soundness. (Some of these are
+// a bit overly thorough/cautious, admittedly)
+//
+// If any of these are hit on a platform that libstd supports, we should likely
+// just use `repr_unpacked.rs` there instead (unless the fix is easy).
+macro_rules! static_assert {
+ ($condition:expr) => {
+ const _: () = assert!($condition);
+ };
+ (@usize_eq: $lhs:expr, $rhs:expr) => {
+ const _: [(); $lhs] = [(); $rhs];
+ };
+}
+
+// The bitpacking we use requires pointers be exactly 64 bits.
+static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8);
+
+// We also require pointers and usize be the same size.
+static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>());
+
+// `Custom` and `SimpleMessage` need to be thin pointers.
+static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8);
+static_assert!(@usize_eq: size_of::<Box<Custom>>(), 8);
+
+static_assert!((TAG_MASK + 1).is_power_of_two());
+// And they must have sufficient alignment.
+static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
+static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
+
+static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE_MESSAGE), TAG_SIMPLE_MESSAGE);
+static_assert!(@usize_eq: (TAG_MASK & TAG_CUSTOM), TAG_CUSTOM);
+static_assert!(@usize_eq: (TAG_MASK & TAG_OS), TAG_OS);
+static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE), TAG_SIMPLE);
+
+// This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we
+// offset a pointer by this value, and expect it to both be within the same
+// object, and to not wrap around the address space. See the comment in that
+// function for further details.
+//
+// Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this
+// check isn't needed for that one, although the assertion that we don't
+// actually wrap around in that wrapping_add does simplify the safety reasoning
+// elsewhere considerably.
+static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
+
+// These two store a payload which is allowed to be zero, so they must be
+// non-zero to preserve the `NonNull`'s range invariant.
+static_assert!(TAG_OS != 0);
+static_assert!(TAG_SIMPLE != 0);
+// We can't tag `SimpleMessage`s, the tag must be 0.
+static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0);
+
+// Check that the point of all of this still holds.
+//
+// We'd check against `io::Error`, but *technically* it's allowed to vary,
+// as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but
+// the `#[repr()]` would show up in rustdoc, which might be seen as a stable
+// commitment.
+static_assert!(@usize_eq: size_of::<Repr>(), 8);
+static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8);
+static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8);
+static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16);
diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/std/src/io/error/repr_unpacked.rs
new file mode 100644
index 0000000..3729c03
--- /dev/null
+++ b/library/std/src/io/error/repr_unpacked.rs
@@ -0,0 +1,50 @@
+//! This is a fairly simple unpacked error representation that's used on
+//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
+//! would have no benefit.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc::boxed::Box;
+
+type Inner = ErrorData<Box<Custom>>;
+
+pub(super) struct Repr(Inner);
+
+impl Repr {
+ pub(super) fn new_custom(b: Box<Custom>) -> Self {
+ Self(Inner::Custom(b))
+ }
+ #[inline]
+ pub(super) fn new_os(code: i32) -> Self {
+ Self(Inner::Os(code))
+ }
+ #[inline]
+ pub(super) fn new_simple(kind: ErrorKind) -> Self {
+ Self(Inner::Simple(kind))
+ }
+ #[inline]
+ pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+ Self(Inner::SimpleMessage(m))
+ }
+ #[inline]
+ pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+ self.0
+ }
+ #[inline]
+ pub(super) fn data(&self) -> ErrorData<&Custom> {
+ match &self.0 {
+ Inner::Os(c) => ErrorData::Os(*c),
+ Inner::Simple(k) => ErrorData::Simple(*k),
+ Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+ Inner::Custom(m) => ErrorData::Custom(&*m),
+ }
+ }
+ #[inline]
+ pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+ match &mut self.0 {
+ Inner::Os(c) => ErrorData::Os(*c),
+ Inner::Simple(k) => ErrorData::Simple(*k),
+ Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+ Inner::Custom(m) => ErrorData::Custom(&mut *m),
+ }
+ }
+}
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index 5098a46..c2c5155 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -1,4 +1,5 @@
-use super::{Custom, Error, ErrorKind, Repr};
+use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr};
+use crate::assert_matches::assert_matches;
use crate::error;
use crate::fmt;
use crate::mem::size_of;
@@ -16,9 +17,9 @@
let msg = error_string(code);
let kind = decode_error_kind(code);
let err = Error {
- repr: Repr::Custom(box Custom {
+ repr: Repr::new_custom(box Custom {
kind: ErrorKind::InvalidInput,
- error: box Error { repr: super::Repr::Os(code) },
+ error: box Error { repr: super::Repr::new_os(code) },
}),
};
let expected = format!(
@@ -60,10 +61,83 @@
#[test]
fn test_const() {
- const E: Error = Error::new_const(ErrorKind::NotFound, &"hello");
+ const E: Error = const_io_error!(ErrorKind::NotFound, "hello");
assert_eq!(E.kind(), ErrorKind::NotFound);
assert_eq!(E.to_string(), "hello");
assert!(format!("{:?}", E).contains("\"hello\""));
assert!(format!("{:?}", E).contains("NotFound"));
}
+
+#[test]
+fn test_os_packing() {
+ for code in -20i32..20i32 {
+ let e = Error::from_raw_os_error(code);
+ assert_eq!(e.raw_os_error(), Some(code));
+ assert_matches!(
+ e.repr.data(),
+ ErrorData::Os(c) if c == code,
+ );
+ }
+}
+
+#[test]
+fn test_errorkind_packing() {
+ assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound);
+ assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied);
+ assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized);
+ // Check that the innards look like like what we want.
+ assert_matches!(
+ Error::from(ErrorKind::OutOfMemory).repr.data(),
+ ErrorData::Simple(ErrorKind::OutOfMemory),
+ );
+}
+
+#[test]
+fn test_simple_message_packing() {
+ use super::{ErrorKind::*, SimpleMessage};
+ macro_rules! check_simple_msg {
+ ($err:expr, $kind:ident, $msg:literal) => {{
+ let e = &$err;
+ // Check that the public api is right.
+ assert_eq!(e.kind(), $kind);
+ assert!(format!("{:?}", e).contains($msg));
+ // and we got what we expected
+ assert_matches!(
+ e.repr.data(),
+ ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg })
+ );
+ }};
+ }
+
+ let not_static = const_io_error!(Uncategorized, "not a constant!");
+ check_simple_msg!(not_static, Uncategorized, "not a constant!");
+
+ const CONST: Error = const_io_error!(NotFound, "definitely a constant!");
+ check_simple_msg!(CONST, NotFound, "definitely a constant!");
+
+ static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!");
+ check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!");
+}
+
+#[derive(Debug, PartialEq)]
+struct Bojji(bool);
+impl error::Error for Bojji {}
+impl fmt::Display for Bojji {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ah! {:?}", self)
+ }
+}
+
+#[test]
+fn test_custom_error_packing() {
+ use super::Custom;
+ let test = Error::new(ErrorKind::Uncategorized, Bojji(true));
+ assert_matches!(
+ test.repr.data(),
+ ErrorData::Custom(Custom {
+ kind: ErrorKind::Uncategorized,
+ error,
+ }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
+ );
+}
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 23201f9..64d2457 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -5,7 +5,7 @@
use crate::cmp;
use crate::fmt;
use crate::io::{
- self, BufRead, Error, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
+ self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
};
use crate::mem;
@@ -279,7 +279,10 @@
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
- return Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"));
+ return Err(io::const_io_error!(
+ ErrorKind::UnexpectedEof,
+ "failed to fill whole buffer"
+ ));
}
let (a, b) = self.split_at(buf.len());
@@ -361,7 +364,7 @@
if self.write(data)? == data.len() {
Ok(())
} else {
- Err(Error::new_const(ErrorKind::WriteZero, &"failed to write whole buffer"))
+ Err(io::const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"))
}
}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index ecc9e91..71a59fb 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -261,34 +261,28 @@
use crate::sys;
use crate::sys_common::memchr;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::buffered::IntoInnerError;
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use self::buffered::WriterPanicked;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::buffered::{BufReader, BufWriter, LineWriter};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::copy::copy;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::cursor::Cursor;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::error::{Error, ErrorKind, Result};
#[unstable(feature = "internal_output_capture", issue = "none")]
#[doc(no_inline, hidden)]
pub use self::stdio::set_output_capture;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
+#[unstable(feature = "print_internals", issue = "none")]
+pub use self::stdio::{_eprint, _print};
#[unstable(feature = "stdio_locked", issue = "86845")]
pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
-#[unstable(feature = "print_internals", issue = "none")]
-pub use self::stdio::{_eprint, _print};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
+pub use self::{
+ buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
+ copy::copy,
+ cursor::Cursor,
+ error::{Error, ErrorKind, Result},
+ stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock},
+ util::{empty, repeat, sink, Empty, Repeat, Sink},
+};
#[unstable(feature = "read_buf", issue = "78485")]
pub use self::readbuf::ReadBuf;
+pub(crate) use error::const_io_error;
mod buffered;
pub(crate) mod copy;
@@ -344,7 +338,10 @@
let ret = f(g.buf);
if str::from_utf8(&g.buf[g.len..]).is_err() {
ret.and_then(|_| {
- Err(Error::new_const(ErrorKind::InvalidData, &"stream did not contain valid UTF-8"))
+ Err(error::const_io_error!(
+ ErrorKind::InvalidData,
+ "stream did not contain valid UTF-8"
+ ))
})
} else {
g.len = g.buf.len();
@@ -461,7 +458,7 @@
}
}
if !buf.is_empty() {
- Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+ Err(error::const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
} else {
Ok(())
}
@@ -1038,14 +1035,14 @@
///
/// # use std::io;
/// fn main() -> io::Result<()> {
-/// let stdin = io::read_to_string(&mut io::stdin())?;
+/// let stdin = io::read_to_string(io::stdin())?;
/// println!("Stdin was:");
/// println!("{}", stdin);
/// Ok(())
/// }
/// ```
#[unstable(feature = "io_read_to_string", issue = "80218")]
-pub fn read_to_string<R: Read>(reader: &mut R) -> Result<String> {
+pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
Ok(buf)
@@ -1519,9 +1516,9 @@
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => {
- return Err(Error::new_const(
+ return Err(error::const_io_error!(
ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => buf = &buf[n..],
@@ -1587,9 +1584,9 @@
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(0) => {
- return Err(Error::new_const(
+ return Err(error::const_io_error!(
ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => IoSlice::advance_slices(&mut bufs, n),
@@ -1664,7 +1661,7 @@
if output.error.is_err() {
output.error
} else {
- Err(Error::new_const(ErrorKind::Uncategorized, &"formatter error"))
+ Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
}
}
}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index c072f0c..3d6de20 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -7,7 +7,7 @@
use crate::cell::{Cell, RefCell};
use crate::fmt;
-use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, Split};
+use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
use crate::lazy::SyncOnceCell;
use crate::pin::Pin;
use crate::sync::atomic::{AtomicBool, Ordering};
@@ -465,29 +465,6 @@
pub fn lines(self) -> Lines<StdinLock<'static>> {
self.into_locked().lines()
}
-
- /// Consumes this handle and returns an iterator over input bytes,
- /// split at the specified byte value.
- ///
- /// For detailed semantics of this method, see the documentation on
- /// [`BufRead::split`].
- ///
- /// # Examples
- ///
- /// ```no_run
- /// #![feature(stdin_forwarders)]
- /// use std::io;
- ///
- /// let splits = io::stdin().split(b'-');
- /// for split in splits {
- /// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
- /// }
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- #[unstable(feature = "stdin_forwarders", issue = "87096")]
- pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
- self.into_locked().split(byte)
- }
}
#[stable(feature = "std_debug", since = "1.16.0")]
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index ea49bfe..eb62634 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -185,12 +185,12 @@
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new_const(io::ErrorKind::Other, &""))
+ Err(io::const_io_error!(io::ErrorKind::Other, ""))
}
}
impl BufRead for R {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
- Err(io::Error::new_const(io::ErrorKind::Other, &""))
+ Err(io::const_io_error!(io::ErrorKind::Other, ""))
}
fn consume(&mut self, _amt: usize) {}
}
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index a370485..35d230e 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2172,7 +2172,7 @@
/// i.next().unwrap_or_else(I::Item::default)
/// }
///
-/// assert_eq!(first_or_default(vec![1, 2, 3].into_iter()), 1);
+/// assert_eq!(first_or_default([1, 2, 3].into_iter()), 1);
/// assert_eq!(first_or_default(Vec::<i32>::new().into_iter()), 0);
/// ```
///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b002104..8c38db9 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -35,8 +35,8 @@
//! development you may want to press the `[-]` button near the top of the
//! page to collapse it into a more skimmable view.
//!
-//! While you are looking at that `[-]` button also notice the `[src]`
-//! button. Rust's API documentation comes with the source code and you are
+//! While you are looking at that `[-]` button also notice the `source`
+//! link. Rust's API documentation comes with the source code and you are
//! encouraged to read it. The standard library source is generally high
//! quality and a peek behind the curtains is often enlightening.
//!
@@ -195,15 +195,12 @@
test(no_crate_inject, attr(deny(warnings))),
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
-#![cfg_attr(
- not(bootstrap),
- doc(cfg_hide(
- not(test),
- not(any(test, bootstrap)),
- no_global_oom_handling,
- not(no_global_oom_handling)
- ))
-)]
+#![doc(cfg_hide(
+ not(test),
+ not(any(test, bootstrap)),
+ no_global_oom_handling,
+ not(no_global_oom_handling)
+))]
// Don't link to std. We are std.
#![no_std]
#![warn(deprecated_in_future)]
@@ -225,6 +222,7 @@
// std is implemented with unstable features, many of which are internal
// compiler details that will never be stable
// NB: the following list is sorted to minimize merge conflicts.
+#![feature(absolute_path)]
#![feature(alloc_error_handler)]
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
@@ -235,7 +233,7 @@
#![feature(array_error_internals)]
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
-#![feature(async_stream)]
+#![feature(async_iterator)]
#![feature(atomic_mut_ptr)]
#![feature(auto_traits)]
#![feature(bench_black_box)]
@@ -245,11 +243,11 @@
#![feature(c_variadic)]
#![feature(cfg_accessible)]
#![feature(cfg_eval)]
-#![feature(cfg_target_has_atomic)]
+#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))]
#![feature(cfg_target_thread_local)]
#![feature(char_error_internals)]
#![feature(char_internals)]
-#![cfg_attr(not(bootstrap), feature(concat_bytes))]
+#![feature(concat_bytes)]
#![feature(concat_idents)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
@@ -294,10 +292,8 @@
#![feature(intra_doc_pointers)]
#![feature(lang_items)]
#![feature(linkage)]
-#![feature(llvm_asm)]
#![feature(log_syntax)]
#![feature(map_try_insert)]
-#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_write_slice)]
@@ -313,8 +309,10 @@
#![feature(once_cell)]
#![feature(panic_info_message)]
#![feature(panic_internals)]
+#![feature(panic_can_unwind)]
#![feature(panic_unwind)]
#![feature(pin_static_ref)]
+#![feature(platform_intrinsics)]
#![feature(portable_simd)]
#![feature(prelude_import)]
#![feature(ptr_as_uninit)]
@@ -342,7 +340,6 @@
#![feature(unboxed_closures)]
#![feature(unwrap_infallible)]
#![feature(vec_into_raw_parts)]
-#![feature(vec_spare_capacity)]
// NB: the above list is sorted to minimize merge conflicts.
#![default_lib_allocator]
@@ -405,15 +402,10 @@
pub use alloc_crate::vec;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::any;
-#[stable(feature = "simd_arch", since = "1.27.0")]
-// The `no_inline`-attribute is required to make the documentation of all
-// targets available.
-// See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for
-// more information.
-#[doc(no_inline)] // Note (#82861): required for correct documentation
-pub use core::arch;
#[stable(feature = "core_array", since = "1.36.0")]
pub use core::array;
+#[unstable(feature = "async_iterator", issue = "79024")]
+pub use core::async_iter;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::cell;
#[stable(feature = "rust1", since = "1.0.0")]
@@ -468,10 +460,6 @@
pub use core::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::result;
-#[unstable(feature = "portable_simd", issue = "86656")]
-pub use core::simd;
-#[unstable(feature = "async_stream", issue = "79024")]
-pub use core::stream;
#[stable(feature = "i128", since = "1.26.0")]
#[allow(deprecated, deprecated_in_future)]
pub use core::u128;
@@ -516,6 +504,25 @@
#[unstable(feature = "once_cell", issue = "74465")]
pub mod lazy;
+// Pull in `std_float` crate into libstd. The contents of
+// `std_float` are in a different repository: rust-lang/portable-simd.
+#[path = "../../portable-simd/crates/std_float/src/lib.rs"]
+#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
+#[allow(rustdoc::bare_urls)]
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
+mod std_float;
+
+#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
+#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
+#[unstable(feature = "portable_simd", issue = "86656")]
+pub mod simd {
+ #[doc(inline)]
+ pub use crate::std_float::StdFloat;
+ #[doc(inline)]
+ pub use core::simd::*;
+}
+
#[stable(feature = "futures_api", since = "1.36.0")]
pub mod task {
//! Types and Traits for working with asynchronous tasks.
@@ -529,6 +536,32 @@
pub use alloc::task::*;
}
+#[doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")]
+#[stable(feature = "simd_arch", since = "1.27.0")]
+pub mod arch {
+ #[stable(feature = "simd_arch", since = "1.27.0")]
+ // The `no_inline`-attribute is required to make the documentation of all
+ // targets available.
+ // See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for
+ // more information.
+ #[doc(no_inline)] // Note (#82861): required for correct documentation
+ pub use core::arch::*;
+
+ #[stable(feature = "simd_aarch64", since = "1.60.0")]
+ pub use std_detect::is_aarch64_feature_detected;
+ #[stable(feature = "simd_x86", since = "1.27.0")]
+ pub use std_detect::is_x86_feature_detected;
+ #[unstable(feature = "stdsimd", issue = "48556")]
+ pub use std_detect::{
+ is_arm_feature_detected, is_mips64_feature_detected, is_mips_feature_detected,
+ is_powerpc64_feature_detected, is_powerpc_feature_detected, is_riscv_feature_detected,
+ };
+}
+
+// This was stabilized in the crate root so we have to keep it there.
+#[stable(feature = "simd_x86", since = "1.27.0")]
+pub use std_detect::is_x86_feature_detected;
+
// The runtime entry point and a few unstable public functions used by the
// compiler
#[macro_use]
@@ -547,18 +580,6 @@
#[allow(dead_code, unused_attributes)]
mod backtrace_rs;
-#[stable(feature = "simd_x86", since = "1.27.0")]
-pub use std_detect::is_x86_feature_detected;
-#[doc(hidden)]
-#[unstable(feature = "stdsimd", issue = "48556")]
-pub use std_detect::*;
-#[unstable(feature = "stdsimd", issue = "48556")]
-pub use std_detect::{
- is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
- is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
- is_riscv_feature_detected,
-};
-
// Re-export macros defined in libcore.
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)]
@@ -572,8 +593,8 @@
#[allow(deprecated)]
pub use core::{
assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
- env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm,
- log_syntax, module_path, option_env, stringify, trace_macros,
+ env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
+ module_path, option_env, stringify, trace_macros,
};
#[unstable(
@@ -581,7 +602,6 @@
issue = "87555",
reason = "`concat_bytes` is not stable enough for use and is subject to change"
)]
-#[cfg(not(bootstrap))]
pub use core::concat_bytes;
#[stable(feature = "core_primitive", since = "1.43.0")]
@@ -610,7 +630,3 @@
#[unstable(feature = "sealed", issue = "none")]
pub trait Sealed {}
}
-
-#[unstable(feature = "thread_local_const_init", issue = "91543")]
-#[allow(unused)]
-fn workaround_for_91543_as_racer_needs_this_feature_gate() {}
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 5dc75d3..23cbfae 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -57,6 +57,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
#[allow_internal_unstable(print_internals)]
macro_rules! print {
($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
@@ -90,6 +91,7 @@
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
() => ($crate::print!("\n"));
@@ -121,6 +123,7 @@
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
#[allow_internal_unstable(print_internals)]
macro_rules! eprint {
($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
@@ -149,6 +152,7 @@
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! eprintln {
() => ($crate::eprint!("\n"));
@@ -282,6 +286,7 @@
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
/// [`log`]: https://crates.io/crates/log
#[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")]
#[stable(feature = "dbg_macro", since = "1.32.0")]
macro_rules! dbg {
// NOTE: We cannot use `concat!` to make a static string as a format argument
diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs
index a0c77b6..f676e0a 100644
--- a/library/std/src/net/mod.rs
+++ b/library/std/src/net/mod.rs
@@ -17,7 +17,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
@@ -25,6 +25,8 @@
pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::parser::AddrParseError;
+#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
+pub use self::tcp::IntoIncoming;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::tcp::{Incoming, TcpListener, TcpStream};
#[stable(feature = "rust1", since = "1.0.0")]
@@ -88,6 +90,6 @@
}
}
Err(last_err.unwrap_or_else(|| {
- Error::new_const(ErrorKind::InvalidInput, &"could not resolve to any addresses")
+ io::const_io_error!(ErrorKind::InvalidInput, "could not resolve to any addresses")
}))
}
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 1ba54d8..cc4e4fd 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -405,7 +405,7 @@
/// use std::net::TcpStream;
///
/// let stream = TcpStream::connect("127.0.0.1:8000")
- /// .expect("couldn't bind to address");
+ /// .expect("Couldn't connect to the server...");
/// let mut buf = [0; 10];
/// let len = stream.peek(&mut buf).expect("peek failed");
/// ```
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 6354752..11a696e 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -2,7 +2,7 @@
mod tests;
use crate::fmt;
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use crate::sys_common::net as net_imp;
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -175,7 +175,9 @@
pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
match addr.to_socket_addrs()?.next() {
Some(addr) => self.0.send_to(buf, &addr),
- None => Err(Error::new_const(ErrorKind::InvalidInput, &"no addresses to send data to")),
+ None => {
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "no addresses to send data to"))
+ }
}
}
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 52d7d46..71c660e 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -8,6 +8,8 @@
use crate::fs;
use crate::marker::PhantomData;
use crate::mem::forget;
+#[cfg(not(target_os = "wasi"))]
+use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed file descriptor.
@@ -67,6 +69,37 @@
}
}
+impl OwnedFd {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file handle
+ /// as the existing `OwnedFd` instance.
+ #[cfg(not(target_os = "wasi"))]
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ // We want to atomically duplicate this file descriptor and set the
+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+ // is a POSIX flag that was added to Linux in 2.6.24.
+ #[cfg(not(target_os = "espidf"))]
+ let cmd = libc::F_DUPFD_CLOEXEC;
+
+ // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
+ // will never be supported, as this is a bare metal framework with
+ // no capabilities for multi-process execution. While F_DUPFD is also
+ // not supported yet, it might be (currently it returns ENOSYS).
+ #[cfg(target_os = "espidf")]
+ let cmd = libc::F_DUPFD;
+
+ let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
+ Ok(unsafe { Self::from_raw_fd(fd) })
+ }
+
+ #[cfg(target_os = "wasi")]
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ Err(crate::io::const_io_error!(
+ crate::io::ErrorKind::Unsupported,
+ "operation not supported on WASI yet",
+ ))
+ }
+}
+
#[unstable(feature = "io_safety", issue = "87074")]
impl AsRawFd for BorrowedFd<'_> {
#[inline]
@@ -168,6 +201,22 @@
}
#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsFd> AsFd for &T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsFd> AsFd for &mut T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for BorrowedFd<'_> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index cd92dca..d78049b 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -239,6 +239,7 @@
target_arch = "riscv32"
))]
mod arch {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
}
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index f0b38d2..b6d5199 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -45,94 +45,13 @@
}
}
-type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
-#[doc(cfg(all()))]
-#[cfg(any(
- all(
- target_os = "linux",
- any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "hexagon",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "s390x",
- target_arch = "riscv64",
- target_arch = "riscv32"
- )
- ),
- all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
- all(target_os = "l4re", target_arch = "x86_64"),
- all(
- target_os = "freebsd",
- any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "riscv64"
- )
- ),
- all(
- target_os = "netbsd",
- any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
- ),
- all(target_os = "openbsd", target_arch = "aarch64"),
- all(
- target_os = "vxworks",
- any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "powerpc64",
- target_arch = "powerpc"
- )
- ),
- all(target_os = "fuchsia", target_arch = "aarch64")
-))]}
-type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
-#[doc(cfg(all()))]
-#[cfg(not(any(
- all(
- target_os = "linux",
- any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "hexagon",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "s390x",
- target_arch = "riscv64",
- target_arch = "riscv32"
- )
- ),
- all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
- all(target_os = "l4re", target_arch = "x86_64"),
- all(
- target_os = "freebsd",
- any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "riscv64"
- )
- ),
- all(
- target_os = "netbsd",
- any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
- ),
- all(target_os = "openbsd", target_arch = "aarch64"),
- all(
- target_os = "vxworks",
- any(
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "powerpc64",
- target_arch = "powerpc"
- )
- ),
- all(target_os = "fuchsia", target_arch = "aarch64")
-)))]}
+type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char;
+// Make this type alias appear cfg-dependent so that Clippy does not suggest
+// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed
+// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
+// is fixed.
+#[cfg(all())]
+#[doc(cfg(all()))] }
type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
@@ -180,3 +99,58 @@
/// platforms where this is not the case.
#[unstable(feature = "c_size_t", issue = "88345")]
pub type c_ssize_t = isize;
+
+mod c_char_definition {
+ cfg_if::cfg_if! {
+ // These are the targets on which c_char is unsigned.
+ if #[cfg(any(
+ all(
+ target_os = "linux",
+ any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "hexagon",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x",
+ target_arch = "riscv64",
+ target_arch = "riscv32"
+ )
+ ),
+ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(
+ target_os = "freebsd",
+ any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "riscv64"
+ )
+ ),
+ all(
+ target_os = "netbsd",
+ any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
+ ),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(
+ target_os = "vxworks",
+ any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc64",
+ target_arch = "powerpc"
+ )
+ ),
+ all(target_os = "fuchsia", target_arch = "aarch64")
+ ))] {
+ pub type c_char = u8;
+ pub type NonZero_c_char = core::num::NonZeroU8;
+ } else {
+ // On every other target, c_char is signed.
+ pub type c_char = i8;
+ pub type NonZero_c_char = core::num::NonZeroI8;
+ }
+ }
+}
diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs
index 54c9a93..650f712 100644
--- a/library/std/src/os/unix/ffi/os_str.rs
+++ b/library/std/src/os/unix/ffi/os_str.rs
@@ -28,9 +28,11 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
+ #[inline]
fn from_vec(vec: Vec<u8>) -> OsString {
FromInner::from_inner(Buf { inner: vec })
}
+ #[inline]
fn into_vec(self) -> Vec<u8> {
self.into_inner().inner
}
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 0284a42..75d65e6 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -114,7 +114,7 @@
}
}
if !buf.is_empty() {
- Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
} else {
Ok(())
}
@@ -196,9 +196,9 @@
while !buf.is_empty() {
match self.write_at(buf, offset) {
Ok(0) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => {
@@ -966,7 +966,7 @@
///
/// fn main() -> std::io::Result<()> {
/// let f = std::fs::File::open("/file")?;
-/// fs::fchown(f, Some(0), Some(0))?;
+/// fs::fchown(&f, Some(0), Some(0))?;
/// Ok(())
/// }
/// ```
diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs
index 6317e31..a4d2ba7 100644
--- a/library/std/src/os/unix/io/raw.rs
+++ b/library/std/src/os/unix/io/raw.rs
@@ -2,4 +2,5 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index f450e41..034fa30 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -2,7 +2,7 @@
use crate::os::unix::ffi::OsStrExt;
use crate::path::Path;
use crate::sys::cvt;
-use crate::{ascii, fmt, io, iter, mem};
+use crate::{ascii, fmt, io, mem, ptr};
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
#[cfg(not(unix))]
@@ -22,30 +22,33 @@
path - base
}
-pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
- let mut addr: libc::sockaddr_un = mem::zeroed();
+pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ // SAFETY: All zeros is a valid representation for `sockaddr_un`.
+ let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
let bytes = path.as_os_str().as_bytes();
if bytes.contains(&0) {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"paths must not contain interior null bytes",
+ "paths must not contain interior null bytes",
));
}
if bytes.len() >= addr.sun_path.len() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"path must be shorter than SUN_LEN",
+ "path must be shorter than SUN_LEN",
));
}
- for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
- *dst = *src as libc::c_char;
- }
- // null byte for pathname addresses is already there because we zeroed the
- // struct
+ // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
+ // both point to valid memory.
+ // NOTE: We zeroed the memory above, so the path is already null
+ // terminated.
+ unsafe {
+ ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
+ };
let mut len = sun_path_offset(&addr) + bytes.len();
match bytes.get(0) {
@@ -118,15 +121,52 @@
// linux returns zero bytes of address
len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
} else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"file descriptor did not correspond to a Unix socket",
+ "file descriptor did not correspond to a Unix socket",
));
}
Ok(SocketAddr { addr, len })
}
+ /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the path is longer than `SUN_LEN` or if it contains
+ /// NULL bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(unix_socket_creation)]
+ /// use std::os::unix::net::SocketAddr;
+ /// use std::path::Path;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let address = SocketAddr::from_path("/path/to/socket")?;
+ /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// Creating a `SocketAddr` with a NULL byte results in an error.
+ ///
+ /// ```
+ /// #![feature(unix_socket_creation)]
+ /// use std::os::unix::net::SocketAddr;
+ ///
+ /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+ /// ```
+ #[unstable(feature = "unix_socket_creation", issue = "93423")]
+ pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+ where
+ P: AsRef<Path>,
+ {
+ sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
+ }
+
/// Returns `true` if the address is unnamed.
///
/// # Examples
@@ -283,9 +323,9 @@
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
if namespace.len() + 1 > addr.sun_path.len() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"namespace must be shorter than SUN_LEN",
+ "namespace must be shorter than SUN_LEN",
));
}
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 5c62679..160c8f1 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -87,7 +87,7 @@
}
}
if !buf.is_empty() {
- Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
} else {
Ok(())
}
@@ -153,9 +153,9 @@
while !buf.is_empty() {
match self.write_at(buf, offset) {
Ok(0) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => {
@@ -250,6 +250,21 @@
}
fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
+ let advice = match advice {
+ a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL,
+ a if a == wasi::ADVICE_SEQUENTIAL.raw() => wasi::ADVICE_SEQUENTIAL,
+ a if a == wasi::ADVICE_RANDOM.raw() => wasi::ADVICE_RANDOM,
+ a if a == wasi::ADVICE_WILLNEED.raw() => wasi::ADVICE_WILLNEED,
+ a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED,
+ a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE,
+ _ => {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "invalid parameter 'advice'",
+ ));
+ }
+ };
+
self.as_inner().as_inner().advise(offset, len, advice)
}
@@ -539,5 +554,5 @@
fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str()
- .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+ .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
}
diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs
index e6bcf87..73c097d 100644
--- a/library/std/src/os/wasi/net/mod.rs
+++ b/library/std/src/os/wasi/net/mod.rs
@@ -1,3 +1,23 @@
//! WASI-specific networking functionality
#![unstable(feature = "wasi_ext", issue = "71213")]
+
+use crate::io;
+use crate::net;
+use crate::sys_common::AsInner;
+
+/// WASI-specific extensions to [`std::net::TcpListener`].
+///
+/// [`std::net::TcpListener`]: crate::net::TcpListener
+pub trait TcpListenerExt {
+ /// Accept a socket.
+ ///
+ /// This corresponds to the `sock_accept` syscall.
+ fn sock_accept(&self, flags: u16) -> io::Result<u32>;
+}
+
+impl TcpListenerExt for net::TcpListener {
+ fn sock_accept(&self, flags: u16) -> io::Result<u32> {
+ self.as_inner().as_inner().as_inner().sock_accept(flags)
+ }
+}
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 1527f5b..8df6c54 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -6,9 +6,11 @@
use crate::convert::TryFrom;
use crate::fmt;
use crate::fs;
+use crate::io;
use crate::marker::PhantomData;
use crate::mem::forget;
use crate::sys::c;
+use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed handle.
@@ -144,6 +146,36 @@
}
}
+impl OwnedHandle {
+ /// Creates a new `OwnedHandle` instance that shares the same underlying file handle
+ /// as the existing `OwnedHandle` instance.
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
+ }
+
+ pub(crate) fn duplicate(
+ &self,
+ access: c::DWORD,
+ inherit: bool,
+ options: c::DWORD,
+ ) -> io::Result<Self> {
+ let mut ret = 0 as c::HANDLE;
+ cvt(unsafe {
+ let cur_proc = c::GetCurrentProcess();
+ c::DuplicateHandle(
+ cur_proc,
+ self.as_raw_handle(),
+ cur_proc,
+ &mut ret,
+ access,
+ inherit as c::BOOL,
+ options,
+ )
+ })?;
+ unsafe { Ok(Self::from_raw_handle(ret)) }
+ }
+}
+
impl TryFrom<HandleOrInvalid> for OwnedHandle {
type Error = ();
@@ -284,6 +316,22 @@
fn as_handle(&self) -> BorrowedHandle<'_>;
}
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsHandle> AsHandle for &T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsHandle> AsHandle for &mut T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
impl AsHandle for BorrowedHandle<'_> {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 23db66d..2f13eb7 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -4,9 +4,13 @@
use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use crate::fmt;
+use crate::io;
use crate::marker::PhantomData;
+use crate::mem;
use crate::mem::forget;
+use crate::sys;
use crate::sys::c;
+use crate::sys::cvt;
/// A borrowed socket.
///
@@ -69,6 +73,77 @@
}
}
+impl OwnedSocket {
+ /// Creates a new `OwnedSocket` instance that shares the same underlying socket
+ /// as the existing `OwnedSocket` instance.
+ pub fn try_clone(&self) -> io::Result<Self> {
+ let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+ let result = unsafe {
+ c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
+ };
+ sys::net::cvt(result)?;
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
+ )
+ };
+
+ if socket != c::INVALID_SOCKET {
+ unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
+ } else {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+ return Err(io::Error::from_raw_os_error(error));
+ }
+
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED,
+ )
+ };
+
+ if socket == c::INVALID_SOCKET {
+ return Err(last_error());
+ }
+
+ unsafe {
+ let socket = OwnedSocket::from_raw_socket(socket);
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
+ }
+ }
+
+ #[cfg(not(target_vendor = "uwp"))]
+ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+ cvt(unsafe {
+ c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
+ })
+ .map(drop)
+ }
+
+ #[cfg(target_vendor = "uwp")]
+ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP"))
+ }
+}
+
+/// Returns the last error from the Windows socket interface.
+fn last_error() -> io::Error {
+ io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
+}
+
impl AsRawSocket for BorrowedSocket<'_> {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
@@ -135,6 +210,22 @@
fn as_socket(&self) -> BorrowedSocket<'_>;
}
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsSocket> AsSocket for &T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsSocket> AsSocket for &mut T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
impl AsSocket for BorrowedSocket<'_> {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index c0605b2..ac16f47 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -5,6 +5,7 @@
use crate::any::Any;
use crate::collections;
use crate::panicking;
+use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{Mutex, RwLock};
use crate::thread::Result;
@@ -36,6 +37,9 @@
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use crate::panicking::{set_hook, take_hook};
+#[unstable(feature = "panic_update_hook", issue = "92649")]
+pub use crate::panicking::update_hook;
+
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use core::panic::{Location, PanicInfo};
@@ -199,5 +203,118 @@
crate::panicking::panic_count::set_always_abort();
}
+/// The configuration for whether and how the default panic hook will capture
+/// and display the backtrace.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[unstable(feature = "panic_backtrace_config", issue = "93346")]
+#[non_exhaustive]
+pub enum BacktraceStyle {
+ /// Prints a terser backtrace which ideally only contains relevant
+ /// information.
+ Short,
+ /// Prints a backtrace with all possible information.
+ Full,
+ /// Disable collecting and displaying backtraces.
+ Off,
+}
+
+impl BacktraceStyle {
+ pub(crate) fn full() -> Option<Self> {
+ if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None }
+ }
+
+ fn as_usize(self) -> usize {
+ match self {
+ BacktraceStyle::Short => 1,
+ BacktraceStyle::Full => 2,
+ BacktraceStyle::Off => 3,
+ }
+ }
+
+ fn from_usize(s: usize) -> Option<Self> {
+ Some(match s {
+ 0 => return None,
+ 1 => BacktraceStyle::Short,
+ 2 => BacktraceStyle::Full,
+ 3 => BacktraceStyle::Off,
+ _ => unreachable!(),
+ })
+ }
+}
+
+// Tracks whether we should/can capture a backtrace, and how we should display
+// that backtrace.
+//
+// Internally stores equivalent of an Option<BacktraceStyle>.
+static SHOULD_CAPTURE: AtomicUsize = AtomicUsize::new(0);
+
+/// Configure whether the default panic hook will capture and display a
+/// backtrace.
+///
+/// The default value for this setting may be set by the `RUST_BACKTRACE`
+/// environment variable; see the details in [`get_backtrace_style`].
+#[unstable(feature = "panic_backtrace_config", issue = "93346")]
+pub fn set_backtrace_style(style: BacktraceStyle) {
+ if !cfg!(feature = "backtrace") {
+ // If the `backtrace` feature of this crate isn't enabled, skip setting.
+ return;
+ }
+ SHOULD_CAPTURE.store(style.as_usize(), Ordering::Release);
+}
+
+/// Checks whether the standard library's panic hook will capture and print a
+/// backtrace.
+///
+/// This function will, if a backtrace style has not been set via
+/// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to
+/// determine a default value for the backtrace formatting:
+///
+/// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE`
+/// environment variable if `set_backtrace_style` has not been called to
+/// override the default value. After a call to `set_backtrace_style` or
+/// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect.
+///
+/// `RUST_BACKTRACE` is read according to these rules:
+///
+/// * `0` for `BacktraceStyle::Off`
+/// * `full` for `BacktraceStyle::Full`
+/// * `1` for `BacktraceStyle::Short`
+/// * Other values are currently `BacktraceStyle::Short`, but this may change in
+/// the future
+///
+/// Returns `None` if backtraces aren't currently supported.
+#[unstable(feature = "panic_backtrace_config", issue = "93346")]
+pub fn get_backtrace_style() -> Option<BacktraceStyle> {
+ if !cfg!(feature = "backtrace") {
+ // If the `backtrace` feature of this crate isn't enabled quickly return
+ // `Unsupported` so this can be constant propagated all over the place
+ // to optimize away callers.
+ return None;
+ }
+ if let Some(style) = BacktraceStyle::from_usize(SHOULD_CAPTURE.load(Ordering::Acquire)) {
+ return Some(style);
+ }
+
+ // Setting environment variables for Fuchsia components isn't a standard
+ // or easily supported workflow. For now, display backtraces by default.
+ let format = if cfg!(target_os = "fuchsia") {
+ BacktraceStyle::Full
+ } else {
+ crate::env::var_os("RUST_BACKTRACE")
+ .map(|x| {
+ if &x == "0" {
+ BacktraceStyle::Off
+ } else if &x == "full" {
+ BacktraceStyle::Full
+ } else {
+ BacktraceStyle::Short
+ }
+ })
+ .unwrap_or(BacktraceStyle::Off)
+ };
+ set_backtrace_style(format);
+ Some(format)
+}
+
#[cfg(test)]
mod tests;
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 87854fe..2b9ae32 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -9,6 +9,7 @@
#![deny(unsafe_op_in_unsafe_fn)]
+use crate::panic::BacktraceStyle;
use core::panic::{BoxMeUp, Location, PanicInfo};
use crate::any::Any;
@@ -18,7 +19,7 @@
use crate::process;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::stdio::panic_output;
-use crate::sys_common::backtrace::{self, RustBacktrace};
+use crate::sys_common::backtrace;
use crate::sys_common::rwlock::StaticRWLock;
use crate::sys_common::thread_info;
use crate::thread;
@@ -76,6 +77,12 @@
Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
}
+impl Hook {
+ fn custom(f: impl Fn(&PanicInfo<'_>) + 'static + Sync + Send) -> Self {
+ Self::Custom(Box::into_raw(Box::new(f)))
+ }
+}
+
static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
static mut HOOK: Hook = Hook::Default;
@@ -118,6 +125,11 @@
panic!("cannot modify the panic hook from a panicking thread");
}
+ // SAFETY:
+ //
+ // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+ // - The argument of `Box::from_raw` is always a valid pointer that was created using
+ // `Box::into_raw`.
unsafe {
let guard = HOOK_LOCK.write();
let old_hook = HOOK;
@@ -167,6 +179,11 @@
panic!("cannot modify the panic hook from a panicking thread");
}
+ // SAFETY:
+ //
+ // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+ // - The argument of `Box::from_raw` is always a valid pointer that was created using
+ // `Box::into_raw`.
unsafe {
let guard = HOOK_LOCK.write();
let hook = HOOK;
@@ -180,13 +197,76 @@
}
}
+/// Atomic combination of [`take_hook`] and [`set_hook`]. Use this to replace the panic handler with
+/// a new panic handler that does something and then executes the old handler.
+///
+/// [`take_hook`]: ./fn.take_hook.html
+/// [`set_hook`]: ./fn.set_hook.html
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+///
+/// # Examples
+///
+/// The following will print the custom message, and then the normal output of panic.
+///
+/// ```should_panic
+/// #![feature(panic_update_hook)]
+/// use std::panic;
+///
+/// // Equivalent to
+/// // let prev = panic::take_hook();
+/// // panic::set_hook(move |info| {
+/// // println!("...");
+/// // prev(info);
+/// // );
+/// panic::update_hook(move |prev, info| {
+/// println!("Print custom message and execute panic handler as usual");
+/// prev(info);
+/// });
+///
+/// panic!("Custom and then normal");
+/// ```
+#[unstable(feature = "panic_update_hook", issue = "92649")]
+pub fn update_hook<F>(hook_fn: F)
+where
+ F: Fn(&(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), &PanicInfo<'_>)
+ + Sync
+ + Send
+ + 'static,
+{
+ if thread::panicking() {
+ panic!("cannot modify the panic hook from a panicking thread");
+ }
+
+ // SAFETY:
+ //
+ // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+ // - The argument of `Box::from_raw` is always a valid pointer that was created using
+ // `Box::into_raw`.
+ unsafe {
+ let guard = HOOK_LOCK.write();
+ let old_hook = HOOK;
+ HOOK = Hook::Default;
+
+ let prev = match old_hook {
+ Hook::Default => Box::new(default_hook),
+ Hook::Custom(ptr) => Box::from_raw(ptr),
+ };
+
+ HOOK = Hook::custom(move |info| hook_fn(&prev, info));
+ drop(guard);
+ }
+}
+
fn default_hook(info: &PanicInfo<'_>) {
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
- let backtrace_env = if panic_count::get_count() >= 2 {
- RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
+ let backtrace = if panic_count::get_count() >= 2 {
+ BacktraceStyle::full()
} else {
- backtrace::rust_backtrace_env()
+ crate::panic::get_backtrace_style()
};
// The current implementation always returns `Some`.
@@ -207,10 +287,14 @@
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
- match backtrace_env {
- RustBacktrace::Print(format) => drop(backtrace::print(err, format)),
- RustBacktrace::Disabled => {}
- RustBacktrace::RuntimeDisabled => {
+ match backtrace {
+ Some(BacktraceStyle::Short) => {
+ drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Short))
+ }
+ Some(BacktraceStyle::Full) => {
+ drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Full))
+ }
+ Some(BacktraceStyle::Off) => {
if FIRST_PANIC.swap(false, Ordering::SeqCst) {
let _ = writeln!(
err,
@@ -218,6 +302,8 @@
);
}
}
+ // If backtraces aren't supported, do nothing.
+ None => {}
}
};
@@ -497,9 +583,14 @@
let msg = info.message().unwrap(); // The current implementation always returns Some
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
if let Some(msg) = msg.as_str() {
- rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+ rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
} else {
- rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+ rust_panic_with_hook(
+ &mut PanicPayload::new(msg),
+ info.message(),
+ loc,
+ info.can_unwind(),
+ );
}
})
}
@@ -523,7 +614,7 @@
let loc = Location::caller();
return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
- rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+ rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
});
struct PanicPayload<A> {
@@ -568,6 +659,7 @@
payload: &mut dyn BoxMeUp,
message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>,
+ can_unwind: bool,
) -> ! {
let (must_abort, panics) = panic_count::increase();
@@ -584,14 +676,14 @@
} else {
// Unfortunately, this does not print a backtrace, because creating
// a `Backtrace` will allocate, which we must to avoid here.
- let panicinfo = PanicInfo::internal_constructor(message, location);
+ let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
}
- intrinsics::abort()
+ crate::sys::abort_internal();
}
unsafe {
- let mut info = PanicInfo::internal_constructor(message, location);
+ let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
let _guard = HOOK_LOCK.read();
match HOOK {
// Some platforms (like wasm) know that printing to stderr won't ever actually
@@ -612,13 +704,13 @@
};
}
- if panics > 1 {
+ if panics > 1 || !can_unwind {
// If a thread panics while it's already unwinding then we
// have limited options. Currently our preference is to
// just abort. In the future we may consider resuming
// unwinding or otherwise exiting the thread cleanly.
rtprintpanic!("thread panicked while panicking. aborting.\n");
- intrinsics::abort()
+ crate::sys::abort_internal();
}
rust_panic(payload)
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index bfbcb00..e544608 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -72,6 +72,7 @@
use crate::borrow::{Borrow, Cow};
use crate::cmp;
+use crate::collections::TryReserveError;
use crate::error::Error;
use crate::fmt;
use crate::fs;
@@ -84,7 +85,7 @@
use crate::sync::Arc;
use crate::ffi::{OsStr, OsString};
-
+use crate::sys;
use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};
////////////////////////////////////////////////////////////////////////////////
@@ -267,6 +268,12 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
+/// The primary separator of path components for the current platform.
+///
+/// For example, `/` on Unix and `\` on Windows.
+#[unstable(feature = "main_separator_str", issue = "94071")]
+pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
+
////////////////////////////////////////////////////////////////////////////////
// Misc helpers
////////////////////////////////////////////////////////////////////////////////
@@ -1512,6 +1519,15 @@
self.inner.reserve(additional)
}
+ /// Invokes [`try_reserve`] on the underlying instance of [`OsString`].
+ ///
+ /// [`try_reserve`]: OsString::try_reserve
+ #[unstable(feature = "try_reserve_2", issue = "91789")]
+ #[inline]
+ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.inner.try_reserve(additional)
+ }
+
/// Invokes [`reserve_exact`] on the underlying instance of [`OsString`].
///
/// [`reserve_exact`]: OsString::reserve_exact
@@ -1521,6 +1537,15 @@
self.inner.reserve_exact(additional)
}
+ /// Invokes [`try_reserve_exact`] on the underlying instance of [`OsString`].
+ ///
+ /// [`try_reserve_exact`]: OsString::try_reserve_exact
+ #[unstable(feature = "try_reserve_2", issue = "91789")]
+ #[inline]
+ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.inner.try_reserve_exact(additional)
+ }
+
/// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`].
///
/// [`shrink_to_fit`]: OsString::shrink_to_fit
@@ -1581,7 +1606,7 @@
#[stable(feature = "path_buf_from_box", since = "1.18.0")]
impl From<Box<Path>> for PathBuf {
- /// Converts a `Box<Path>` into a `PathBuf`
+ /// Converts a <code>[Box]<[Path]></code> into a [`PathBuf`].
///
/// This conversion does not allocate or copy memory.
#[inline]
@@ -1592,7 +1617,7 @@
#[stable(feature = "box_from_path_buf", since = "1.20.0")]
impl From<PathBuf> for Box<Path> {
- /// Converts a `PathBuf` into a `Box<Path>`
+ /// Converts a [`PathBuf`] into a <code>[Box]<[Path]></code>.
///
/// This conversion currently should not allocate memory,
/// but this behavior is not guaranteed on all platforms or in all future versions.
@@ -1612,7 +1637,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
- /// Converts a borrowed `OsStr` to a `PathBuf`.
+ /// Converts a borrowed [`OsStr`] to a [`PathBuf`].
///
/// Allocates a [`PathBuf`] and copies the data into it.
#[inline]
@@ -1766,7 +1791,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<PathBuf> for Arc<Path> {
- /// Converts a [`PathBuf`] into an [`Arc`] by moving the [`PathBuf`] data into a new [`Arc`] buffer.
+ /// Converts a [`PathBuf`] into an <code>[Arc]<[Path]></code> by moving the [`PathBuf`] data
+ /// into a new [`Arc`] buffer.
#[inline]
fn from(s: PathBuf) -> Arc<Path> {
let arc: Arc<OsStr> = Arc::from(s.into_os_string());
@@ -1786,7 +1812,8 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<PathBuf> for Rc<Path> {
- /// Converts a [`PathBuf`] into an [`Rc`] by moving the [`PathBuf`] data into a new `Rc` buffer.
+ /// Converts a [`PathBuf`] into an <code>[Rc]<[Path]></code> by moving the [`PathBuf`] data into
+ /// a new [`Rc`] buffer.
#[inline]
fn from(s: PathBuf) -> Rc<Path> {
let rc: Rc<OsStr> = Rc::from(s.into_os_string());
@@ -1796,7 +1823,7 @@
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<&Path> for Rc<Path> {
- /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new `Rc` buffer.
+ /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer.
#[inline]
fn from(s: &Path) -> Rc<Path> {
let rc: Rc<OsStr> = Rc::from(s.as_os_str());
@@ -2709,7 +2736,7 @@
/// This function will traverse symbolic links to query information about the
/// destination file. In case of broken symbolic links this will return `Ok(false)`.
///
- /// As opposed to the `exists()` method, this one doesn't silently ignore errors
+ /// As opposed to the [`exists()`] method, this one doesn't silently ignore errors
/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
/// denied on some of the parent directories.)
///
@@ -2722,6 +2749,8 @@
/// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
/// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
/// ```
+ ///
+ /// [`exists()`]: Self::exists
// FIXME: stabilization should modify documentation of `exists()` to recommend this method
// instead.
#[unstable(feature = "path_try_exists", issue = "83186")]
@@ -2806,7 +2835,7 @@
/// use std::os::unix::fs::symlink;
///
/// let link_path = Path::new("link");
- /// symlink("/origin_does_not_exists/", link_path).unwrap();
+ /// symlink("/origin_does_not_exist/", link_path).unwrap();
/// assert_eq!(link_path.is_symlink(), true);
/// assert_eq!(link_path.exists(), false);
/// ```
@@ -3149,3 +3178,79 @@
"prefix not found"
}
}
+
+/// Makes the path absolute without accessing the filesystem.
+///
+/// If the path is relative, the current directory is used as the base directory.
+/// All intermediate components will be resolved according to platforms-specific
+/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not
+/// resolve symlinks and may succeed even if the path does not exist.
+///
+/// If the `path` is empty or getting the
+/// [current directory][crate::env::current_dir] fails then an error will be
+/// returned.
+///
+/// # Examples
+///
+/// ## Posix paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(unix)]
+/// fn main() -> std::io::Result<()> {
+/// use std::path::{self, Path};
+///
+/// // Relative to absolute
+/// let absolute = path::absolute("foo/./bar")?;
+/// assert!(absolute.ends_with("foo/bar"));
+///
+/// // Absolute to absolute
+/// let absolute = path::absolute("/foo//test/.././bar.rs")?;
+/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs"));
+/// Ok(())
+/// }
+/// # #[cfg(not(unix))]
+/// # fn main() {}
+/// ```
+///
+/// The path is resolved using [POSIX semantics][posix-semantics] except that
+/// it stops short of resolving symlinks. This means it will keep `..`
+/// components and trailing slashes.
+///
+/// ## Windows paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(windows)]
+/// fn main() -> std::io::Result<()> {
+/// use std::path::{self, Path};
+///
+/// // Relative to absolute
+/// let absolute = path::absolute("foo/./bar")?;
+/// assert!(absolute.ends_with(r"foo\bar"));
+///
+/// // Absolute to absolute
+/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?;
+///
+/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs"));
+/// Ok(())
+/// }
+/// # #[cfg(not(windows))]
+/// # fn main() {}
+/// ```
+///
+/// For verbatim paths this will simply return the path as given. For other
+/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
+/// This may change in the future.
+///
+/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+#[unstable(feature = "absolute_path", issue = "92750")]
+pub fn absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+ let path = path.as_ref();
+ if path.as_os_str().is_empty() {
+ Err(io::const_io_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",))
+ } else {
+ sys::path::absolute(path)
+ }
+}
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 0ab5956..8e51433 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1700,6 +1700,64 @@
ord!(Equal, "foo/bar", "foo/bar//");
}
+#[test]
+#[cfg(unix)]
+fn test_unix_absolute() {
+ use crate::path::absolute;
+
+ assert!(absolute("").is_err());
+
+ let relative = "a/b";
+ let mut expected = crate::env::current_dir().unwrap();
+ expected.push(relative);
+ assert_eq!(absolute(relative).unwrap(), expected);
+
+ // Test how components are collected.
+ assert_eq!(absolute("/a/b/c").unwrap(), Path::new("/a/b/c"));
+ assert_eq!(absolute("/a//b/c").unwrap(), Path::new("/a/b/c"));
+ assert_eq!(absolute("//a/b/c").unwrap(), Path::new("//a/b/c"));
+ assert_eq!(absolute("///a/b/c").unwrap(), Path::new("/a/b/c"));
+ assert_eq!(absolute("/a/b/c/").unwrap(), Path::new("/a/b/c/"));
+ assert_eq!(absolute("/a/./b/../c/.././..").unwrap(), Path::new("/a/b/../c/../.."));
+}
+
+#[test]
+#[cfg(windows)]
+fn test_windows_absolute() {
+ use crate::path::absolute;
+ // An empty path is an error.
+ assert!(absolute("").is_err());
+
+ let relative = r"a\b";
+ let mut expected = crate::env::current_dir().unwrap();
+ expected.push(relative);
+ assert_eq!(absolute(relative).unwrap(), expected);
+
+ macro_rules! unchanged(
+ ($path:expr) => {
+ assert_eq!(absolute($path).unwrap(), Path::new($path));
+ }
+ );
+
+ unchanged!(r"C:\path\to\file");
+ unchanged!(r"C:\path\to\file\");
+ unchanged!(r"\\server\share\to\file");
+ unchanged!(r"\\server.\share.\to\file");
+ unchanged!(r"\\.\PIPE\name");
+ unchanged!(r"\\.\C:\path\to\COM1");
+ unchanged!(r"\\?\C:\path\to\file");
+ unchanged!(r"\\?\UNC\server\share\to\file");
+ unchanged!(r"\\?\PIPE\name");
+ // Verbatim paths are always unchanged, no matter what.
+ unchanged!(r"\\?\path.\to/file..");
+
+ assert_eq!(absolute(r"C:\path..\to.\file.").unwrap(), Path::new(r"C:\path..\to\file"));
+ assert_eq!(absolute(r"C:\path\to\COM1").unwrap(), Path::new(r"\\.\COM1"));
+ assert_eq!(absolute(r"C:\path\to\COM1.txt").unwrap(), Path::new(r"\\.\COM1"));
+ assert_eq!(absolute(r"C:\path\to\COM1 .txt").unwrap(), Path::new(r"\\.\COM1"));
+ assert_eq!(absolute(r"C:\path\to\cOnOuT$").unwrap(), Path::new(r"\\.\cOnOuT$"));
+}
+
#[bench]
fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
let prefix = "my/home";
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index b52bcdf..0226c4d 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -40,9 +40,8 @@
#[doc(no_inline)]
pub use core::prelude::v1::{
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
- format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
- option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq,
- PartialOrd,
+ format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
+ stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
};
#[unstable(
@@ -50,7 +49,6 @@
issue = "87555",
reason = "`concat_bytes` is not stable enough for use and is subject to change"
)]
-#[cfg(not(bootstrap))]
#[doc(no_inline)]
pub use core::prelude::v1::concat_bytes;
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 8fcd8cd..ebb1d89 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -275,20 +275,69 @@
mod prim_never {}
#[doc(primitive = "char")]
+#[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type.
///
/// The `char` type represents a single character. More specifically, since
/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
-/// scalar value]', which is similar to, but not the same as, a '[Unicode code
-/// point]'.
-///
-/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
-/// [Unicode code point]: https://www.unicode.org/glossary/#code_point
+/// scalar value]'.
///
/// This documentation describes a number of methods and trait implementations on the
/// `char` type. For technical reasons, there is additional, separate
/// documentation in [the `std::char` module](char/index.html) as well.
///
+/// # Validity
+///
+/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]'
+/// other than a [surrogate code point]. This has a fixed numerical definition:
+/// code points are in the range 0 to 0x10FFFF, inclusive.
+/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF.
+///
+/// No `char` may be constructed, whether as a literal or at runtime, that is not a
+/// Unicode scalar value:
+///
+/// ```compile_fail
+/// // Each of these is a compiler error
+/// ['\u{D800}', '\u{DFFF}', '\u{110000}'];
+/// ```
+///
+/// ```should_panic
+/// // Panics; from_u32 returns None.
+/// char::from_u32(0xDE01).unwrap();
+/// ```
+///
+/// ```no_run
+/// // Undefined behaviour
+/// unsafe { char::from_u32_unchecked(0x110000) };
+/// ```
+///
+/// USVs are also the exact set of values that may be encoded in UTF-8. Because
+/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store
+/// any `char` in a `str` or read any character from a `str` as a `char`.
+///
+/// The gap in valid `char` values is understood by the compiler, so in the
+/// below example the two ranges are understood to cover the whole range of
+/// possible `char` values and there is no error for a [non-exhaustive match].
+///
+/// ```
+/// let c: char = 'a';
+/// match c {
+/// '\0' ..= '\u{D7FF}' => false,
+/// '\u{E000}' ..= '\u{10FFFF}' => true,
+/// };
+/// ```
+///
+/// All USVs are valid `char` values, but not all of them represent a real
+/// character. Many USVs are not currently assigned to a character, but may be
+/// in the future ("reserved"); some will never be a character
+/// ("noncharacters"); and some may be given different meanings by different
+/// users ("private use").
+///
+/// [Unicode code point]: https://www.unicode.org/glossary/#code_point
+/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
+/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive
+/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point
+///
/// # Representation
///
/// `char` is always four bytes in size. This is a different representation than
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index e012594..e3fff15 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1277,7 +1277,7 @@
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<ChildStdin> for Stdio {
- /// Converts a `ChildStdin` into a `Stdio`
+ /// Converts a [`ChildStdin`] into a [`Stdio`].
///
/// # Examples
///
@@ -1306,7 +1306,7 @@
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<ChildStdout> for Stdio {
- /// Converts a `ChildStdout` into a `Stdio`
+ /// Converts a [`ChildStdout`] into a [`Stdio`].
///
/// # Examples
///
@@ -1335,7 +1335,7 @@
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<ChildStderr> for Stdio {
- /// Converts a `ChildStderr` into a `Stdio`
+ /// Converts a [`ChildStderr`] into a [`Stdio`].
///
/// # Examples
///
@@ -1366,7 +1366,7 @@
#[stable(feature = "stdio_from", since = "1.20.0")]
impl From<fs::File> for Stdio {
- /// Converts a `File` into a `Stdio`
+ /// Converts a [`File`](fs::File) into a [`Stdio`].
///
/// # Examples
///
@@ -1676,6 +1676,29 @@
pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
}
+impl ExitCode {
+ // This should not be stabilized when stabilizing ExitCode, we don't know that i32 will serve
+ // all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we
+ // likely want to isolate users anything that could restrict the platform specific
+ // representation of an ExitCode
+ //
+ // More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426
+ /// Convert an ExitCode into an i32
+ #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+ #[inline]
+ pub fn to_i32(self) -> i32 {
+ self.0.as_i32()
+ }
+}
+
+#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+impl From<u8> for ExitCode {
+ /// Construct an exit code from an arbitrary u8 value.
+ fn from(code: u8) -> Self {
+ ExitCode(imp::ExitCode::from(code))
+ }
+}
+
impl Child {
/// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
/// error is returned.
@@ -2016,20 +2039,20 @@
pub trait Termination {
/// Is called to get the representation of the value as status code.
/// This status code is returned to the operating system.
- fn report(self) -> i32;
+ fn report(self) -> ExitCode;
}
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl Termination for () {
#[inline]
- fn report(self) -> i32 {
+ fn report(self) -> ExitCode {
ExitCode::SUCCESS.report()
}
}
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl<E: fmt::Debug> Termination for Result<(), E> {
- fn report(self) -> i32 {
+ fn report(self) -> ExitCode {
match self {
Ok(()) => ().report(),
Err(err) => Err::<!, _>(err).report(),
@@ -2039,14 +2062,14 @@
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl Termination for ! {
- fn report(self) -> i32 {
+ fn report(self) -> ExitCode {
self
}
}
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl<E: fmt::Debug> Termination for Result<!, E> {
- fn report(self) -> i32 {
+ fn report(self) -> ExitCode {
let Err(err) = self;
eprintln!("Error: {:?}", err);
ExitCode::FAILURE.report()
@@ -2055,7 +2078,7 @@
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl<E: fmt::Debug> Termination for Result<Infallible, E> {
- fn report(self) -> i32 {
+ fn report(self) -> ExitCode {
let Err(err) = self;
Err::<!, _>(err).report()
}
@@ -2064,7 +2087,7 @@
#[unstable(feature = "termination_trait_lib", issue = "43301")]
impl Termination for ExitCode {
#[inline]
- fn report(self) -> i32 {
- self.0.as_i32()
+ fn report(self) -> ExitCode {
+ self
}
}
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 08e58257..663537a 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -142,7 +142,7 @@
argv: *const *const u8,
) -> isize {
let Ok(v) = lang_start_internal(
- &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
+ &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
argc,
argv,
);
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 57f1dcc..3ea0a6c 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -188,12 +188,9 @@
/// [`lock`]: Mutex::lock
/// [`try_lock`]: Mutex::try_lock
#[must_use = "if unused the Mutex will immediately unlock"]
-#[cfg_attr(
- not(bootstrap),
- must_not_suspend = "holding a MutexGuard across suspend \
+#[must_not_suspend = "holding a MutexGuard across suspend \
points can cause deadlocks, delays, \
- and cause Futures to not implement `Send`"
-)]
+ and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: &'a Mutex<T>,
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 2f4395c..2e72a9e 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -95,12 +95,9 @@
/// [`read`]: RwLock::read
/// [`try_read`]: RwLock::try_read
#[must_use = "if unused the RwLock will immediately unlock"]
-#[cfg_attr(
- not(bootstrap),
- must_not_suspend = "holding a RwLockReadGuard across suspend \
+#[must_not_suspend = "holding a RwLockReadGuard across suspend \
points can cause deadlocks, delays, \
- and cause Futures to not implement `Send`"
-)]
+ and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
@@ -121,12 +118,9 @@
/// [`write`]: RwLock::write
/// [`try_write`]: RwLock::try_write
#[must_use = "if unused the RwLock will immediately unlock"]
-#[cfg_attr(
- not(bootstrap),
- must_not_suspend = "holding a RwLockWriteGuard across suspend \
+#[must_not_suspend = "holding a RwLockWriteGuard across suspend \
points can cause deadlocks, delays, \
- and cause Future's to not implement `Send`"
-)]
+ and cause Future's to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 9665d1f..e06eaf6 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -14,8 +14,8 @@
target_arch = "asmjs",
target_arch = "wasm32",
target_arch = "hexagon",
- target_arch = "riscv32",
- target_arch = "xtensa"
+ all(target_arch = "riscv32", not(target_os = "espidf")),
+ all(target_arch = "xtensa", not(target_os = "espidf")),
)))]
pub const MIN_ALIGN: usize = 8;
#[cfg(all(any(
@@ -28,6 +28,12 @@
target_arch = "wasm64",
)))]
pub const MIN_ALIGN: usize = 16;
+// The allocator on the esp-idf platform guarentees 4 byte alignment.
+#[cfg(all(any(
+ all(target_arch = "riscv32", target_os = "espidf"),
+ all(target_arch = "xtensa", target_os = "espidf"),
+)))]
+pub const MIN_ALIGN: usize = 4;
pub unsafe fn realloc_fallback(
alloc: &System,
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 974c44e..fa9a7fb 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -226,7 +226,7 @@
(false, _, true) => Ok(O_WRONLY | O_APPEND),
(true, _, true) => Ok(O_RDWR | O_APPEND),
(false, false, false) => {
- Err(io::Error::new_const(ErrorKind::InvalidInput, &"invalid access mode"))
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid access mode"))
}
}
}
@@ -236,17 +236,17 @@
(true, false) => {}
(false, false) => {
if self.truncate || self.create || self.create_new {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid creation mode",
+ "invalid creation mode",
));
}
}
(_, true) => {
if self.truncate && !self.create_new {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid creation mode",
+ "invalid creation mode",
));
}
}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 185b68c..b798c97 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -58,9 +58,9 @@
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(
+ crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on HermitCore yet",
+ "operation not supported on HermitCore yet",
)
}
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 1a6b3bc..f65fd8e 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -14,9 +14,9 @@
/// if not, starts it.
pub fn init() -> io::Result<()> {
if abi::network_init() < 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initialize network interface",
+ "Unable to initialize network interface",
));
}
@@ -50,9 +50,9 @@
match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::Error::new_const(
+ _ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initiate a connection on a socket",
+ "Unable to initiate a connection on a socket",
)),
}
}
@@ -64,9 +64,9 @@
Some(duration.as_millis() as u64),
) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::Error::new_const(
+ _ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initiate a connection on a socket",
+ "Unable to initiate a connection on a socket",
)),
}
}
@@ -74,7 +74,7 @@
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
.map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
})
}
@@ -83,12 +83,12 @@
*self.0.as_inner(),
duration.map(|d| d.as_millis() as u64),
)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
@@ -96,7 +96,7 @@
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
@@ -104,7 +104,7 @@
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
abi::tcpstream::peek(*self.0.as_inner(), buf)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peek failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
}
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
@@ -116,7 +116,7 @@
for i in ioslice.iter_mut() {
let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to read on socket")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
})?;
if ret != 0 {
@@ -141,7 +141,7 @@
for i in ioslice.iter() {
size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to write on socket")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
})?;
}
@@ -155,13 +155,13 @@
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"))?;
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
- return Err(io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"));
+ return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
}
};
@@ -173,9 +173,8 @@
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
- abi::tcpstream::shutdown(*self.0.as_inner(), how as i32).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"unable to shutdown socket")
- })
+ abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
@@ -192,22 +191,22 @@
pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
}
pub fn nodelay(&self) -> io::Result<bool> {
abi::tcpstream::nodelay(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"nodelay failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
}
pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
abi::tcpstream::set_tll(*self.0.as_inner(), tll)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to set TTL"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
}
pub fn ttl(&self) -> io::Result<u32> {
abi::tcpstream::get_tll(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to get TTL"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
@@ -216,7 +215,7 @@
pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"unable to set blocking mode")
+ io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
})
}
}
@@ -243,12 +242,12 @@
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"))?;
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
- return Err(io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"));
+ return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
}
};
diff --git a/library/std/src/sys/hermit/stdio.rs b/library/std/src/sys/hermit/stdio.rs
index 33b8390..514de1d 100644
--- a/library/std/src/sys/hermit/stdio.rs
+++ b/library/std/src/sys/hermit/stdio.rs
@@ -40,7 +40,7 @@
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
@@ -52,7 +52,7 @@
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
@@ -81,7 +81,7 @@
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
@@ -93,7 +93,7 @@
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs
index 81b21fb..e53a1fe 100644
--- a/library/std/src/sys/hermit/thread.rs
+++ b/library/std/src/sys/hermit/thread.rs
@@ -39,7 +39,7 @@
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
drop(Box::from_raw(p));
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Unable to create thread!"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Unable to create thread!"))
} else {
Ok(Thread { tid: tid })
};
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index c02de17..27173de 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -115,14 +115,6 @@
Instant { t: time }
}
- pub const fn zero() -> Instant {
- Instant { t: Timespec::zero() }
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
}
diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs
index dac4b8a..2992a6a 100644
--- a/library/std/src/sys/itron/condvar.rs
+++ b/library/std/src/sys/itron/condvar.rs
@@ -15,10 +15,12 @@
pub type MovableCondvar = Condvar;
impl Condvar {
+ #[inline]
pub const fn new() -> Condvar {
Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
}
+ #[inline]
pub unsafe fn init(&mut self) {}
pub unsafe fn notify_one(&self) {
@@ -190,7 +192,7 @@
let insert_after = {
let mut cursor = head.last;
loop {
- if waiter.priority <= cursor.as_ref().priority {
+ if waiter.priority >= cursor.as_ref().priority {
// `cursor` and all previous waiters have the same or higher
// priority than `current_task_priority`. Insert the new
// waiter right after `cursor`.
@@ -206,7 +208,7 @@
if let Some(mut insert_after) = insert_after {
// Insert `waiter` after `insert_after`
- let insert_before = insert_after.as_ref().prev;
+ let insert_before = insert_after.as_ref().next;
waiter.prev = Some(insert_after);
insert_after.as_mut().next = Some(waiter_ptr);
@@ -214,6 +216,8 @@
waiter.next = insert_before;
if let Some(mut insert_before) = insert_before {
insert_before.as_mut().prev = Some(waiter_ptr);
+ } else {
+ head.last = waiter_ptr;
}
} else {
// Insert `waiter` to the front
@@ -240,11 +244,11 @@
match (waiter.prev, waiter.next) {
(Some(mut prev), Some(mut next)) => {
prev.as_mut().next = Some(next);
- next.as_mut().next = Some(prev);
+ next.as_mut().prev = Some(prev);
}
(None, Some(mut next)) => {
head.first = next;
- next.as_mut().next = None;
+ next.as_mut().prev = None;
}
(Some(mut prev), None) => {
prev.as_mut().next = None;
@@ -271,6 +275,7 @@
unsafe { waiter.as_ref().task != 0 }
}
+ #[inline]
pub fn pop_front(&mut self) -> Option<abi::ID> {
unsafe {
let head = self.head.as_mut()?;
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index ebcc9ab..5b718a4 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -77,17 +77,14 @@
const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
// there's no single value for `JOINING`
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::<usize>();
+// 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs.
+pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::<usize>();
impl Thread {
/// # Safety
///
/// See `thread::Builder::spawn_unchecked` for safety requirements.
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
- // Inherit the current task's priority
- let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?;
- let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?;
-
let inner = Box::new(ThreadInner {
start: UnsafeCell::new(ManuallyDrop::new(p)),
lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
@@ -175,7 +172,8 @@
exinf: inner_ptr as abi::EXINF,
// The entry point
task: Some(trampoline),
- itskpri: priority,
+ // Inherit the calling task's base priority
+ itskpri: abi::TPRI_SELF,
stksz: stack,
// Let the kernel allocate the stack,
stk: crate::ptr::null_mut(),
diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs
index 6a992ad..25f13ee 100644
--- a/library/std/src/sys/itron/time.rs
+++ b/library/std/src/sys/itron/time.rs
@@ -14,15 +14,6 @@
}
}
- pub const fn zero() -> Instant {
- Instant(0)
- }
-
- pub fn actually_monotonic() -> bool {
- // There are ways to change the system time
- false
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0).map(|ticks| {
// `SYSTIM` is measured in microseconds
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index a2a763c..158c92e 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -58,7 +58,7 @@
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(ErrorKind::Unsupported, &"operation not supported on SGX yet")
+ crate::io::const_io_error!(ErrorKind::Unsupported, "operation not supported on SGX yet")
}
/// This function is used to implement various functions that doesn't exist,
@@ -69,9 +69,9 @@
pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
- Err(crate::io::Error::new_const(
+ Err(crate::io::const_io_error!(
ErrorKind::Uncategorized,
- &"operation can't be trusted to have any effect on SGX",
+ "operation can't be trusted to have any effect on SGX",
))
} else {
Ok(v)
diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs
index 89c5af6..d14990c 100644
--- a/library/std/src/sys/sgx/net.rs
+++ b/library/std/src/sys/sgx/net.rs
@@ -97,9 +97,9 @@
pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
if dur == Duration::default() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
Self::connect(Ok(addr)) // FIXME: ignoring timeout
@@ -108,9 +108,9 @@
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match dur {
Some(dur) if dur == Duration::default() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
_ => sgx_ineffective(()),
@@ -120,9 +120,9 @@
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match dur {
Some(dur) if dur == Duration::default() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
_ => sgx_ineffective(()),
diff --git a/library/std/src/sys/sgx/path.rs b/library/std/src/sys/sgx/path.rs
index 840a7ae..c805c15 100644
--- a/library/std/src/sys/sgx/path.rs
+++ b/library/std/src/sys/sgx/path.rs
@@ -1,5 +1,7 @@
use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +19,7 @@
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
diff --git a/library/std/src/sys/sgx/time.rs b/library/std/src/sys/sgx/time.rs
index e2f6e6d..db4cf28 100644
--- a/library/std/src/sys/sgx/time.rs
+++ b/library/std/src/sys/sgx/time.rs
@@ -25,14 +25,6 @@
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant(self.0.checked_sub(*other)?))
}
-
- pub fn actually_monotonic() -> bool {
- false
- }
-
- pub const fn zero() -> Instant {
- Instant(Duration::from_secs(0))
- }
}
impl SystemTime {
diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs
index 7c21d0d..eb06a6d 100644
--- a/library/std/src/sys/solid/abi/sockets.rs
+++ b/library/std/src/sys/solid/abi/sockets.rs
@@ -175,6 +175,9 @@
#[link_name = "SOLID_NET_Close"]
pub fn close(s: c_int) -> c_int;
+ #[link_name = "SOLID_NET_Dup"]
+ pub fn dup(s: c_int) -> c_int;
+
#[link_name = "SOLID_NET_GetPeerName"]
pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs
index 8a0eeff..a2cbee4 100644
--- a/library/std/src/sys/solid/fs.rs
+++ b/library/std/src/sys/solid/fs.rs
@@ -289,7 +289,26 @@
}
fn cstr(path: &Path) -> io::Result<CString> {
- Ok(CString::new(path.as_os_str().as_bytes())?)
+ let path = path.as_os_str().as_bytes();
+
+ if !path.starts_with(br"\") {
+ // Relative paths aren't supported
+ return Err(crate::io::const_io_error!(
+ crate::io::ErrorKind::Unsupported,
+ "relative path is not supported on this platform",
+ ));
+ }
+
+ // Apply the thread-safety wrapper
+ const SAFE_PREFIX: &[u8] = br"\TS";
+ let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat();
+
+ CString::from_vec_with_nul(wrapped_path).map_err(|_| {
+ crate::io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "path provided contains a nul byte",
+ )
+ })
}
impl File {
@@ -461,7 +480,7 @@
pub fn unlink(p: &Path) -> io::Result<()> {
if stat(p)?.file_type().is_dir() {
- Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory"))
+ Err(io::const_io_error!(io::ErrorKind::IsADirectory, "is a directory"))
} else {
error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
.map_err(|e| e.as_io_error())?;
@@ -491,7 +510,7 @@
.map_err(|e| e.as_io_error())?;
Ok(())
} else {
- Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory"))
+ Err(io::const_io_error!(io::ErrorKind::NotADirectory, "not a directory"))
}
}
@@ -511,7 +530,7 @@
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
// This target doesn't support symlinks
stat(p)?;
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link"))
+ Err(io::const_io_error!(io::ErrorKind::InvalidInput, "not a symbolic link"))
}
pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 211b8d7..2082c94 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -57,9 +57,9 @@
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(
+ crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
+ "operation not supported on this platform",
)
}
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index 63ba634..a43407b 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -107,7 +107,7 @@
}
fn duplicate(&self) -> io::Result<FileDesc> {
- super::unsupported()
+ cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
}
}
@@ -243,9 +243,9 @@
}
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
@@ -271,7 +271,7 @@
};
match n {
- 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
+ 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
let can_write = writefds.num_fds != 0;
if !can_write {
@@ -364,9 +364,9 @@
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs
index 82542d8..22239e1 100644
--- a/library/std/src/sys/solid/os.rs
+++ b/library/std/src/sys/solid/os.rs
@@ -173,11 +173,7 @@
/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this
/// function just returns a generic error.
fn cvt_env(t: c_int) -> io::Result<c_int> {
- if t == -1 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure"))
- } else {
- Ok(t)
- }
+ if t == -1 { Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) }
}
pub fn temp_dir() -> PathBuf {
diff --git a/library/std/src/sys/solid/path.rs b/library/std/src/sys/solid/path.rs
index 4a14332..7045c9b 100644
--- a/library/std/src/sys/solid/path.rs
+++ b/library/std/src/sys/solid/path.rs
@@ -1,5 +1,7 @@
use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +19,7 @@
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs
index c67a736..ab988be 100644
--- a/library/std/src/sys/solid/time.rs
+++ b/library/std/src/sys/solid/time.rs
@@ -21,7 +21,7 @@
tm_min: rtc.tm_min,
tm_hour: rtc.tm_hour,
tm_mday: rtc.tm_mday,
- tm_mon: rtc.tm_mon,
+ tm_mon: rtc.tm_mon - 1,
tm_year: rtc.tm_year,
tm_wday: rtc.tm_wday,
tm_yday: 0,
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 2362bff..3de7c68 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -259,22 +259,9 @@
}
}
+ #[inline]
pub fn duplicate(&self) -> io::Result<FileDesc> {
- // We want to atomically duplicate this file descriptor and set the
- // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
- // is a POSIX flag that was added to Linux in 2.6.24.
- #[cfg(not(target_os = "espidf"))]
- let cmd = libc::F_DUPFD_CLOEXEC;
-
- // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
- // will never be supported, as this is a bare metal framework with
- // no capabilities for multi-process execution. While F_DUPFD is also
- // not supported yet, it might be (currently it returns ENOSYS).
- #[cfg(target_os = "espidf")]
- let cmd = libc::F_DUPFD;
-
- let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
- Ok(unsafe { FileDesc::from_raw_fd(fd) })
+ Ok(Self(self.0.try_clone()?))
}
}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index f8deda9..8bd0b9b 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -34,7 +34,20 @@
use libc::dirfd;
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
use libc::fstatat64;
+#[cfg(any(
+ target_os = "android",
+ target_os = "solaris",
+ target_os = "fuchsia",
+ target_os = "redox",
+ target_os = "illumos"
+))]
+use libc::readdir as readdir64;
+#[cfg(target_os = "linux")]
+use libc::readdir64;
+#[cfg(any(target_os = "emscripten", target_os = "l4re"))]
+use libc::readdir64_r;
#[cfg(not(any(
+ target_os = "android",
target_os = "linux",
target_os = "emscripten",
target_os = "solaris",
@@ -60,9 +73,7 @@
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
};
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
-use libc::{
- dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64,
-};
+use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
pub use crate::sys_common::fs::try_exists;
@@ -202,6 +213,8 @@
pub struct ReadDir {
inner: Arc<InnerReadDir>,
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -218,11 +231,12 @@
pub struct DirEntry {
entry: dirent64,
dir: Arc<InnerReadDir>,
- // We need to store an owned copy of the entry name
- // on Solaris and Fuchsia because a) it uses a zero-length
- // array to store the name, b) its lifetime between readdir
- // calls is not guaranteed.
+ // We need to store an owned copy of the entry name on platforms that use
+ // readdir() (not readdir_r()), because a) struct dirent may use a flexible
+ // array to store the name, b) it lives only until the next readdir() call.
#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -373,17 +387,17 @@
tv_nsec: ext.stx_btime.tv_nsec as _,
}))
} else {
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"creation time is not available for the filesystem",
+ "creation time is not available for the filesystem",
))
};
}
}
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"creation time is not available on this platform \
+ "creation time is not available on this platform \
currently",
))
}
@@ -449,6 +463,8 @@
type Item = io::Result<DirEntry>;
#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
@@ -457,12 +473,13 @@
fn next(&mut self) -> Option<io::Result<DirEntry>> {
unsafe {
loop {
- // Although readdir_r(3) would be a correct function to use here because
- // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
- // is safe to use in threaded applications and it is generally preferred
- // over the readdir_r(3C) function.
+ // As of POSIX.1-2017, readdir() is not required to be thread safe; only
+ // readdir_r() is. However, readdir_r() cannot correctly handle platforms
+ // with unlimited or variable NAME_MAX. Many modern platforms guarantee
+ // thread safety for readdir() as long an individual DIR* is not accessed
+ // concurrently, which is sufficient for Rust.
super::os::set_errno(0);
- let entry_ptr = libc::readdir(self.inner.dirp.0);
+ let entry_ptr = readdir64(self.inner.dirp.0);
if entry_ptr.is_null() {
// null can mean either the end is reached or an error occurred.
// So we had to clear errno beforehand to check for an error now.
@@ -472,10 +489,18 @@
};
}
+ // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
+ // whole thing (#93384). Instead, copy everything except the name.
+ let entry_bytes = entry_ptr as *const u8;
+ let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8;
+ let name_offset = entry_name.offset_from(entry_bytes) as usize;
+ let mut entry: dirent64 = mem::zeroed();
+ ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset);
+
let ret = DirEntry {
- entry: *entry_ptr,
+ entry,
// d_name is guaranteed to be null-terminated.
- name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(),
+ name: CStr::from_ptr(entry_name as *const _).to_owned(),
dir: Arc::clone(&self.inner),
};
if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
@@ -486,6 +511,8 @@
}
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
@@ -531,17 +558,17 @@
impl DirEntry {
pub fn path(&self) -> PathBuf {
- self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
+ self.dir.root.join(self.file_name_os_str())
}
pub fn file_name(&self) -> OsString {
- OsStr::from_bytes(self.name_bytes()).to_os_string()
+ self.file_name_os_str().to_os_string()
}
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
pub fn metadata(&self) -> io::Result<FileAttr> {
let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
- let name = self.entry.d_name.as_ptr();
+ let name = self.name_cstr().as_ptr();
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
@@ -571,7 +598,7 @@
target_os = "vxworks"
))]
pub fn file_type(&self) -> io::Result<FileType> {
- lstat(&self.path()).map(|m| m.file_type())
+ self.metadata().map(|m| m.file_type())
}
#[cfg(not(any(
@@ -589,7 +616,7 @@
libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }),
libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }),
libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }),
- _ => lstat(&self.path()).map(|m| m.file_type()),
+ _ => self.metadata().map(|m| m.file_type()),
}
}
@@ -639,29 +666,21 @@
)
}
}
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "emscripten",
- target_os = "l4re",
- target_os = "haiku",
- target_os = "vxworks",
- target_os = "espidf"
- ))]
+ #[cfg(not(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "freebsd",
+ target_os = "dragonfly"
+ )))]
fn name_bytes(&self) -> &[u8] {
- unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() }
- }
- #[cfg(any(
- target_os = "solaris",
- target_os = "illumos",
- target_os = "fuchsia",
- target_os = "redox"
- ))]
- fn name_bytes(&self) -> &[u8] {
- self.name.as_bytes()
+ self.name_cstr().to_bytes()
}
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -670,7 +689,14 @@
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
}
- #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+ ))]
fn name_cstr(&self) -> &CStr {
&self.name
}
@@ -1076,6 +1102,8 @@
Ok(ReadDir {
inner: Arc::new(inner),
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -1448,8 +1476,8 @@
pub use remove_dir_impl::remove_dir_all;
-// Fallback for REDOX
-#[cfg(target_os = "redox")]
+// Fallback for REDOX and ESP-IDF
+#[cfg(any(target_os = "redox", target_os = "espidf"))]
mod remove_dir_impl {
pub use crate::sys_common::fs::remove_dir_all;
}
@@ -1573,7 +1601,11 @@
}
// Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))]
+#[cfg(not(any(
+ all(target_os = "macos", target_arch = "x86_64"),
+ target_os = "redox",
+ target_os = "espidf"
+)))]
mod remove_dir_impl {
use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
use crate::ffi::CStr;
@@ -1611,6 +1643,8 @@
ReadDir {
inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
@@ -1627,7 +1661,6 @@
target_os = "illumos",
target_os = "haiku",
target_os = "vxworks",
- target_os = "fuchsia"
))]
fn is_dir(_ent: &DirEntry) -> Option<bool> {
None
@@ -1638,7 +1671,6 @@
target_os = "illumos",
target_os = "haiku",
target_os = "vxworks",
- target_os = "fuchsia"
)))]
fn is_dir(ent: &DirEntry) -> Option<bool> {
match ent.entry.d_type {
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index ba63b41..d13e1ec 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -1,8 +1,8 @@
macro_rules! unimpl {
() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"No networking available on L4Re.",
+ "No networking available on L4Re.",
));
};
}
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 2ba6c8d..605cc49 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -159,7 +159,7 @@
libc::ENOSPC => StorageFull,
libc::ENOSYS => Unsupported,
libc::EMLINK => TooManyLinks,
- libc::ENAMETOOLONG => FilenameTooLong,
+ libc::ENAMETOOLONG => InvalidFilename,
libc::ENETDOWN => NetworkDown,
libc::ENETUNREACH => NetworkUnreachable,
libc::ENOTCONN => NotConnected,
@@ -322,9 +322,6 @@
}
pub fn unsupported_err() -> io::Error {
- io::Error::new_const(
- io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
- )
+ io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",)
}
}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index a82a017..61c15ec 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -154,9 +154,9 @@
let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
@@ -165,7 +165,7 @@
loop {
let elapsed = start.elapsed();
if elapsed >= timeout {
- return Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"));
+ return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
let timeout = timeout - elapsed;
@@ -192,9 +192,9 @@
// for POLLHUP rather than read readiness
if pollfd.revents & libc::POLLHUP != 0 {
let e = self.take_error()?.unwrap_or_else(|| {
- io::Error::new_const(
+ io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no error set after POLLHUP",
+ "no error set after POLLHUP",
)
});
return Err(e);
@@ -338,9 +338,9 @@
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 8a028d9..b268ef5 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -75,7 +75,7 @@
}
/// Sets the platform-specific value of errno
-#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
+#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
#[allow(dead_code)] // but not all target cfgs actually end up using it
pub fn set_errno(e: i32) {
unsafe { *errno_location() = e as c_int }
@@ -294,9 +294,9 @@
0,
))?;
if path_len <= 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"KERN_PROC_PATHNAME sysctl returned zero-length string",
+ "KERN_PROC_PATHNAME sysctl returned zero-length string",
));
}
let mut path: Vec<u8> = Vec::with_capacity(path_len);
@@ -317,9 +317,9 @@
if curproc_exe.is_file() {
return crate::fs::read_link(curproc_exe);
}
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"/proc/curproc/exe doesn't point to regular file.",
+ "/proc/curproc/exe doesn't point to regular file.",
))
}
sysctl().or_else(|_| procfs())
@@ -336,9 +336,9 @@
cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?;
argv.set_len(argv_len as usize);
if argv[0].is_null() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no current exe available",
+ "no current exe available",
));
}
let argv0 = CStr::from_ptr(argv[0]).to_bytes();
@@ -353,9 +353,9 @@
#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
pub fn current_exe() -> io::Result<PathBuf> {
match crate::fs::read_link("/proc/self/exe") {
- Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new_const(
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no /proc/self/exe available. Is /proc mounted?",
+ "no /proc/self/exe available. Is /proc mounted?",
)),
other => other,
}
@@ -417,7 +417,7 @@
);
if result != 0 {
use crate::io::ErrorKind;
- Err(io::Error::new_const(ErrorKind::Uncategorized, &"Error getting executable path"))
+ Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path"))
} else {
let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes();
Ok(PathBuf::from(OsStr::from_bytes(name)))
@@ -433,7 +433,7 @@
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
- Err(io::Error::new_const(ErrorKind::Unsupported, &"Not yet implemented!"))
+ Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
}
#[cfg(target_os = "vxworks")]
diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs
index 717add9..6d6f4c8 100644
--- a/library/std/src/sys/unix/path.rs
+++ b/library/std/src/sys/unix/path.rs
@@ -1,5 +1,7 @@
+use crate::env;
use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
@@ -18,3 +20,43 @@
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';
+
+/// Make a POSIX path absolute without changing its semantics.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+ // This is mostly a wrapper around collecting `Path::components`, with
+ // exceptions made where this conflicts with the POSIX specification.
+ // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+ let mut components = path.components();
+ let path_os = path.as_os_str().bytes();
+
+ let mut normalized = if path.is_absolute() {
+ // "If a pathname begins with two successive <slash> characters, the
+ // first component following the leading <slash> characters may be
+ // interpreted in an implementation-defined manner, although more than
+ // two leading <slash> characters shall be treated as a single <slash>
+ // character."
+ if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+ components.next();
+ PathBuf::from("//")
+ } else {
+ PathBuf::new()
+ }
+ } else {
+ env::current_dir()?
+ };
+ normalized.extend(components);
+
+ // "Interfaces using pathname resolution may specify additional constraints
+ // when a pathname that does not name an existing directory contains at
+ // least one non- <slash> character and contains one or more trailing
+ // <slash> characters".
+ // A trailing <slash> is also meaningful if "a symbolic link is
+ // encountered during pathname resolution".
+ if path_os.ends_with(b"/") {
+ normalized.push("");
+ }
+
+ Ok(normalized)
+}
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 7ac2f9d..97985dd 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -476,6 +476,12 @@
}
}
+impl From<u8> for ExitCode {
+ fn from(code: u8) -> Self {
+ Self(code)
+ }
+}
+
pub struct CommandArgs<'a> {
iter: crate::slice::Iter<'a, CString>,
}
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index ce77c21..09bfd96 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -23,9 +23,9 @@
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
@@ -38,9 +38,9 @@
pub fn exec(&mut self, default: Stdio) -> io::Error {
if self.saw_nul() {
- return io::Error::new_const(
+ return io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
);
}
@@ -186,9 +186,9 @@
))?;
}
if actual != 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Failed to get exit status of process",
+ "Failed to get exit status of process",
));
}
Ok(ExitStatus(proc_info.return_code))
@@ -224,9 +224,9 @@
))?;
}
if actual != 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Failed to get exit status of process",
+ "Failed to get exit status of process",
));
}
Ok(Some(ExitStatus(proc_info.return_code)))
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index bce35b3..9fc2d9f 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -44,9 +44,9 @@
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
@@ -222,10 +222,7 @@
let envp = self.capture_env();
if self.saw_nul() {
- return io::Error::new_const(
- ErrorKind::InvalidInput,
- &"nul byte found in provided data",
- );
+ return io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data",);
}
match self.setup_io(default, true) {
@@ -581,9 +578,9 @@
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
- Err(Error::new_const(
+ Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid argument: can't kill an exited process",
+ "invalid argument: can't kill an exited process",
))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index 157debf..560c621 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -53,5 +53,10 @@
let status = got.expect("panic unexpectedly propagated");
dbg!(status);
let signal = status.signal().expect("expected child process to die of signal");
- assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP);
+ assert!(
+ signal == libc::SIGABRT
+ || signal == libc::SIGILL
+ || signal == libc::SIGTRAP
+ || signal == libc::SIGSEGV
+ );
}
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index c17822f..c6714d3 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -24,9 +24,9 @@
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
let (ours, theirs) = self.setup_io(default, needs_stdin)?;
@@ -142,9 +142,9 @@
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
- Err(Error::new_const(
+ Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid argument: can't kill an exited process",
+ "invalid argument: can't kill an exited process",
))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 9e02966..cf8cf5a 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -287,7 +287,7 @@
}
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-1 => Err(io::Error::last_os_error()),
- 0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
+ 0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
}
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
@@ -318,7 +318,7 @@
if res == -1 {
return Err(io::Error::last_os_error());
} else if cpus == 0 {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
@@ -344,7 +344,7 @@
if res == -1 {
return Err(io::Error::last_os_error());
} else if cpus == 0 {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
@@ -356,14 +356,14 @@
let res = libc::get_system_info(&mut sinfo);
if res != libc::B_OK {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize))
}
} else {
// FIXME: implement on vxWorks, Redox, l4re
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
}
}
}
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 824283e..59ddd1a 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -154,14 +154,6 @@
Instant { t: unsafe { mach_absolute_time() } }
}
- pub const fn zero() -> Instant {
- Instant { t: 0 }
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
let diff = self.t.checked_sub(other.t)?;
let info = info();
@@ -296,17 +288,6 @@
Instant { t: now(libc::CLOCK_MONOTONIC) }
}
- pub const fn zero() -> Instant {
- Instant { t: Timespec::zero() }
- }
-
- pub fn actually_monotonic() -> bool {
- (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
- || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
- || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
- || cfg!(target_os = "fuchsia")
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
}
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index a06b44e..5274f53 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -21,9 +21,9 @@
}
pub fn unsupported_err() -> std_io::Error {
- std_io::Error::new_const(
+ std_io::const_io_error!(
std_io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
+ "operation not supported on this platform",
)
}
diff --git a/library/std/src/sys/unsupported/os.rs b/library/std/src/sys/unsupported/os.rs
index 2886ec1..e150ae1 100644
--- a/library/std/src/sys/unsupported/os.rs
+++ b/library/std/src/sys/unsupported/os.rs
@@ -81,11 +81,11 @@
}
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot set env vars on this platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
}
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot unset env vars on this platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
}
pub fn temp_dir() -> PathBuf {
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 7846e43..42a1ff7 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -162,6 +162,15 @@
}
}
+impl From<u8> for ExitCode {
+ fn from(code: u8) -> Self {
+ match code {
+ 0 => Self::SUCCESS,
+ 1..=255 => Self::FAILURE,
+ }
+ }
+}
+
pub struct Process(!);
impl Process {
diff --git a/library/std/src/sys/unsupported/time.rs b/library/std/src/sys/unsupported/time.rs
index 8aaf177..6d67b53 100644
--- a/library/std/src/sys/unsupported/time.rs
+++ b/library/std/src/sys/unsupported/time.rs
@@ -13,14 +13,6 @@
panic!("time not implemented on this platform")
}
- pub const fn zero() -> Instant {
- Instant(Duration::from_secs(0))
- }
-
- pub fn actually_monotonic() -> bool {
- false
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0)
}
diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs
index e4f4456..0b9c8e6 100644
--- a/library/std/src/sys/wasi/fd.rs
+++ b/library/std/src/sys/wasi/fd.rs
@@ -228,6 +228,10 @@
unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
}
+ pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result<wasi::Fd> {
+ unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
+ }
+
pub fn sock_recv(
&self,
ri_data: &mut [IoSliceMut<'_>],
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 5924789..cd6815b 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -711,7 +711,7 @@
pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str()
- .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+ .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
@@ -757,7 +757,7 @@
for entry in ReadDir::new(fd, dummy_root) {
let entry = entry?;
let path = crate::str::from_utf8(&entry.name).map_err(|_| {
- io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found")
+ io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
})?;
if entry.file_type()?.is_dir() {
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 8d62335..f878941 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -61,23 +61,26 @@
if errno > u16::MAX as i32 || errno < 0 {
return Uncategorized;
}
- match errno as u16 {
- wasi::ERRNO_CONNREFUSED => ConnectionRefused,
- wasi::ERRNO_CONNRESET => ConnectionReset,
- wasi::ERRNO_PERM | wasi::ERRNO_ACCES => PermissionDenied,
- wasi::ERRNO_PIPE => BrokenPipe,
- wasi::ERRNO_NOTCONN => NotConnected,
- wasi::ERRNO_CONNABORTED => ConnectionAborted,
- wasi::ERRNO_ADDRNOTAVAIL => AddrNotAvailable,
- wasi::ERRNO_ADDRINUSE => AddrInUse,
- wasi::ERRNO_NOENT => NotFound,
- wasi::ERRNO_INTR => Interrupted,
- wasi::ERRNO_INVAL => InvalidInput,
- wasi::ERRNO_TIMEDOUT => TimedOut,
- wasi::ERRNO_EXIST => AlreadyExists,
- wasi::ERRNO_AGAIN => WouldBlock,
- wasi::ERRNO_NOSYS => Unsupported,
- wasi::ERRNO_NOMEM => OutOfMemory,
+
+ match errno {
+ e if e == wasi::ERRNO_CONNREFUSED.raw().into() => ConnectionRefused,
+ e if e == wasi::ERRNO_CONNRESET.raw().into() => ConnectionReset,
+ e if e == wasi::ERRNO_PERM.raw().into() || e == wasi::ERRNO_ACCES.raw().into() => {
+ PermissionDenied
+ }
+ e if e == wasi::ERRNO_PIPE.raw().into() => BrokenPipe,
+ e if e == wasi::ERRNO_NOTCONN.raw().into() => NotConnected,
+ e if e == wasi::ERRNO_CONNABORTED.raw().into() => ConnectionAborted,
+ e if e == wasi::ERRNO_ADDRNOTAVAIL.raw().into() => AddrNotAvailable,
+ e if e == wasi::ERRNO_ADDRINUSE.raw().into() => AddrInUse,
+ e if e == wasi::ERRNO_NOENT.raw().into() => NotFound,
+ e if e == wasi::ERRNO_INTR.raw().into() => Interrupted,
+ e if e == wasi::ERRNO_INVAL.raw().into() => InvalidInput,
+ e if e == wasi::ERRNO_TIMEDOUT.raw().into() => TimedOut,
+ e if e == wasi::ERRNO_EXIST.raw().into() => AlreadyExists,
+ e if e == wasi::ERRNO_AGAIN.raw().into() => WouldBlock,
+ e if e == wasi::ERRNO_NOSYS.raw().into() => Unsupported,
+ e if e == wasi::ERRNO_NOMEM.raw().into() => OutOfMemory,
_ => Uncategorized,
}
}
@@ -96,6 +99,6 @@
return ret;
}
-fn err2io(err: wasi::Error) -> std_io::Error {
- std_io::Error::from_raw_os_error(err.raw_error().into())
+fn err2io(err: wasi::Errno) -> std_io::Error {
+ std_io::Error::from_raw_os_error(err.raw().into())
}
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index a4dbb22..c66e0e4 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -1,5 +1,6 @@
#![deny(unsafe_op_in_unsafe_fn)]
+use super::err2io;
use super::fd::WasiFd;
use crate::convert::TryFrom;
use crate::fmt;
@@ -87,24 +88,24 @@
unsupported()
}
- pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
- unsupported()
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.read_vectored(&mut [IoSliceMut::new(buf)])
}
- pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- unsupported()
+ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.socket().as_inner().read(bufs)
}
pub fn is_read_vectored(&self) -> bool {
true
}
- pub fn write(&self, _: &[u8]) -> io::Result<usize> {
- unsupported()
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.write_vectored(&[IoSlice::new(buf)])
}
- pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
- unsupported()
+ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.socket().as_inner().write(bufs)
}
pub fn is_write_vectored(&self) -> bool {
@@ -155,8 +156,23 @@
unsupported()
}
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
+ pub fn set_nonblocking(&self, state: bool) -> io::Result<()> {
+ let fdstat = unsafe {
+ wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)?
+ };
+
+ let mut flags = fdstat.fs_flags;
+
+ if state {
+ flags |= wasi::FDFLAGS_NONBLOCK;
+ } else {
+ flags &= !wasi::FDFLAGS_NONBLOCK;
+ }
+
+ unsafe {
+ wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags)
+ .map_err(err2io)
+ }
}
pub fn socket(&self) -> &Socket {
@@ -194,7 +210,16 @@
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
- unsupported()
+ let fd = unsafe {
+ wasi::sock_accept(self.as_inner().as_inner().as_raw_fd() as _, 0).map_err(err2io)?
+ };
+
+ Ok((
+ TcpStream::from_inner(unsafe { Socket::from_raw_fd(fd as _) }),
+ // WASI has no concept of SocketAddr yet
+ // return an unspecified IPv4Addr
+ SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0),
+ ))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
@@ -221,8 +246,23 @@
unsupported()
}
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
+ pub fn set_nonblocking(&self, state: bool) -> io::Result<()> {
+ let fdstat = unsafe {
+ wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)?
+ };
+
+ let mut flags = fdstat.fs_flags;
+
+ if state {
+ flags |= wasi::FDFLAGS_NONBLOCK;
+ } else {
+ flags &= !wasi::FDFLAGS_NONBLOCK;
+ }
+
+ unsafe {
+ wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags)
+ .map_err(err2io)
+ }
}
pub fn socket(&self) -> &Socket {
diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs
index 2c8f394..4cc0e4e 100644
--- a/library/std/src/sys/wasi/stdio.rs
+++ b/library/std/src/sys/wasi/stdio.rs
@@ -104,7 +104,7 @@
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn is_ebadf(err: &io::Error) -> bool {
- err.raw_os_error() == Some(wasi::ERRNO_BADF.into())
+ err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into())
}
pub fn panic_output() -> Option<impl io::Write> {
diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs
index 2e4e474..e7a6ab4 100644
--- a/library/std/src/sys/wasi/thread.rs
+++ b/library/std/src/sys/wasi/thread.rs
@@ -41,8 +41,7 @@
let in_ = wasi::Subscription {
userdata: USERDATA,
- r#type: wasi::EVENTTYPE_CLOCK,
- u: wasi::SubscriptionU { clock },
+ u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
};
unsafe {
let mut event: wasi::Event = mem::zeroed();
@@ -51,7 +50,10 @@
(
Ok(1),
wasi::Event {
- userdata: USERDATA, error: 0, r#type: wasi::EVENTTYPE_CLOCK, ..
+ userdata: USERDATA,
+ error: wasi::ERRNO_SUCCESS,
+ type_: wasi::EVENTTYPE_CLOCK,
+ ..
},
) => {}
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs
index 2e720d1..0885856 100644
--- a/library/std/src/sys/wasi/time.rs
+++ b/library/std/src/sys/wasi/time.rs
@@ -10,7 +10,7 @@
pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
-fn current_time(clock: u32) -> Duration {
+fn current_time(clock: wasi::Clockid) -> Duration {
let ts = unsafe {
wasi::clock_time_get(
clock, 1, // precision... seems ignored though?
@@ -25,14 +25,6 @@
Instant(current_time(wasi::CLOCKID_MONOTONIC))
}
- pub const fn zero() -> Instant {
- Instant(Duration::from_secs(0))
- }
-
- pub fn actually_monotonic() -> bool {
- true
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0)
}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 09d3661..c7b6290 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -83,11 +83,13 @@
pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1;
pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400;
+pub const INVALID_FILE_ATTRIBUTES: DWORD = DWORD::MAX;
pub const FILE_SHARE_DELETE: DWORD = 0x4;
pub const FILE_SHARE_READ: DWORD = 0x1;
pub const FILE_SHARE_WRITE: DWORD = 0x2;
+pub const FILE_OPEN: ULONG = 0x00000001;
pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000;
pub const OBJ_DONT_REPARSE: ULONG = 0x1000;
@@ -1074,6 +1076,7 @@
lpBuffer: LPWSTR,
lpFilePart: *mut LPWSTR,
) -> DWORD;
+ pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
}
#[link(name = "ws2_32")]
@@ -1228,15 +1231,20 @@
compat_fn! {
"ntdll":
- pub fn NtOpenFile(
+ pub fn NtCreateFile(
FileHandle: *mut HANDLE,
DesiredAccess: ACCESS_MASK,
ObjectAttributes: *const OBJECT_ATTRIBUTES,
IoStatusBlock: *mut IO_STATUS_BLOCK,
+ AllocationSize: *mut i64,
+ FileAttributes: ULONG,
ShareAccess: ULONG,
- OpenOptions: ULONG
+ CreateDisposition: ULONG,
+ CreateOptions: ULONG,
+ EaBuffer: *mut c_void,
+ EaLength: ULONG
) -> NTSTATUS {
- panic!("`NtOpenFile` not available");
+ panic!("`NtCreateFile` not available");
}
pub fn RtlNtStatusToDosError(
Status: NTSTATUS
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index dd21c6b..cb83ee2 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -460,7 +460,7 @@
}
pub fn duplicate(&self) -> io::Result<File> {
- Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
+ Ok(Self { handle: self.handle.try_clone()? })
}
fn reparse_point<'a>(
@@ -511,9 +511,9 @@
)
}
_ => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"Unsupported reparse point type",
+ "Unsupported reparse point type",
));
}
};
@@ -712,11 +712,11 @@
/// Open a link relative to the parent directory, ensure no symlinks are followed.
fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<File> {
- // This is implemented using the lower level `NtOpenFile` function as
+ // This is implemented using the lower level `NtCreateFile` function as
// unfortunately opening a file relative to a parent is not supported by
// win32 functions. It is however a fundamental feature of the NT kernel.
//
- // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile
+ // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile
unsafe {
let mut handle = ptr::null_mut();
let mut io_status = c::IO_STATUS_BLOCK::default();
@@ -732,14 +732,19 @@
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
..c::OBJECT_ATTRIBUTES::default()
};
- let status = c::NtOpenFile(
+ let status = c::NtCreateFile(
&mut handle,
access,
&object,
&mut io_status,
+ crate::ptr::null_mut(),
+ 0,
c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+ c::FILE_OPEN,
// If `name` is a symlink then open the link rather than the target.
c::FILE_OPEN_REPARSE_POINT,
+ crate::ptr::null_mut(),
+ 0,
);
// Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError")
if c::nt_success(status) {
@@ -1124,9 +1129,9 @@
#[cfg(target_vendor = "uwp")]
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"hard link are not supported on UWP",
+ "hard link are not supported on UWP",
));
}
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index c3a3482..daab39b 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -262,26 +262,17 @@
Ok(written as usize)
}
+ pub fn try_clone(&self) -> io::Result<Self> {
+ Ok(Self(self.0.try_clone()?))
+ }
+
pub fn duplicate(
&self,
access: c::DWORD,
inherit: bool,
options: c::DWORD,
- ) -> io::Result<Handle> {
- let mut ret = 0 as c::HANDLE;
- cvt(unsafe {
- let cur_proc = c::GetCurrentProcess();
- c::DuplicateHandle(
- cur_proc,
- self.as_raw_handle(),
- cur_proc,
- &mut ret,
- access,
- inherit as c::BOOL,
- options,
- )
- })?;
- unsafe { Ok(Handle::from_raw_handle(ret)) }
+ ) -> io::Result<Self> {
+ Ok(Self(self.0.duplicate(access, inherit, options)?))
}
}
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 084af43..dc28817 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -71,6 +71,7 @@
c::ERROR_FILE_NOT_FOUND => return NotFound,
c::ERROR_PATH_NOT_FOUND => return NotFound,
c::ERROR_NO_DATA => return BrokenPipe,
+ c::ERROR_INVALID_NAME => return InvalidFilename,
c::ERROR_INVALID_PARAMETER => return InvalidInput,
c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
c::ERROR_SEM_TIMEOUT
@@ -104,7 +105,7 @@
c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
- c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
+ c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
_ => {}
}
@@ -160,9 +161,9 @@
fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
if unrolled_find_u16s(0, &maybe_result).is_some() {
- return Err(crate::io::Error::new_const(
+ return Err(crate::io::const_io_error!(
ErrorKind::InvalidInput,
- &"strings passed to WinAPI cannot contain NULs",
+ "strings passed to WinAPI cannot contain NULs",
));
}
maybe_result.push(0);
@@ -285,6 +286,7 @@
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
+ #[cfg(not(miri))] // inline assembly does not work in Miri
unsafe {
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 9c631e7..aa6400a 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -134,7 +134,7 @@
unsafe {
let socket = Self::from_raw_socket(socket);
- socket.set_no_inherit()?;
+ socket.0.set_no_inherit()?;
Ok(socket)
}
}
@@ -152,9 +152,9 @@
match result {
Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
@@ -185,9 +185,7 @@
};
match count {
- 0 => {
- Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
- }
+ 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
if writefds.fd_count != 1 {
if let Some(e) = self.take_error()? {
@@ -213,52 +211,7 @@
}
pub fn duplicate(&self) -> io::Result<Socket> {
- let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
- let result = unsafe {
- c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
- };
- cvt(result)?;
- let socket = unsafe {
- c::WSASocketW(
- info.iAddressFamily,
- info.iSocketType,
- info.iProtocol,
- &mut info,
- 0,
- c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
- )
- };
-
- if socket != c::INVALID_SOCKET {
- unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
- } else {
- let error = unsafe { c::WSAGetLastError() };
-
- if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
- return Err(io::Error::from_raw_os_error(error));
- }
-
- let socket = unsafe {
- c::WSASocketW(
- info.iAddressFamily,
- info.iSocketType,
- info.iProtocol,
- &mut info,
- 0,
- c::WSA_FLAG_OVERLAPPED,
- )
- };
-
- if socket == c::INVALID_SOCKET {
- return Err(last_error());
- }
-
- unsafe {
- let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
- socket.set_no_inherit()?;
- Ok(socket)
- }
- }
+ Ok(Self(self.0.try_clone()?))
}
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
@@ -398,9 +351,9 @@
Some(dur) => {
let timeout = sys::dur2timeout(dur);
if timeout == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
timeout
@@ -421,19 +374,6 @@
}
}
- #[cfg(not(target_vendor = "uwp"))]
- fn set_no_inherit(&self) -> io::Result<()> {
- sys::cvt(unsafe {
- c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
- })
- .map(drop)
- }
-
- #[cfg(target_vendor = "uwp")]
- fn set_no_inherit(&self) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
- }
-
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Write => c::SD_SEND,
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index 79e0eaf..e54fcae 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -260,3 +260,19 @@
)?;
Ok(path)
}
+
+/// Make a Windows path absolute.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+ if path.as_os_str().bytes().starts_with(br"\\?\") {
+ return Ok(path.into());
+ }
+ let path = to_u16s(path)?;
+ let lpfilename = path.as_ptr();
+ fill_utf16_buf(
+ // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+ // `lpfilename` is a pointer to a null terminated string that is not
+ // invalidated until after `GetFullPathNameW` returns successfully.
+ |buffer, size| unsafe { c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) },
+ super::os2path,
+ )
+}
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 5ad5704..fafd141 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -149,7 +149,7 @@
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
if str.as_ref().encode_wide().any(|b| b == 0) {
- Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
} else {
Ok(str)
}
@@ -369,9 +369,9 @@
) -> io::Result<PathBuf> {
// Early return if there is no filename.
if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"program path has no file name",
+ "program path has no file name",
));
}
// Test if the file name has the `exe` extension.
@@ -394,7 +394,7 @@
// Append `.exe` if not already there.
path = path::append_suffix(path, EXE_SUFFIX.as_ref());
- if path.try_exists().unwrap_or(false) {
+ if program_exists(&path) {
return Ok(path);
} else {
// It's ok to use `set_extension` here because the intent is to
@@ -415,14 +415,14 @@
if !has_extension {
path.set_extension(EXE_EXTENSION);
}
- if let Ok(true) = path.try_exists() { Some(path) } else { None }
+ if program_exists(&path) { Some(path) } else { None }
});
if let Some(path) = result {
return Ok(path);
}
}
// If we get here then the executable cannot be found.
- Err(io::Error::new_const(io::ErrorKind::NotFound, &"program not found"))
+ Err(io::const_io_error!(io::ErrorKind::NotFound, "program not found"))
}
// Calls `f` for every path that should be used to find an executable.
@@ -485,6 +485,21 @@
None
}
+/// Check if a file exists without following symlinks.
+fn program_exists(path: &Path) -> bool {
+ unsafe {
+ to_u16s(path)
+ .map(|path| {
+ // Getting attributes using `GetFileAttributesW` does not follow symlinks
+ // and it will almost always be successful if the link exists.
+ // There are some exceptions for special system files (e.g. the pagefile)
+ // but these are not executable.
+ c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
+ })
+ .unwrap_or(false)
+ }
+}
+
impl Stdio {
fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
match *self {
@@ -666,6 +681,12 @@
}
}
+impl From<u8> for ExitCode {
+ fn from(code: u8) -> Self {
+ ExitCode(c::DWORD::from(code))
+ }
+}
+
fn zeroed_startupinfo() -> c::STARTUPINFO {
c::STARTUPINFO {
cb: 0,
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index f122176..d18c3d8 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -135,6 +135,8 @@
fn windows_exe_resolver() {
use super::resolve_exe;
use crate::io;
+ use crate::sys::fs::symlink;
+ use crate::sys_common::io::test::tmpdir;
let env_paths = || env::var_os("PATH");
@@ -178,4 +180,13 @@
// The application's directory is also searched.
let current_exe = env::current_exe().unwrap();
assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
+
+ // Create a temporary path and add a broken symlink.
+ let temp = tmpdir();
+ let mut exe_path = temp.path().to_owned();
+ exe_path.push("exists.exe");
+ symlink("<DOES NOT EXIST>".as_ref(), &exe_path).unwrap();
+
+ // A broken symlink should still be resolved.
+ assert!(resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok());
}
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 684b8e3..a001d6b 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -110,9 +110,9 @@
if data[0] >> 6 != 0b10 {
// not a continuation byte - reject
incomplete_utf8.len = 0;
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
incomplete_utf8.bytes[incomplete_utf8.len as usize] = data[0];
@@ -132,9 +132,9 @@
return Ok(1);
}
Err(_) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
}
@@ -156,9 +156,9 @@
incomplete_utf8.len = 1;
return Ok(1);
} else {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
}
@@ -364,9 +364,9 @@
}
Err(_) => {
// We can't really do any better than forget all data and return an error.
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdin in console mode does not support non-UTF-16 input; \
+ "Windows stdin in console mode does not support non-UTF-16 input; \
encountered unpaired surrogate",
));
}
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 75f70c2..e4bba92 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -107,9 +107,9 @@
sysinfo.dwNumberOfProcessors as usize
};
match res {
- 0 => Err(io::Error::new_const(
+ 0 => Err(io::const_io_error!(
io::ErrorKind::NotFound,
- &"The number of hardware threads is not known for the target platform",
+ "The number of hardware threads is not known for the target platform",
)),
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
}
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 91e4f76..a04908b 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -41,14 +41,6 @@
perf_counter::PerformanceCounterInstant::now().into()
}
- pub fn actually_monotonic() -> bool {
- false
- }
-
- pub const fn zero() -> Instant {
- Instant { t: Duration::from_secs(0) }
- }
-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
// On windows there's a threshold below which we consider two timestamps
// equivalent due to measurement error. For more details + doc link,
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index d5e8f12..b0b5559 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -7,7 +7,6 @@
use crate::io;
use crate::io::prelude::*;
use crate::path::{self, Path, PathBuf};
-use crate::sync::atomic::{self, Ordering};
use crate::sys_common::mutex::StaticMutex;
/// Max number of frames to print.
@@ -144,51 +143,6 @@
result
}
-pub enum RustBacktrace {
- Print(PrintFmt),
- Disabled,
- RuntimeDisabled,
-}
-
-// For now logging is turned off by default, and this function checks to see
-// whether the magical environment variable is present to see if it's turned on.
-pub fn rust_backtrace_env() -> RustBacktrace {
- // If the `backtrace` feature of this crate isn't enabled quickly return
- // `None` so this can be constant propagated all over the place to turn
- // optimize away callers.
- if !cfg!(feature = "backtrace") {
- return RustBacktrace::Disabled;
- }
-
- // Setting environment variables for Fuchsia components isn't a standard
- // or easily supported workflow. For now, always display backtraces.
- if cfg!(target_os = "fuchsia") {
- return RustBacktrace::Print(PrintFmt::Full);
- }
-
- static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
- match ENABLED.load(Ordering::SeqCst) {
- 0 => {}
- 1 => return RustBacktrace::RuntimeDisabled,
- 2 => return RustBacktrace::Print(PrintFmt::Short),
- _ => return RustBacktrace::Print(PrintFmt::Full),
- }
-
- let (format, cache) = env::var_os("RUST_BACKTRACE")
- .map(|x| {
- if &x == "0" {
- (RustBacktrace::RuntimeDisabled, 1)
- } else if &x == "full" {
- (RustBacktrace::Print(PrintFmt::Full), 3)
- } else {
- (RustBacktrace::Print(PrintFmt::Short), 2)
- }
- })
- .unwrap_or((RustBacktrace::RuntimeDisabled, 1));
- ENABLED.store(cache, Ordering::SeqCst);
- format
-}
-
/// Prints the filename of the backtrace frame.
///
/// See also `output`.
diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs
index 309f548..617ac52 100644
--- a/library/std/src/sys_common/fs.rs
+++ b/library/std/src/sys_common/fs.rs
@@ -4,9 +4,9 @@
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;
-pub(crate) const NOT_FILE_ERROR: Error = Error::new_const(
+pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!(
ErrorKind::InvalidInput,
- &"the source path is neither a regular file nor a symlink to a regular file",
+ "the source path is neither a regular file nor a symlink to a regular file",
);
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
index ea9108f..d1e9fed 100644
--- a/library/std/src/sys_common/io.rs
+++ b/library/std/src/sys_common/io.rs
@@ -8,6 +8,7 @@
use crate::env;
use crate::fs;
use crate::path::{Path, PathBuf};
+ use crate::thread;
use rand::RngCore;
pub struct TempDir(PathBuf);
@@ -29,7 +30,12 @@
// Gee, seeing how we're testing the fs module I sure hope that we
// at least implement this correctly!
let TempDir(ref p) = *self;
- fs::remove_dir_all(p).unwrap();
+ let result = fs::remove_dir_all(p);
+ // Avoid panicking while panicking as this causes the process to
+ // immediately abort, without displaying test results.
+ if !thread::panicking() {
+ result.unwrap();
+ }
}
}
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index c5c3df3..70b29d4 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -5,7 +5,7 @@
use crate::convert::{TryFrom, TryInto};
use crate::ffi::CString;
use crate::fmt;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
use crate::mem;
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::ptr;
@@ -102,7 +102,7 @@
*(storage as *const _ as *const c::sockaddr_in6)
})))
}
- _ => Err(Error::new_const(ErrorKind::InvalidInput, &"invalid argument")),
+ _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument")),
}
}
@@ -165,7 +165,7 @@
($e:expr, $msg:expr) => {
match $e {
Some(r) => r,
- None => return Err(io::Error::new_const(io::ErrorKind::InvalidInput, &$msg)),
+ None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)),
}
};
}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 1d2f6e9..1be3ed7 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -142,6 +142,7 @@
/// [`std::thread::LocalKey`]: crate::thread::LocalKey
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
#[allow_internal_unstable(thread_local_internals)]
macro_rules! thread_local {
// empty (base case for the recursion)
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index ae4b658..f8d790c 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -180,6 +180,12 @@
#[macro_use]
mod local;
+#[unstable(feature = "scoped_threads", issue = "93203")]
+mod scoped;
+
+#[unstable(feature = "scoped_threads", issue = "93203")]
+pub use scoped::{scope, Scope, ScopedJoinHandle};
+
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::local::{AccessError, LocalKey};
@@ -447,6 +453,20 @@
F: Send + 'a,
T: Send + 'a,
{
+ Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?))
+ }
+
+ unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
+ self,
+ f: F,
+ scope_data: Option<&'scope scoped::ScopeData>,
+ ) -> io::Result<JoinInner<'scope, T>>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'a,
+ T: Send + 'a,
+ 'scope: 'a,
+ {
let Builder { name, stack_size } = self;
let stack_size = stack_size.unwrap_or_else(thread::min_stack);
@@ -456,7 +476,8 @@
}));
let their_thread = my_thread.clone();
- let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
+ let my_packet: Arc<Packet<'scope, T>> =
+ Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
let their_packet = my_packet.clone();
let output_capture = crate::io::set_output_capture(None);
@@ -480,10 +501,14 @@
// closure (it is an Arc<...>) and `my_packet` will be stored in the
// same `JoinInner` as this closure meaning the mutation will be
// safe (not modify it and affect a value far away).
- unsafe { *their_packet.get() = Some(try_result) };
+ unsafe { *their_packet.result.get() = Some(try_result) };
};
- Ok(JoinHandle(JoinInner {
+ if let Some(scope_data) = scope_data {
+ scope_data.increment_num_running_threads();
+ }
+
+ Ok(JoinInner {
// SAFETY:
//
// `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
@@ -498,16 +523,16 @@
// exist after the thread has terminated, which is signaled by `Thread::join`
// returning.
native: unsafe {
- Some(imp::Thread::new(
+ imp::Thread::new(
stack_size,
mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(
Box::new(main),
),
- )?)
+ )?
},
thread: my_thread,
- packet: Packet(my_packet),
- }))
+ packet: my_packet,
+ })
}
}
@@ -1242,34 +1267,48 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
-// This packet is used to communicate the return value between the spawned thread
-// and the rest of the program. Memory is shared through the `Arc` within and there's
-// no need for a mutex here because synchronization happens with `join()` (the
-// caller will never read this packet until the thread has exited).
+// This packet is used to communicate the return value between the spawned
+// thread and the rest of the program. It is shared through an `Arc` and
+// there's no need for a mutex here because synchronization happens with `join()`
+// (the caller will never read this packet until the thread has exited).
//
-// This packet itself is then stored into a `JoinInner` which in turns is placed
-// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
-// manually worry about impls like Send and Sync. The type `T` should
-// already always be Send (otherwise the thread could not have been created) and
-// this type is inherently Sync because no methods take &self. Regardless,
-// however, we add inheriting impls for Send/Sync to this type to ensure it's
-// Send/Sync and that future modifications will still appropriately classify it.
-struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
-
-unsafe impl<T: Send> Send for Packet<T> {}
-unsafe impl<T: Sync> Sync for Packet<T> {}
-
-/// Inner representation for JoinHandle
-struct JoinInner<T> {
- native: Option<imp::Thread>,
- thread: Thread,
- packet: Packet<T>,
+// An Arc to the packet is stored into a `JoinInner` which in turns is placed
+// in `JoinHandle`.
+struct Packet<'scope, T> {
+ scope: Option<&'scope scoped::ScopeData>,
+ result: UnsafeCell<Option<Result<T>>>,
}
-impl<T> JoinInner<T> {
- fn join(&mut self) -> Result<T> {
- self.native.take().unwrap().join();
- unsafe { (*self.packet.0.get()).take().unwrap() }
+// Due to the usage of `UnsafeCell` we need to manually implement Sync.
+// The type `T` should already always be Send (otherwise the thread could not
+// have been created) and the Packet is Sync because all access to the
+// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
+unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
+
+impl<'scope, T> Drop for Packet<'scope, T> {
+ fn drop(&mut self) {
+ // Book-keeping so the scope knows when it's done.
+ if let Some(scope) = self.scope {
+ // If this packet was for a thread that ran in a scope, the thread
+ // panicked, and nobody consumed the panic payload, we make sure
+ // the scope function will panic.
+ let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+ scope.decrement_num_running_threads(unhandled_panic);
+ }
+ }
+}
+
+/// Inner representation for JoinHandle
+struct JoinInner<'scope, T> {
+ native: imp::Thread,
+ thread: Thread,
+ packet: Arc<Packet<'scope, T>>,
+}
+
+impl<'scope, T> JoinInner<'scope, T> {
+ fn join(mut self) -> Result<T> {
+ self.native.join();
+ Arc::get_mut(&mut self.packet).unwrap().result.get_mut().take().unwrap()
}
}
@@ -1336,7 +1375,7 @@
/// [`thread::Builder::spawn`]: Builder::spawn
/// [`thread::spawn`]: spawn
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct JoinHandle<T>(JoinInner<T>);
+pub struct JoinHandle<T>(JoinInner<'static, T>);
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
unsafe impl<T> Send for JoinHandle<T> {}
@@ -1400,29 +1439,29 @@
/// join_handle.join().expect("Couldn't join on the associated thread");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn join(mut self) -> Result<T> {
+ pub fn join(self) -> Result<T> {
self.0.join()
}
- /// Checks if the the associated thread is still running its main function.
+ /// Checks if the associated thread is still running its main function.
///
/// This might return `false` for a brief moment after the thread's main
/// function has returned, but before the thread itself has stopped running.
#[unstable(feature = "thread_is_running", issue = "90470")]
pub fn is_running(&self) -> bool {
- Arc::strong_count(&self.0.packet.0) > 1
+ Arc::strong_count(&self.0.packet) > 1
}
}
impl<T> AsInner<imp::Thread> for JoinHandle<T> {
fn as_inner(&self) -> &imp::Thread {
- self.0.native.as_ref().unwrap()
+ &self.0.native
}
}
impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
fn into_inner(self) -> imp::Thread {
- self.0.native.unwrap()
+ self.0.native
}
}
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
new file mode 100644
index 0000000..9dd7c15
--- /dev/null
+++ b/library/std/src/thread/scoped.rs
@@ -0,0 +1,316 @@
+use super::{current, park, Builder, JoinInner, Result, Thread};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::sync::Arc;
+
+/// A scope to spawn scoped threads in.
+///
+/// See [`scope`] for details.
+pub struct Scope<'env> {
+ data: ScopeData,
+ /// Invariance over 'env, to make sure 'env cannot shrink,
+ /// which is necessary for soundness.
+ ///
+ /// Without invariance, this would compile fine but be unsound:
+ ///
+ /// ```compile_fail
+ /// #![feature(scoped_threads)]
+ ///
+ /// std::thread::scope(|s| {
+ /// s.spawn(|s| {
+ /// let a = String::from("abcd");
+ /// s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+ /// });
+ /// });
+ /// ```
+ env: PhantomData<&'env mut &'env ()>,
+}
+
+/// An owned permission to join on a scoped thread (block on its termination).
+///
+/// See [`Scope::spawn`] for details.
+pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
+
+pub(super) struct ScopeData {
+ num_running_threads: AtomicUsize,
+ a_thread_panicked: AtomicBool,
+ main_thread: Thread,
+}
+
+impl ScopeData {
+ pub(super) fn increment_num_running_threads(&self) {
+ // We check for 'overflow' with usize::MAX / 2, to make sure there's no
+ // chance it overflows to 0, which would result in unsoundness.
+ if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
+ // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
+ self.decrement_num_running_threads(false);
+ panic!("too many running threads in thread scope");
+ }
+ }
+ pub(super) fn decrement_num_running_threads(&self, panic: bool) {
+ if panic {
+ self.a_thread_panicked.store(true, Ordering::Relaxed);
+ }
+ if self.num_running_threads.fetch_sub(1, Ordering::Release) == 1 {
+ self.main_thread.unpark();
+ }
+ }
+}
+
+/// Create a scope for spawning scoped threads.
+///
+/// The function passed to `scope` will be provided a [`Scope`] object,
+/// through which scoped threads can be [spawned][`Scope::spawn`].
+///
+/// Unlike non-scoped threads, scoped threads can borrow non-`'static` data,
+/// as the scope guarantees all threads will be joined at the end of the scope.
+///
+/// All threads spawned within the scope that haven't been manually joined
+/// will be automatically joined before this function returns.
+///
+/// # Panics
+///
+/// If any of the automatically joined threads panicked, this function will panic.
+///
+/// If you want to handle panics from spawned threads,
+/// [`join`][ScopedJoinHandle::join] them before the end of the scope.
+///
+/// # Example
+///
+/// ```
+/// #![feature(scoped_threads)]
+/// use std::thread;
+///
+/// let mut a = vec![1, 2, 3];
+/// let mut x = 0;
+///
+/// thread::scope(|s| {
+/// s.spawn(|_| {
+/// println!("hello from the first scoped thread");
+/// // We can borrow `a` here.
+/// dbg!(&a);
+/// });
+/// s.spawn(|_| {
+/// println!("hello from the second scoped thread");
+/// // We can even mutably borrow `x` here,
+/// // because no other threads are using it.
+/// x += a[0] + a[2];
+/// });
+/// println!("hello from the main thread");
+/// });
+///
+/// // After the scope, we can modify and access our variables again:
+/// a.push(4);
+/// assert_eq!(x, a.len());
+/// ```
+#[track_caller]
+pub fn scope<'env, F, T>(f: F) -> T
+where
+ F: FnOnce(&Scope<'env>) -> T,
+{
+ let scope = Scope {
+ data: ScopeData {
+ num_running_threads: AtomicUsize::new(0),
+ main_thread: current(),
+ a_thread_panicked: AtomicBool::new(false),
+ },
+ env: PhantomData,
+ };
+
+ // Run `f`, but catch panics so we can make sure to wait for all the threads to join.
+ let result = catch_unwind(AssertUnwindSafe(|| f(&scope)));
+
+ // Wait until all the threads are finished.
+ while scope.data.num_running_threads.load(Ordering::Acquire) != 0 {
+ park();
+ }
+
+ // Throw any panic from `f`, or the return value of `f` if no thread panicked.
+ match result {
+ Err(e) => resume_unwind(e),
+ Ok(_) if scope.data.a_thread_panicked.load(Ordering::Relaxed) => {
+ panic!("a scoped thread panicked")
+ }
+ Ok(result) => result,
+ }
+}
+
+impl<'env> Scope<'env> {
+ /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
+ ///
+ /// Unlike non-scoped threads, threads spawned with this function may
+ /// borrow non-`'static` data from the outside the scope. See [`scope`] for
+ /// details.
+ ///
+ /// The join handle provides a [`join`] method that can be used to join the spawned
+ /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
+ /// the panic payload.
+ ///
+ /// If the join handle is dropped, the spawned thread will implicitly joined at the
+ /// end of the scope. In that case, if the spawned thread panics, [`scope`] will
+ /// panic after all threads are joined.
+ ///
+ /// This call will create a thread using default parameters of [`Builder`].
+ /// If you want to specify the stack size or the name of the thread, use
+ /// [`Builder::spawn_scoped`] instead.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the OS fails to create a thread; use [`Builder::spawn_scoped`]
+ /// to recover from such errors.
+ ///
+ /// [`join`]: ScopedJoinHandle::join
+ pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+ where
+ F: FnOnce(&Scope<'env>) -> T + Send + 'env,
+ T: Send + 'env,
+ {
+ Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
+ }
+}
+
+impl Builder {
+ /// Spawns a new scoped thread using the settings set through this `Builder`.
+ ///
+ /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to
+ /// capture any failure to create the thread at the OS level.
+ ///
+ /// [`io::Result`]: crate::io::Result
+ ///
+ /// # Panics
+ ///
+ /// Panics if a thread name was set and it contained null bytes.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(scoped_threads)]
+ /// use std::thread;
+ ///
+ /// let mut a = vec![1, 2, 3];
+ /// let mut x = 0;
+ ///
+ /// thread::scope(|s| {
+ /// thread::Builder::new()
+ /// .name("first".to_string())
+ /// .spawn_scoped(s, |_|
+ /// {
+ /// println!("hello from the {:?} scoped thread", thread::current().name());
+ /// // We can borrow `a` here.
+ /// dbg!(&a);
+ /// })
+ /// .unwrap();
+ /// thread::Builder::new()
+ /// .name("second".to_string())
+ /// .spawn_scoped(s, |_|
+ /// {
+ /// println!("hello from the {:?} scoped thread", thread::current().name());
+ /// // We can even mutably borrow `x` here,
+ /// // because no other threads are using it.
+ /// x += a[0] + a[2];
+ /// })
+ /// .unwrap();
+ /// println!("hello from the main thread");
+ /// });
+ ///
+ /// // After the scope, we can modify and access our variables again:
+ /// a.push(4);
+ /// assert_eq!(x, a.len());
+ /// ```
+ pub fn spawn_scoped<'scope, 'env, F, T>(
+ self,
+ scope: &'scope Scope<'env>,
+ f: F,
+ ) -> io::Result<ScopedJoinHandle<'scope, T>>
+ where
+ F: FnOnce(&Scope<'env>) -> T + Send + 'env,
+ T: Send + 'env,
+ {
+ Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+ }
+}
+
+impl<'scope, T> ScopedJoinHandle<'scope, T> {
+ /// Extracts a handle to the underlying thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(scoped_threads)]
+ /// #![feature(thread_is_running)]
+ ///
+ /// use std::thread;
+ ///
+ /// thread::scope(|s| {
+ /// let t = s.spawn(|_| {
+ /// println!("hello");
+ /// });
+ /// println!("thread id: {:?}", t.thread().id());
+ /// });
+ /// ```
+ #[must_use]
+ pub fn thread(&self) -> &Thread {
+ &self.0.thread
+ }
+
+ /// Waits for the associated thread to finish.
+ ///
+ /// This function will return immediately if the associated thread has already finished.
+ ///
+ /// In terms of [atomic memory orderings], the completion of the associated
+ /// thread synchronizes with this function returning.
+ /// In other words, all operations performed by that thread
+ /// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses)
+ /// all operations that happen after `join` returns.
+ ///
+ /// If the associated thread panics, [`Err`] is returned with the panic payload.
+ ///
+ /// [atomic memory orderings]: crate::sync::atomic
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(scoped_threads)]
+ /// #![feature(thread_is_running)]
+ ///
+ /// use std::thread;
+ ///
+ /// thread::scope(|s| {
+ /// let t = s.spawn(|_| {
+ /// panic!("oh no");
+ /// });
+ /// assert!(t.join().is_err());
+ /// });
+ /// ```
+ pub fn join(self) -> Result<T> {
+ self.0.join()
+ }
+
+ /// Checks if the associated thread is still running its main function.
+ ///
+ /// This might return `false` for a brief moment after the thread's main
+ /// function has returned, but before the thread itself has stopped running.
+ #[unstable(feature = "thread_is_running", issue = "90470")]
+ pub fn is_running(&self) -> bool {
+ Arc::strong_count(&self.0.packet) > 1
+ }
+}
+
+impl<'env> fmt::Debug for Scope<'env> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Scope")
+ .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
+ .field("a_thread_panicked", &self.data.a_thread_panicked.load(Ordering::Relaxed))
+ .field("main_thread", &self.data.main_thread)
+ .finish_non_exhaustive()
+ }
+}
+
+impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ScopedJoinHandle").finish_non_exhaustive()
+ }
+}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 86cc93c..df8a726 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -31,7 +31,6 @@
#![stable(feature = "time", since = "1.3.0")]
-mod monotonic;
#[cfg(test)]
mod tests;
@@ -45,16 +44,16 @@
pub use core::time::Duration;
#[unstable(feature = "duration_checked_float", issue = "83400")]
-pub use core::time::FromSecsError;
+pub use core::time::FromFloatSecsError;
/// A measurement of a monotonically nondecreasing clock.
/// Opaque and useful only with [`Duration`].
///
-/// Instants are always guaranteed to be no less than any previously measured
-/// instant when created, and are often useful for tasks such as measuring
+/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously
+/// measured instant when created, and are often useful for tasks such as measuring
/// benchmarks or timing how long an operation takes.
///
-/// Note, however, that instants are not guaranteed to be **steady**. In other
+/// Note, however, that instants are **not** guaranteed to be **steady**. In other
/// words, each tick of the underlying clock might not be the same length (e.g.
/// some seconds may be longer than others). An instant may jump forwards or
/// experience time dilation (slow down or speed up), but it will never go
@@ -84,6 +83,8 @@
/// }
/// ```
///
+/// [platform bugs]: Instant#monotonicity
+///
/// # OS-specific behaviors
///
/// An `Instant` is a wrapper around system-specific types and it may behave
@@ -125,6 +126,26 @@
/// > structure cannot represent the new point in time.
///
/// [`add`]: Instant::add
+///
+/// ## Monotonicity
+///
+/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior
+/// if available, which is the case for all [tier 1] platforms.
+/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization
+/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks
+/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this
+/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations
+/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order.
+///
+/// This workaround obscures programming errors where earlier and later instants are accidentally
+/// swapped. For this reason future rust versions may reintroduce panics.
+///
+/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html
+/// [`duration_since`]: Instant::duration_since
+/// [`elapsed`]: Instant::elapsed
+/// [`sub`]: Instant::sub
+/// [`checked_duration_since`]: Instant::checked_duration_since
+///
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct Instant(time::Instant);
@@ -176,7 +197,12 @@
/// }
/// ```
///
-/// # Underlying System calls
+/// # Platform-specific behavior
+///
+/// The precision of `SystemTime` can depend on the underlying OS-specific time format.
+/// For example, on Windows the time is represented in 100 nanosecond intervals whereas Linux
+/// can represent nanosecond intervals.
+///
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
@@ -242,59 +268,19 @@
#[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> Instant {
- let os_now = time::Instant::now();
-
- // And here we come upon a sad state of affairs. The whole point of
- // `Instant` is that it's monotonically increasing. We've found in the
- // wild, however, that it's not actually monotonically increasing for
- // one reason or another. These appear to be OS and hardware level bugs,
- // and there's not really a whole lot we can do about them. Here's a
- // taste of what we've found:
- //
- // * #48514 - OpenBSD, x86_64
- // * #49281 - linux arm64 and s390x
- // * #51648 - windows, x86
- // * #56560 - windows, x86_64, AWS
- // * #56612 - windows, x86, vm (?)
- // * #56940 - linux, arm64
- // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
- // Firefox bug
- //
- // It seems that this just happens a lot in the wild.
- // We're seeing panics across various platforms where consecutive calls
- // to `Instant::now`, such as via the `elapsed` function, are panicking
- // as they're going backwards. Placed here is a last-ditch effort to try
- // to fix things up. We keep a global "latest now" instance which is
- // returned instead of what the OS says if the OS goes backwards.
- //
- // To hopefully mitigate the impact of this, a few platforms are
- // excluded as "these at least haven't gone backwards yet".
- //
- // While issues have been seen on arm64 platforms the Arm architecture
- // requires that the counter monotonically increases and that it must
- // provide a uniform view of system time (e.g. it must not be possible
- // for a core to receive a message from another core with a time stamp
- // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
- // there have been a few 64bit SoCs that have bugs which cause time to
- // not monoticially increase, these have been fixed in the Linux kernel
- // and we shouldn't penalize all Arm SoCs for those who refuse to
- // update their kernels:
- // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
- // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
- // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
- // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
- if time::Instant::actually_monotonic() {
- return Instant(os_now);
- }
-
- Instant(monotonic::monotonize(os_now))
+ Instant(time::Instant::now())
}
- /// Returns the amount of time elapsed from another instant to this one.
+ /// Returns the amount of time elapsed from another instant to this one,
+ /// or zero duration if that instant is later than this one.
///
/// # Panics
///
- /// This function will panic if `earlier` is later than `self`.
+ /// Previous rust versions panicked when `earlier` was later than `self`. Currently this
+ /// method saturates. Future versions may reintroduce the panic in some circumstances.
+ /// See [Monotonicity].
+ ///
+ /// [Monotonicity]: Instant#monotonicity
///
/// # Examples
///
@@ -306,16 +292,22 @@
/// sleep(Duration::new(1, 0));
/// let new_now = Instant::now();
/// println!("{:?}", new_now.duration_since(now));
+ /// println!("{:?}", now.duration_since(new_now)); // 0ns
/// ```
#[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration_since(&self, earlier: Instant) -> Duration {
- self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
+ self.checked_duration_since(earlier).unwrap_or_default()
}
/// Returns the amount of time elapsed from another instant to this one,
/// or None if that instant is later than this one.
///
+ /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s,
+ /// this method can return `None`.
+ ///
+ /// [monotonicity bugs]: Instant#monotonicity
+ ///
/// # Examples
///
/// ```no_run
@@ -359,9 +351,11 @@
///
/// # Panics
///
- /// This function may panic if the current time is earlier than this
- /// instant, which is something that can happen if an `Instant` is
- /// produced synthetically.
+ /// Previous rust versions panicked when self was earlier than the current time. Currently this
+ /// method returns a Duration of zero in that case. Future versions may reintroduce the panic.
+ /// See [Monotonicity].
+ ///
+ /// [Monotonicity]: Instant#monotonicity
///
/// # Examples
///
@@ -437,6 +431,16 @@
impl Sub<Instant> for Instant {
type Output = Duration;
+ /// Returns the amount of time elapsed from another instant to this one,
+ /// or zero duration if that instant is later than this one.
+ ///
+ /// # Panics
+ ///
+ /// Previous rust versions panicked when `other` was later than `self`. Currently this
+ /// method saturates. Future versions may reintroduce the panic in some circumstances.
+ /// See [Monotonicity].
+ ///
+ /// [Monotonicity]: Instant#monotonicity
fn sub(self, other: Instant) -> Duration {
self.duration_since(other)
}
diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
deleted file mode 100644
index 64f1624..0000000
--- a/library/std/src/time/monotonic.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-use crate::sys::time;
-
-#[inline]
-pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
- inner::monotonize(raw)
-}
-
-#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))]
-pub mod inner {
- use crate::sync::atomic::AtomicU64;
- use crate::sync::atomic::Ordering::*;
- use crate::sys::time;
- use crate::time::Duration;
-
- pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();
-
- // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
- const UNINITIALIZED: u64 = 0b11 << 30;
- static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);
-
- #[inline]
- pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
- monotonize_impl(&MONO, raw)
- }
-
- #[inline]
- pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
- let delta = raw.checked_sub_instant(&ZERO).unwrap();
- let secs = delta.as_secs();
- // occupies no more than 30 bits (10^9 seconds)
- let nanos = delta.subsec_nanos() as u64;
-
- // This wraps around every 136 years (2^32 seconds).
- // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
- // than 2^31 seconds as expected and everything else as a backslide which will be
- // monotonized.
- // This could be a problem for programs that call instants at intervals greater
- // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
- let packed = (secs << 32) | nanos;
- let updated = mono.fetch_update(Relaxed, Relaxed, |old| {
- (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed)
- });
- match updated {
- Ok(_) => raw,
- Err(newer) => {
- // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
- // passed in value and the 64bits loaded from the atomic
- let seconds_lower = newer >> 32;
- let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
- if secs & 0xffff_ffff > seconds_lower {
- // Backslide caused the lower 32bit of the seconds part to wrap.
- // This must be the case because the seconds part is larger even though
- // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
- //
- // We assume that backslides are smaller than 2^32 seconds
- // which means we need to add 1 to the upper half to restore it.
- //
- // Example:
- // most recent observed time: 0xA1_0000_0000_0000_0000u128
- // bits stored in AtomicU64: 0x0000_0000_0000_0000u64
- // backslide by 1s
- // caller time is 0xA0_ffff_ffff_0000_0000u128
- // -> we can fix up the upper half time by adding 1 << 32
- seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
- }
- let secs = seconds_upper | seconds_lower;
- let nanos = newer as u32;
- ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
- }
- }
- }
-}
-
-#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))]
-pub mod inner {
- use crate::sync::atomic::AtomicU128;
- use crate::sync::atomic::Ordering::*;
- use crate::sys::time;
- use crate::time::Duration;
-
- const ZERO: time::Instant = time::Instant::zero();
- static MONO: AtomicU128 = AtomicU128::new(0);
-
- #[inline]
- pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
- let delta = raw.checked_sub_instant(&ZERO).unwrap();
- // Split into seconds and nanos since Duration doesn't have a
- // constructor that takes a u128
- let secs = delta.as_secs() as u128;
- let nanos = delta.subsec_nanos() as u128;
- let timestamp: u128 = secs << 64 | nanos;
- let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
- let secs = (timestamp >> 64) as u64;
- let nanos = timestamp as u32;
- ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
- }
-}
-
-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
-pub mod inner {
- use crate::cmp;
- use crate::sys::time;
- use crate::sys_common::mutex::StaticMutex;
-
- #[inline]
- pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
- static LOCK: StaticMutex = StaticMutex::new();
- static mut LAST_NOW: time::Instant = time::Instant::zero();
- unsafe {
- let _lock = LOCK.lock();
- let now = cmp::max(LAST_NOW, os_now);
- LAST_NOW = now;
- now
- }
- }
-}
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 7279925..d1a69ff 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -90,10 +90,9 @@
}
#[test]
-#[should_panic]
-fn instant_duration_since_panic() {
+fn instant_duration_since_saturates() {
let a = Instant::now();
- let _ = (a - Duration::SECOND).duration_since(a);
+ assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO);
}
#[test]
@@ -109,6 +108,7 @@
#[test]
fn instant_saturating_duration_since_nopanic() {
let a = Instant::now();
+ #[allow(deprecated, deprecated_in_future)]
let ret = (a - Duration::SECOND).saturating_duration_since(a);
assert_eq!(ret, Duration::ZERO);
}
@@ -192,31 +192,6 @@
assert!(a < hundred_twenty_years);
}
-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
-#[test]
-fn monotonizer_wrapping_backslide() {
- use super::monotonic::inner::{monotonize_impl, ZERO};
- use core::sync::atomic::AtomicU64;
-
- let reference = AtomicU64::new(0);
-
- let time = match ZERO.checked_add_duration(&Duration::from_secs(0xffff_ffff)) {
- Some(time) => time,
- None => {
- // platform cannot represent u32::MAX seconds so it won't have to deal with this kind
- // of overflow either
- return;
- }
- };
-
- let monotonized = monotonize_impl(&reference, time);
- let expected = ZERO.checked_add_duration(&Duration::from_secs(1 << 32)).unwrap();
- assert_eq!(
- monotonized, expected,
- "64bit monotonizer should handle overflows in the seconds part"
- );
-}
-
macro_rules! bench_instant_threaded {
($bench_name:ident, $thread_count:expr) => {
#[bench]
diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs
index 079f00a..54873f5 100644
--- a/library/std/tests/run-time-detect.rs
+++ b/library/std/tests/run-time-detect.rs
@@ -3,10 +3,9 @@
#![cfg_attr(
any(
all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
- all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
+ all(bootstrap, target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
all(target_arch = "powerpc", target_os = "linux"),
all(target_arch = "powerpc64", target_os = "linux"),
- any(target_arch = "x86", target_arch = "x86_64"),
),
feature(stdsimd)
)]
@@ -14,6 +13,7 @@
#[test]
#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
fn arm_linux() {
+ use std::arch::is_arm_feature_detected;
println!("neon: {}", is_arm_feature_detected!("neon"));
println!("pmull: {}", is_arm_feature_detected!("pmull"));
println!("crypto: {}", is_arm_feature_detected!("crypto"));
@@ -25,6 +25,7 @@
#[test]
#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
fn aarch64_linux() {
+ use std::arch::is_aarch64_feature_detected;
println!("neon: {}", is_aarch64_feature_detected!("neon"));
println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
println!("pmull: {}", is_aarch64_feature_detected!("pmull"));
@@ -44,7 +45,8 @@
println!("flagm: {}", is_aarch64_feature_detected!("flagm"));
println!("ssbs: {}", is_aarch64_feature_detected!("ssbs"));
println!("sb: {}", is_aarch64_feature_detected!("sb"));
- println!("pauth: {}", is_aarch64_feature_detected!("pauth"));
+ println!("paca: {}", is_aarch64_feature_detected!("paca"));
+ println!("pacg: {}", is_aarch64_feature_detected!("pacg"));
println!("dpb: {}", is_aarch64_feature_detected!("dpb"));
println!("dpb2: {}", is_aarch64_feature_detected!("dpb2"));
println!("sve2: {}", is_aarch64_feature_detected!("sve2"));
@@ -71,6 +73,7 @@
#[test]
#[cfg(all(target_arch = "powerpc", target_os = "linux"))]
fn powerpc_linux() {
+ use std::arch::is_powerpc_feature_detected;
println!("altivec: {}", is_powerpc_feature_detected!("altivec"));
println!("vsx: {}", is_powerpc_feature_detected!("vsx"));
println!("power8: {}", is_powerpc_feature_detected!("power8"));
@@ -79,6 +82,7 @@
#[test]
#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
fn powerpc64_linux() {
+ use std::arch::is_powerpc64_feature_detected;
println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
println!("power8: {}", is_powerpc64_feature_detected!("power8"));
@@ -87,6 +91,8 @@
#[test]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn x86_all() {
+ use std::arch::is_x86_feature_detected;
+
// the below is the set of features we can test at runtime, but don't actually
// use to gate anything and are thus not part of the X86_ALLOWED_FEATURES list
diff --git a/library/stdarch/crates/core_arch/avx512bw.md b/library/stdarch/crates/core_arch/avx512bw.md
index fa50c66..20c8c2f 100644
--- a/library/stdarch/crates/core_arch/avx512bw.md
+++ b/library/stdarch/crates/core_arch/avx512bw.md
@@ -1,34 +1,34 @@
<summary>["AVX512BW"]</summary><p>
* [x] [`_mm512_loadu_epi16`]
- * [_] [`_mm512_mask_loadu_epi16`] //need i1
- * [_] [`_mm512_maskz_loadu_epi16`] //need i1
+ * [x] [`_mm512_mask_loadu_epi16`] //need i1
+ * [x] [`_mm512_maskz_loadu_epi16`] //need i1
* [x] [`_mm_loadu_epi16`]
- * [_] [`_mm_mask_loadu_epi16`] //need i1
- * [_] [`_mm_maskz_loadu_epi16`] //need i1
+ * [x] [`_mm_mask_loadu_epi16`] //need i1
+ * [x] [`_mm_maskz_loadu_epi16`] //need i1
* [x] [`_mm256_loadu_epi16`]
- * [_] [`_mm256_mask_loadu_epi16`] //need i1
- * [_] [`_mm256_maskz_loadu_epi16`] //need i1
+ * [x] [`_mm256_mask_loadu_epi16`] //need i1
+ * [x] [`_mm256_maskz_loadu_epi16`] //need i1
* [x] [`_mm512_loadu_epi8`]
- * [_] [`_mm512_mask_loadu_epi8`] //need i1
- * [_] [`_mm512_maskz_loadu_epi8`] //need i1
+ * [x] [`_mm512_mask_loadu_epi8`] //need i1
+ * [x] [`_mm512_maskz_loadu_epi8`] //need i1
* [x] [`_mm_loadu_epi8`]
- * [_] [`_mm_mask_loadu_epi8`] //need i1
- * [_] [`_mm_maskz_loadu_epi8`] //need i1
+ * [x] [`_mm_mask_loadu_epi8`] //need i1
+ * [x] [`_mm_maskz_loadu_epi8`] //need i1
* [x] [`_mm256_loadu_epi8`]
- * [_] [`_mm256_mask_loadu_epi8`] //need i1
- * [_] [`_mm256_maskz_loadu_epi8`] //need i1
- * [_] [`_mm512_mask_storeu_epi16`]
+ * [x] [`_mm256_mask_loadu_epi8`] //need i1
+ * [x] [`_mm256_maskz_loadu_epi8`] //need i1
+ * [x] [`_mm512_mask_storeu_epi16`]
* [x] [`_mm512_storeu_epi16`]
- * [_] [`_mm_mask_storeu_epi16`] //need i1
+ * [x] [`_mm_mask_storeu_epi16`] //need i1
* [x] [`_mm_storeu_epi16`]
- * [_] [`_mm256_mask_storeu_epi16`] //need i1
+ * [x] [`_mm256_mask_storeu_epi16`] //need i1
* [x] [`_mm256_storeu_epi16`]
- * [_] [`_mm512_mask_storeu_epi8`] //need i1
+ * [x] [`_mm512_mask_storeu_epi8`] //need i1
* [x] [`_mm512_storeu_epi8`]
- * [_] [`_mm_mask_storeu_epi8`] //need i1
+ * [x] [`_mm_mask_storeu_epi8`] //need i1
* [x] [`_mm_storeu_epi8`]
- * [_] [`_mm256_mask_storeu_epi8`] //need i1
+ * [x] [`_mm256_mask_storeu_epi8`] //need i1
* [x] [`_mm256_storeu_epi8`]
* [x] [`_mm512_abs_epi16`]
* [x] [`_mm512_mask_abs_epi16`]
diff --git a/library/stdarch/crates/core_arch/avx512f.md b/library/stdarch/crates/core_arch/avx512f.md
index 9d95f0c..6cb6e65 100644
--- a/library/stdarch/crates/core_arch/avx512f.md
+++ b/library/stdarch/crates/core_arch/avx512f.md
@@ -1629,18 +1629,18 @@
* [x] [`_mm_maskz_compress_pd`]
* [x] [`_mm256_mask_compress_pd`]
* [x] [`_mm256_maskz_compress_pd`]
- * [ ] [`_mm512_mask_compressstoreu_epi32`] //need i1
- * [_] [`_mm_mask_compressstoreu_epi32`] //need i1
- * [_] [`_mm256_mask_compressstoreu_epi32`] //need i1
- * [ ] [`_mm512_mask_compressstoreu_epi64`] //need i1
- * [_] [`_mm_mask_compressstoreu_epi64`] //need i1
- * [_] [`_mm256_mask_compressstoreu_epi64`] //need i1
- * [ ] [`_mm512_mask_compressstoreu_ps`] //need i1
- * [_] [`_mm_mask_compressstoreu_ps`] //need i1
- * [_] [`_mm256_mask_compressstoreu_ps`] //need i1
- * [ ] [`_mm512_mask_compressstoreu_pd`] //need i1
- * [_] [`_mm_mask_compressstoreu_pd`] //need i1
- * [_] [`_mm256_mask_compressstoreu_pd`] //need i1
+ * [x] [`_mm512_mask_compressstoreu_epi32`] //need i1
+ * [x] [`_mm_mask_compressstoreu_epi32`] //need i1
+ * [x] [`_mm256_mask_compressstoreu_epi32`] //need i1
+ * [x] [`_mm512_mask_compressstoreu_epi64`] //need i1
+ * [x] [`_mm_mask_compressstoreu_epi64`] //need i1
+ * [x] [`_mm256_mask_compressstoreu_epi64`] //need i1
+ * [x] [`_mm512_mask_compressstoreu_ps`] //need i1
+ * [x] [`_mm_mask_compressstoreu_ps`] //need i1
+ * [x] [`_mm256_mask_compressstoreu_ps`] //need i1
+ * [x] [`_mm512_mask_compressstoreu_pd`] //need i1
+ * [x] [`_mm_mask_compressstoreu_pd`] //need i1
+ * [x] [`_mm256_mask_compressstoreu_pd`] //need i1
* [x] [`_mm512_mask_expand_epi32`]
* [x] [`_mm512_maskz_expand_epi32`]
* [x] [`_mm_mask_expand_epi32`]
@@ -1665,30 +1665,30 @@
* [x] [`_mm_maskz_expand_pd`]
* [x] [`_mm256_mask_expand_pd`]
* [x] [`_mm256_maskz_expand_pd`]
- * [ ] [`_mm512_mask_expandloadu_epi32`] //need i1
- * [ ] [`_mm512_maskz_expandloadu_epi32`] //need i1
- * [_] [`_mm_mask_expandloadu_epi32`] //need i1
- * [_] [`_mm_maskz_expandloadu_epi32`] //need i1
- * [_] [`_mm256_mask_expandloadu_epi32`] //need i1
- * [_] [`_mm256_maskz_expandloadu_epi32`] //need i1
- * [ ] [`_mm512_mask_expandloadu_epi64`] //need i1
- * [ ] [`_mm512_maskz_expandloadu_epi64`] //need i1
- * [_] [`_mm_mask_expandloadu_epi64`] //need i1
- * [_] [`_mm_maskz_expandloadu_epi64`] //need i1
- * [_] [`_mm256_mask_expandloadu_epi64`] //need i1
- * [_] [`_mm256_maskz_expandloadu_epi64`] //need i1
- * [ ] [`_mm512_mask_expandloadu_ps`] //need i1
- * [ ] [`_mm512_maskz_expandloadu_ps`] //need i1
- * [_] [`_mm_mask_expandloadu_ps`] //need i1
- * [_] [`_mm_maskz_expandloadu_ps`] //need i1
- * [_] [`_mm256_mask_expandloadu_ps`] //need i1
- * [_] [`_mm256_maskz_expandloadu_ps`] //need i1
- * [ ] [`_mm512_mask_expandloadu_pd`] //need i1
- * [ ] [`_mm512_maskz_expandloadu_pd`] //need i1
- * [_] [`_mm_mask_expandloadu_pd`] //need i1
- * [_] [`_mm_maskz_expandloadu_pd`] //need i1
- * [_] [`_mm256_mask_expandloadu_pd`] //need i1
- * [_] [`_mm256_maskz_expandloadu_pd`] //need i1
+ * [x] [`_mm512_mask_expandloadu_epi32`] //need i1
+ * [x] [`_mm512_maskz_expandloadu_epi32`] //need i1
+ * [x] [`_mm_mask_expandloadu_epi32`] //need i1
+ * [x] [`_mm_maskz_expandloadu_epi32`] //need i1
+ * [x] [`_mm256_mask_expandloadu_epi32`] //need i1
+ * [x] [`_mm256_maskz_expandloadu_epi32`] //need i1
+ * [x] [`_mm512_mask_expandloadu_epi64`] //need i1
+ * [x] [`_mm512_maskz_expandloadu_epi64`] //need i1
+ * [x] [`_mm_mask_expandloadu_epi64`] //need i1
+ * [x] [`_mm_maskz_expandloadu_epi64`] //need i1
+ * [x] [`_mm256_mask_expandloadu_epi64`] //need i1
+ * [x] [`_mm256_maskz_expandloadu_epi64`] //need i1
+ * [x] [`_mm512_mask_expandloadu_ps`] //need i1
+ * [x] [`_mm512_maskz_expandloadu_ps`] //need i1
+ * [x] [`_mm_mask_expandloadu_ps`] //need i1
+ * [x] [`_mm_maskz_expandloadu_ps`] //need i1
+ * [x] [`_mm256_mask_expandloadu_ps`] //need i1
+ * [x] [`_mm256_maskz_expandloadu_ps`] //need i1
+ * [x] [`_mm512_mask_expandloadu_pd`] //need i1
+ * [x] [`_mm512_maskz_expandloadu_pd`] //need i1
+ * [x] [`_mm_mask_expandloadu_pd`] //need i1
+ * [x] [`_mm_maskz_expandloadu_pd`] //need i1
+ * [x] [`_mm256_mask_expandloadu_pd`] //need i1
+ * [x] [`_mm256_maskz_expandloadu_pd`] //need i1
* [x] [`_mm512_zextpd128_pd512`]
* [x] [`_mm512_zextpd256_pd512`]
* [x] [`_mm512_zextps128_ps512`]
diff --git a/library/stdarch/crates/core_arch/avx512vbmi2.md b/library/stdarch/crates/core_arch/avx512vbmi2.md
deleted file mode 100644
index 693af9d..0000000
--- a/library/stdarch/crates/core_arch/avx512vbmi2.md
+++ /dev/null
@@ -1,153 +0,0 @@
-<summary>["AVX512_VBMI2"]</summary><p>
-
- * [x] [`_mm_mask_compress_epi16`]
- * [x] [`_mm_maskz_compress_epi16`]
- * [x] [`_mm256_mask_compress_epi16`]
- * [x] [`_mm256_maskz_compress_epi16`]
- * [x] [`_mm512_mask_compress_epi16`]
- * [x] [`_mm512_maskz_compress_epi16`]
- * [x] [`_mm_mask_compress_epi8`]
- * [x] [`_mm_maskz_compress_epi8`]
- * [x] [`_mm256_mask_compress_epi8`]
- * [x] [`_mm256_maskz_compress_epi8`]
- * [x] [`_mm512_mask_compress_epi8`]
- * [x] [`_mm512_maskz_compress_epi8`]
- * [_] [`_mm_mask_compressstoreu_epi16`] //need i1
- * [_] [`_mm256_mask_compressstoreu_epi16`] //need i1
- * [_] [`_mm512_mask_compressstoreu_epi16`] //need i1
- * [_] [`_mm_mask_compressstoreu_epi8`] //need i1
- * [_] [`_mm256_mask_compressstoreu_epi8`] //need i1
- * [_] [`_mm512_mask_compressstoreu_epi8`] //need i1
- * [x] [`_mm_mask_expand_epi16`]
- * [x] [`_mm_maskz_expand_epi16`]
- * [x] [`_mm256_mask_expand_epi16`]
- * [x] [`_mm256_maskz_expand_epi16`]
- * [x] [`_mm512_mask_expand_epi16`]
- * [x] [`_mm512_maskz_expand_epi16`]
- * [x] [`_mm_mask_expand_epi8`]
- * [x] [`_mm_maskz_expand_epi8`]
- * [x] [`_mm256_mask_expand_epi8`]
- * [x] [`_mm256_maskz_expand_epi8`]
- * [x] [`_mm512_mask_expand_epi8`]
- * [x] [`_mm512_maskz_expand_epi8`]
- * [_] [`_mm_mask_expandloadu_epi16`] //need i1
- * [_] [`_mm_maskz_expandloadu_epi16`] //need i1
- * [_] [`_mm256_mask_expandloadu_epi16`] //need i1
- * [_] [`_mm256_maskz_expandloadu_epi16`] //need i1
- * [_] [`_mm512_mask_expandloadu_epi16`] //need i1
- * [_] [`_mm512_maskz_expandloadu_epi16`] //need i1
- * [_] [`_mm_mask_expandloadu_epi8`] //need i1
- * [_] [`_mm_maskz_expandloadu_epi8`] //need i1
- * [_] [`_mm256_mask_expandloadu_epi8`] //need i1
- * [_] [`_mm256_maskz_expandloadu_epi8`] //need i1
- * [_] [`_mm512_mask_expandloadu_epi8`] //need i1
- * [_] [`_mm512_maskz_expandloadu_epi8`] //need i1
- * [x] [`_mm_mask_shldi_epi16`]
- * [x] [`_mm_maskz_shldi_epi16`]
- * [x] [`_mm_shldi_epi16`]
- * [x] [`_mm256_mask_shldi_epi16`]
- * [x] [`_mm256_maskz_shldi_epi16`]
- * [x] [`_mm256_shldi_epi16`]
- * [x] [`_mm512_mask_shldi_epi16`]
- * [x] [`_mm512_maskz_shldi_epi16`]
- * [x] [`_mm512_shldi_epi16`]
- * [x] [`_mm_mask_shldi_epi32`]
- * [x] [`_mm_maskz_shldi_epi32`]
- * [x] [`_mm_shldi_epi32`]
- * [x] [`_mm256_mask_shldi_epi32`]
- * [x] [`_mm256_maskz_shldi_epi32`]
- * [x] [`_mm256_shldi_epi32`]
- * [x] [`_mm512_mask_shldi_epi32`]
- * [x] [`_mm512_maskz_shldi_epi32`]
- * [x] [`_mm512_shldi_epi32`]
- * [x] [`_mm_mask_shldi_epi64`]
- * [x] [`_mm_maskz_shldi_epi64`]
- * [x] [`_mm_shldi_epi64`]
- * [x] [`_mm256_mask_shldi_epi64`]
- * [x] [`_mm256_maskz_shldi_epi64`]
- * [x] [`_mm256_shldi_epi64`]
- * [x] [`_mm512_mask_shldi_epi64`]
- * [x] [`_mm512_maskz_shldi_epi64`]
- * [x] [`_mm512_shldi_epi64`]
- * [x] [`_mm_mask_shldv_epi16`]
- * [x] [`_mm_maskz_shldv_epi16`]
- * [x] [`_mm_shldv_epi16`]
- * [x] [`_mm256_mask_shldv_epi16`]
- * [x] [`_mm256_maskz_shldv_epi16`]
- * [x] [`_mm256_shldv_epi16`]
- * [x] [`_mm512_mask_shldv_epi16`]
- * [x] [`_mm512_maskz_shldv_epi16`]
- * [x] [`_mm512_shldv_epi16`]
- * [x] [`_mm_mask_shldv_epi32`]
- * [x] [`_mm_maskz_shldv_epi32`]
- * [x] [`_mm_shldv_epi32`]
- * [x] [`_mm256_mask_shldv_epi32`]
- * [x] [`_mm256_maskz_shldv_epi32`]
- * [x] [`_mm256_shldv_epi32`]
- * [x] [`_mm512_mask_shldv_epi32`]
- * [x] [`_mm512_maskz_shldv_epi32`]
- * [x] [`_mm512_shldv_epi32`]
- * [x] [`_mm_mask_shldv_epi64`]
- * [x] [`_mm_maskz_shldv_epi64`]
- * [x] [`_mm_shldv_epi64`]
- * [x] [`_mm256_mask_shldv_epi64`]
- * [x] [`_mm256_maskz_shldv_epi64`]
- * [x] [`_mm256_shldv_epi64`]
- * [x] [`_mm512_mask_shldv_epi64`]
- * [x] [`_mm512_maskz_shldv_epi64`]
- * [x] [`_mm512_shldv_epi64`]
- * [x] [`_mm_mask_shrdi_epi16`]
- * [x] [`_mm_maskz_shrdi_epi16`]
- * [x] [`_mm_shrdi_epi16`]
- * [x] [`_mm256_mask_shrdi_epi16`]
- * [x] [`_mm256_maskz_shrdi_epi16`]
- * [x] [`_mm256_shrdi_epi16`]
- * [x] [`_mm512_mask_shrdi_epi16`]
- * [x] [`_mm512_maskz_shrdi_epi16`]
- * [x] [`_mm512_shrdi_epi16`]
- * [x] [`_mm_mask_shrdi_epi32`]
- * [x] [`_mm_maskz_shrdi_epi32`]
- * [x] [`_mm_shrdi_epi32`]
- * [x] [`_mm256_mask_shrdi_epi32`]
- * [x] [`_mm256_maskz_shrdi_epi32`]
- * [x] [`_mm256_shrdi_epi32`]
- * [x] [`_mm512_mask_shrdi_epi32`]
- * [x] [`_mm512_maskz_shrdi_epi32`]
- * [x] [`_mm512_shrdi_epi32`]
- * [x] [`_mm_mask_shrdi_epi64`]
- * [x] [`_mm_maskz_shrdi_epi64`]
- * [x] [`_mm_shrdi_epi64`]
- * [x] [`_mm256_mask_shrdi_epi64`]
- * [x] [`_mm256_maskz_shrdi_epi64`]
- * [x] [`_mm256_shrdi_epi64`]
- * [x] [`_mm512_mask_shrdi_epi64`]
- * [x] [`_mm512_maskz_shrdi_epi64`]
- * [x] [`_mm512_shrdi_epi64`]
- * [x] [`_mm_mask_shrdv_epi16`]
- * [x] [`_mm_maskz_shrdv_epi16`]
- * [x] [`_mm_shrdv_epi16`]
- * [x] [`_mm256_mask_shrdv_epi16`]
- * [x] [`_mm256_maskz_shrdv_epi16`]
- * [x] [`_mm256_shrdv_epi16`]
- * [x] [`_mm512_mask_shrdv_epi16`]
- * [x] [`_mm512_maskz_shrdv_epi16`]
- * [x] [`_mm512_shrdv_epi16`]
- * [x] [`_mm_mask_shrdv_epi32`]
- * [x] [`_mm_maskz_shrdv_epi32`]
- * [x] [`_mm_shrdv_epi32`]
- * [x] [`_mm256_mask_shrdv_epi32`]
- * [x] [`_mm256_maskz_shrdv_epi32`]
- * [x] [`_mm256_shrdv_epi32`]
- * [x] [`_mm512_mask_shrdv_epi32`]
- * [x] [`_mm512_maskz_shrdv_epi32`]
- * [x] [`_mm512_shrdv_epi32`]
- * [x] [`_mm_mask_shrdv_epi64`]
- * [x] [`_mm_maskz_shrdv_epi64`]
- * [x] [`_mm_shrdv_epi64`]
- * [x] [`_mm256_mask_shrdv_epi64`]
- * [x] [`_mm256_maskz_shrdv_epi64`]
- * [x] [`_mm256_shrdv_epi64`]
- * [x] [`_mm512_mask_shrdv_epi64`]
- * [x] [`_mm512_maskz_shrdv_epi64`]
- * [x] [`_mm512_shrdv_epi64`]
-</p>
diff --git a/library/stdarch/crates/core_arch/src/core_arch_docs.md b/library/stdarch/crates/core_arch/src/core_arch_docs.md
index 58b7eda..eddd1fc 100644
--- a/library/stdarch/crates/core_arch/src/core_arch_docs.md
+++ b/library/stdarch/crates/core_arch/src/core_arch_docs.md
@@ -194,18 +194,18 @@
* [`nvptx`]
* [`wasm32`]
-[`x86`]: x86/index.html
-[`x86_64`]: x86_64/index.html
-[`arm`]: arm/index.html
-[`aarch64`]: aarch64/index.html
-[`riscv32`]: riscv32/index.html
-[`riscv64`]: riscv64/index.html
-[`mips`]: mips/index.html
-[`mips64`]: mips64/index.html
-[`powerpc`]: powerpc/index.html
-[`powerpc64`]: powerpc64/index.html
-[`nvptx`]: nvptx/index.html
-[`wasm32`]: wasm32/index.html
+[`x86`]: ../../core/arch/x86/index.html
+[`x86_64`]: ../../core/arch/x86_64/index.html
+[`arm`]: ../../core/arch/arm/index.html
+[`aarch64`]: ../../core/arch/aarch64/index.html
+[`riscv32`]: ../../core/arch/riscv32/index.html
+[`riscv64`]: ../../core/arch/riscv64/index.html
+[`mips`]: ../../core/arch/mips/index.html
+[`mips64`]: ../../core/arch/mips64/index.html
+[`powerpc`]: ../../core/arch/powerpc/index.html
+[`powerpc64`]: ../../core/arch/powerpc64/index.html
+[`nvptx`]: ../../core/arch/nvptx/index.html
+[`wasm32`]: ../../core/arch/wasm32/index.html
# Examples
diff --git a/library/stdarch/crates/core_arch/src/riscv64/mod.rs b/library/stdarch/crates/core_arch/src/riscv64/mod.rs
index 24aae78..751b9a8 100644
--- a/library/stdarch/crates/core_arch/src/riscv64/mod.rs
+++ b/library/stdarch/crates/core_arch/src/riscv64/mod.rs
@@ -10,7 +10,7 @@
/// This operation is not available under RV32 base instruction set.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.WU`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_wu(src: *const u32) -> u32 {
let value: u32;
@@ -18,7 +18,7 @@
value
}
-/// Loads virtual machine memory by unsigned double integer
+/// Loads virtual machine memory by double integer
///
/// This instruction performs an explicit memory access as though `V=1`;
/// i.e., with the address translation and protection, and the endianness, that apply to memory
@@ -27,7 +27,7 @@
/// This operation is not available under RV32 base instruction set.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.D`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_d(src: *const i64) -> i64 {
let value: i64;
@@ -42,7 +42,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.D`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hsv_d(dst: *mut i64, src: i64) {
asm!(".insn r 0x73, 0x4, 0x37, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
diff --git a/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs b/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs
index a2c9cb2..347735d 100644
--- a/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs
+++ b/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs
@@ -153,7 +153,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.B`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_b(src: *const i8) -> i8 {
let value: i8;
@@ -168,7 +168,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.BU`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_bu(src: *const u8) -> u8 {
let value: u8;
@@ -183,7 +183,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.H`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_h(src: *const i16) -> i16 {
let value: i16;
@@ -198,7 +198,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.HU`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_hu(src: *const u16) -> u16 {
let value: u16;
@@ -213,7 +213,7 @@
/// but read permission is not required.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLVX.HU`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlvx_hu(src: *const u16) -> u16 {
let insn: u16;
@@ -228,7 +228,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLV.W`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlv_w(src: *const i32) -> i32 {
let value: i32;
@@ -243,7 +243,7 @@
/// but read permission is not required.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HLVX.WU`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hlvx_wu(src: *const u32) -> u32 {
let insn: u32;
@@ -258,7 +258,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.B`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hsv_b(dst: *mut i8, src: i8) {
asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
@@ -271,7 +271,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.H`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hsv_h(dst: *mut i16, src: i16) {
asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
@@ -284,7 +284,7 @@
/// accesses in either VS-mode or VU-mode.
///
/// This function is unsafe for it accesses the virtual supervisor or user via a `HSV.W`
-/// instruction which is effectively an unreference to any memory address.
+/// instruction which is effectively a dereference to any memory address.
#[inline]
pub unsafe fn hsv_w(dst: *mut i32, src: i32) {
asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack));
@@ -469,6 +469,111 @@
asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid, options(nostack))
}
+/// Reads the floating-point control and status register `fcsr`
+///
+/// Register `fcsr` is a 32-bit read/write register that selects the dynamic rounding mode
+/// for floating-point arithmetic operations and holds the accrued exception flag.
+///
+/// Accoding to "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,
+/// register `fcsr` is defined as:
+///
+/// | Bit index | Meaning |
+/// |:----------|:--------|
+/// | 0..=4 | Accrued Exceptions (`fflags`) |
+/// | 5..=7 | Rounding Mode (`frm`) |
+/// | 8..=31 | _Reserved_ |
+///
+/// For definition of each field, visit [`frrm`] and [`frflags`].
+///
+/// [`frrm`]: fn.frrm.html
+/// [`frflags`]: fn.frflags.html
+#[inline]
+pub fn frcsr() -> u32 {
+ let value: u32;
+ unsafe { asm!("frcsr {}", out(reg) value, options(nomem, nostack)) };
+ value
+}
+
+/// Swaps the floating-point control and status register `fcsr`
+///
+/// This function swaps the value in `fcsr` by copying the original value to be returned,
+/// and then writing a new value obtained from input variable `value` into `fcsr`.
+#[inline]
+pub fn fscsr(value: u32) -> u32 {
+ let original: u32;
+ unsafe { asm!("fscsr {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
+ original
+}
+
+/// Reads the floating-point rounding mode register `frm`
+///
+/// Accoding to "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,
+/// the rounding mode field is defined as listed in the table below:
+///
+/// | Rounding Mode | Mnemonic | Meaning |
+/// |:-------------|:----------|:---------|
+/// | 000 | RNE | Round to Nearest, ties to Even |
+/// | 001 | RTZ | Round towards Zero |
+/// | 010 | RDN | Round Down (towards −∞) |
+/// | 011 | RUP | Round Up (towards +∞) |
+/// | 100 | RMM | Round to Nearest, ties to Max Magnitude |
+/// | 101 | | _Reserved for future use._ |
+/// | 110 | | _Reserved for future use._ |
+/// | 111 | DYN | In Rounding Mode register, _reserved_. |
+#[inline]
+pub fn frrm() -> u32 {
+ let value: u32;
+ unsafe { asm!("frrm {}", out(reg) value, options(nomem, nostack)) };
+ value
+}
+
+/// Swaps the floating-point rounding mode register `frm`
+///
+/// This function swaps the value in `frm` by copying the original value to be returned,
+/// and then writing a new value obtained from the three least-significant bits of
+/// input variable `value` into `frm`.
+#[inline]
+pub fn fsrm(value: u32) -> u32 {
+ let original: u32;
+ unsafe { asm!("fsrm {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
+ original
+}
+
+/// Reads the floating-point accrued exception flags register `fflags`
+///
+/// The accrued exception flags indicate the exception conditions that have arisen
+/// on any floating-point arithmetic instruction since the field was last reset by software.
+///
+/// Accoding to "F" Standard Extension for Single-Precision Floating-Point, Version 2.2,
+/// the accured exception flags is defined as a bit vector of 5 bits.
+/// The meaning of each binary bit is listed in the table below.
+///
+/// | Bit index | Mnemonic | Meaning |
+/// |:--|:---|:-----------------|
+/// | 4 | NV | Invalid Operation |
+/// | 3 | DZ | Divide by Zero |
+/// | 2 | OF | Overflow |
+/// | 1 | UF | Underflow |
+/// | 0 | NX | Inexact |
+#[inline]
+pub fn frflags() -> u32 {
+ let value: u32;
+ unsafe { asm!("frflags {}", out(reg) value, options(nomem, nostack)) };
+ value
+}
+
+/// Swaps the floating-point accrued exception flags register `fflags`
+///
+/// This function swaps the value in `fflags` by copying the original value to be returned,
+/// and then writing a new value obtained from the five least-significant bits of
+/// input variable `value` into `fflags`.
+#[inline]
+pub fn fsflags(value: u32) -> u32 {
+ let original: u32;
+ unsafe { asm!("fsflags {}, {}", out(reg) original, in(reg) value, options(nomem, nostack)) }
+ original
+}
+
/// Invalidate hypervisor translation cache for all virtual machines and guest physical addresses
///
/// This instruction invalidates any address-translation cache entries that an
@@ -479,3 +584,188 @@
pub unsafe fn hinval_gvma_all() {
asm!(".insn r 0x73, 0, 0x33, x0, x0, x0", options(nostack))
}
+
+/// `P0` transformation function as is used in the SM3 hash algorithm
+///
+/// This function is included in `Zksh` extension. It's defined as:
+///
+/// ```text
+/// P0(X) = X ⊕ (X ≪ 9) ⊕ (X ≪ 17)
+/// ```
+///
+/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
+///
+/// In the SM3 algorithm, the `P0` transformation is used as `E ← P0(TT2)` when the
+/// compression function `CF` uses the intermediate value `TT2` to calculate
+/// the variable `E` in one iteration for subsequent processes.
+///
+/// According to RISC-V Cryptography Extensions, Volume I, the execution latency of
+/// this instruction must always be independent from the data it operates on.
+#[inline]
+pub fn sm3p0(x: u32) -> u32 {
+ let ans: u32;
+ unsafe {
+ // asm!("sm3p0 {}, {}", out(reg) ans, in(reg) x, options(nomem, nostack))
+ asm!(".insn i 0x13, 0x1, {}, {}, 0x108", out(reg) ans, in(reg) x, options(nomem, nostack))
+ };
+ ans
+}
+
+/// `P1` transformation function as is used in the SM3 hash algorithm
+///
+/// This function is included in `Zksh` extension. It's defined as:
+///
+/// ```text
+/// P1(X) = X ⊕ (X ≪ 15) ⊕ (X ≪ 23)
+/// ```
+///
+/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
+///
+/// In the SM3 algorithm, the `P1` transformation is used to expand message,
+/// where expanded word `Wj` can be generated from the previous words.
+/// The whole process can be described as the following pseudocode:
+///
+/// ```text
+/// FOR j=16 TO 67
+/// Wj ← P1(Wj−16 ⊕ Wj−9 ⊕ (Wj−3 ≪ 15)) ⊕ (Wj−13 ≪ 7) ⊕ Wj−6
+/// ENDFOR
+/// ```
+///
+/// According to RISC-V Cryptography Extensions, Volume I, the execution latency of
+/// this instruction must always be independent from the data it operates on.
+#[inline]
+pub fn sm3p1(x: u32) -> u32 {
+ let ans: u32;
+ unsafe {
+ // asm!("sm3p1 {}, {}", out(reg) ans, in(reg) x, options(nomem, nostack))
+ asm!(".insn i 0x13, 0x1, {}, {}, 0x109", out(reg) ans, in(reg) x, options(nomem, nostack))
+ };
+ ans
+}
+
+/// Accelerates the round function `F` in the SM4 block cipher algorithm
+///
+/// This instruction is included in extension `Zksed`. It's defined as:
+///
+/// ```text
+/// SM4ED(x, a, BS) = x ⊕ T(ai)
+/// ... where
+/// ai = a.bytes[BS]
+/// T(ai) = L(τ(ai))
+/// bi = τ(ai) = SM4-S-Box(ai)
+/// ci = L(bi) = bi ⊕ (bi ≪ 2) ⊕ (bi ≪ 10) ⊕ (bi ≪ 18) ⊕ (bi ≪ 24)
+/// SM4ED = (ci ≪ (BS * 8)) ⊕ x
+/// ```
+///
+/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
+/// As is defined above, `T` is a combined transformation of non linear S-Box transform `τ`
+/// and linear layer transform `L`.
+///
+/// In the SM4 algorithm, the round function `F` is defined as:
+///
+/// ```text
+/// F(x0, x1, x2, x3, rk) = x0 ⊕ T(x1 ⊕ x2 ⊕ x3 ⊕ rk)
+/// ... where
+/// T(A) = L(τ(A))
+/// B = τ(A) = (SM4-S-Box(a0), SM4-S-Box(a1), SM4-S-Box(a2), SM4-S-Box(a3))
+/// C = L(B) = B ⊕ (B ≪ 2) ⊕ (B ≪ 10) ⊕ (B ≪ 18) ⊕ (B ≪ 24)
+/// ```
+///
+/// It can be implemented by `sm4ed` instruction like:
+///
+/// ```no_run
+/// let a = x1 ^ x2 ^ x3 ^ rk;
+/// let c0 = sm4ed::<0>(x0, a);
+/// let c1 = sm4ed::<1>(c0, a); // c1 represents c[0..=1], etc.
+/// let c2 = sm4ed::<2>(c1, a);
+/// let c3 = sm4ed::<3>(c2, a);
+/// return c3; // c3 represents c[0..=3]
+/// ```
+///
+/// According to RISC-V Cryptography Extensions, Volume I, the execution latency of
+/// this instruction must always be independent from the data it operates on.
+pub fn sm4ed<const BS: u8>(x: u32, a: u32) -> u32 {
+ static_assert!(BS: u8 where BS <= 3);
+ let ans: u32;
+ match BS {
+ 0 => unsafe {
+ asm!(".insn r 0x33, 0, 0x18, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) a, options(nomem, nostack))
+ },
+ 1 => unsafe {
+ asm!(".insn r 0x33, 0, 0x38, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) a, options(nomem, nostack))
+ },
+ 2 => unsafe {
+ asm!(".insn r 0x33, 0, 0x58, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) a, options(nomem, nostack))
+ },
+ 3 => unsafe {
+ asm!(".insn r 0x33, 0, 0x78, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) a, options(nomem, nostack))
+ },
+ _ => unreachable!(),
+ };
+ ans
+}
+
+/// Accelerates the key schedule operation in the SM4 block cipher algorithm
+///
+/// This instruction is included in extension `Zksed`. It's defined as:
+///
+/// ```text
+/// SM4KS(x, k, BS) = x ⊕ T'(ki)
+/// ... where
+/// ki = k.bytes[BS]
+/// T'(ki) = L'(τ(ki))
+/// bi = τ(ki) = SM4-S-Box(ki)
+/// ci = L'(bi) = bi ⊕ (bi ≪ 13) ⊕ (bi ≪ 23)
+/// SM4KS = (ci ≪ (BS * 8)) ⊕ x
+/// ```
+///
+/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
+/// As is defined above, `T'` is a combined transformation of non linear S-Box transform `τ`
+/// and the replaced linear layer transform `L'`.
+///
+/// In the SM4 algorithm, the key schedule is defined as:
+///
+/// ```text
+/// rk[i] = K[i+4] = K[i] ⊕ T'(K[i+1] ⊕ K[i+2] ⊕ K[i+3] ⊕ CK[i])
+/// ... where
+/// K[0..=3] = MK[0..=3] ⊕ FK[0..=3]
+/// T'(K) = L'(τ(K))
+/// B = τ(K) = (SM4-S-Box(k0), SM4-S-Box(k1), SM4-S-Box(k2), SM4-S-Box(k3))
+/// C = L'(B) = B ⊕ (B ≪ 13) ⊕ (B ≪ 23)
+/// ```
+///
+/// where `MK` represents the input 128-bit encryption key,
+/// constants `FK` and `CK` are fixed system configuration constant values defined by the SM4 algorithm.
+/// Hence, the key schedule operation can be implemented by `sm4ks` instruction like:
+///
+/// ```no_run
+/// let k = k1 ^ k2 ^ k3 ^ ck_i;
+/// let c0 = sm4ks::<0>(k0, k);
+/// let c1 = sm4ks::<1>(c0, k); // c1 represents c[0..=1], etc.
+/// let c2 = sm4ks::<2>(c1, k);
+/// let c3 = sm4ks::<3>(c2, k);
+/// return c3; // c3 represents c[0..=3]
+/// ```
+///
+/// According to RISC-V Cryptography Extensions, Volume I, the execution latency of
+/// this instruction must always be independent from the data it operates on.
+pub fn sm4ks<const BS: u8>(x: u32, k: u32) -> u32 {
+ static_assert!(BS: u8 where BS <= 3);
+ let ans: u32;
+ match BS {
+ 0 => unsafe {
+ asm!(".insn r 0x33, 0, 0x1A, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) k, options(nomem, nostack))
+ },
+ 1 => unsafe {
+ asm!(".insn r 0x33, 0, 0x3A, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) k, options(nomem, nostack))
+ },
+ 2 => unsafe {
+ asm!(".insn r 0x33, 0, 0x5A, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) k, options(nomem, nostack))
+ },
+ 3 => unsafe {
+ asm!(".insn r 0x33, 0, 0x7A, {}, {}, {}", out(reg) ans, in(reg) x, in(reg) k, options(nomem, nostack))
+ },
+ _ => unreachable!(),
+ };
+ ans
+}
diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs
index 97c6f6c..f70a284 100644
--- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs
+++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs
@@ -16156,6 +16156,126 @@
transmute(vcompresspd128(a.as_f64x2(), _mm_setzero_pd().as_f64x2(), k))
}
+/// Contiguously store the active 32-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f")]
+#[cfg_attr(test, assert_instr(vpcompressd))]
+pub unsafe fn _mm512_mask_compressstoreu_epi32(base_addr: *mut u8, k: __mmask16, a: __m512i) {
+ vcompressstored(base_addr as *mut _, a.as_i32x16(), k)
+}
+
+/// Contiguously store the active 32-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_compressstoreu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressd))]
+pub unsafe fn _mm256_mask_compressstoreu_epi32(base_addr: *mut u8, k: __mmask8, a: __m256i) {
+ vcompressstored256(base_addr as *mut _, a.as_i32x8(), k)
+}
+
+/// Contiguously store the active 32-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_compressstoreu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressd))]
+pub unsafe fn _mm_mask_compressstoreu_epi32(base_addr: *mut u8, k: __mmask8, a: __m128i) {
+ vcompressstored128(base_addr as *mut _, a.as_i32x4(), k)
+}
+
+/// Contiguously store the active 64-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f")]
+#[cfg_attr(test, assert_instr(vpcompressq))]
+pub unsafe fn _mm512_mask_compressstoreu_epi64(base_addr: *mut u8, k: __mmask8, a: __m512i) {
+ vcompressstoreq(base_addr as *mut _, a.as_i64x8(), k)
+}
+
+/// Contiguously store the active 64-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_compressstoreu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressq))]
+pub unsafe fn _mm256_mask_compressstoreu_epi64(base_addr: *mut u8, k: __mmask8, a: __m256i) {
+ vcompressstoreq256(base_addr as *mut _, a.as_i64x4(), k)
+}
+
+/// Contiguously store the active 64-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_compressstoreu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressq))]
+pub unsafe fn _mm_mask_compressstoreu_epi64(base_addr: *mut u8, k: __mmask8, a: __m128i) {
+ vcompressstoreq128(base_addr as *mut _, a.as_i64x2(), k)
+}
+
+/// Contiguously store the active single-precision (32-bit) floating-point elements in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_ps)
+#[inline]
+#[target_feature(enable = "avx512f")]
+#[cfg_attr(test, assert_instr(vcompressps))]
+pub unsafe fn _mm512_mask_compressstoreu_ps(base_addr: *mut u8, k: __mmask16, a: __m512) {
+ vcompressstoreps(base_addr as *mut _, a.as_f32x16(), k)
+}
+
+/// Contiguously store the active single-precision (32-bit) floating-point elements in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_compressstoreu_ps)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vcompressps))]
+pub unsafe fn _mm256_mask_compressstoreu_ps(base_addr: *mut u8, k: __mmask8, a: __m256) {
+ vcompressstoreps256(base_addr as *mut _, a.as_f32x8(), k)
+}
+
+/// Contiguously store the active single-precision (32-bit) floating-point elements in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_compressstoreu_ps)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vcompressps))]
+pub unsafe fn _mm_mask_compressstoreu_ps(base_addr: *mut u8, k: __mmask8, a: __m128) {
+ vcompressstoreps128(base_addr as *mut _, a.as_f32x4(), k)
+}
+
+/// Contiguously store the active double-precision (64-bit) floating-point elements in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_pd)
+#[inline]
+#[target_feature(enable = "avx512f")]
+#[cfg_attr(test, assert_instr(vcompresspd))]
+pub unsafe fn _mm512_mask_compressstoreu_pd(base_addr: *mut u8, k: __mmask8, a: __m512d) {
+ vcompressstorepd(base_addr as *mut _, a.as_f64x8(), k)
+}
+
+/// Contiguously store the active double-precision (64-bit) floating-point elements in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_compressstoreu_pd)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vcompresspd))]
+pub unsafe fn _mm256_mask_compressstoreu_pd(base_addr: *mut u8, k: __mmask8, a: __m256d) {
+ vcompressstorepd256(base_addr as *mut _, a.as_f64x4(), k)
+}
+
+/// Contiguously store the active double-precision (64-bit) floating-point elements in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_compressstoreu_pd)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl")]
+#[cfg_attr(test, assert_instr(vcompresspd))]
+pub unsafe fn _mm_mask_compressstoreu_pd(base_addr: *mut u8, k: __mmask8, a: __m128d) {
+ vcompressstorepd128(base_addr as *mut _, a.as_f64x2(), k)
+}
+
/// Load contiguous active 32-bit integers from a (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi32&expand=2316)
@@ -31651,6 +31771,450 @@
);
}
+/// Load contiguous active 32-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_mask_expandloadu_epi32(
+ src: __m512i,
+ k: __mmask16,
+ mem_addr: *const i32,
+) -> __m512i {
+ let mut dst: __m512i = src;
+ asm!(
+ vpl!("vpexpandd {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 32-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_maskz_expandloadu_epi32(k: __mmask16, mem_addr: *const i32) -> __m512i {
+ let mut dst: __m512i;
+ asm!(
+ vpl!("vpexpandd {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 32-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_expandloadu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_mask_expandloadu_epi32(
+ src: __m256i,
+ k: __mmask8,
+ mem_addr: *const i32,
+) -> __m256i {
+ let mut dst: __m256i = src;
+ asm!(
+ vpl!("vpexpandd {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 32-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_expandloadu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_maskz_expandloadu_epi32(k: __mmask8, mem_addr: *const i32) -> __m256i {
+ let mut dst: __m256i;
+ asm!(
+ vpl!("vpexpandd {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 32-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_expandloadu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_mask_expandloadu_epi32(
+ src: __m128i,
+ k: __mmask8,
+ mem_addr: *const i32,
+) -> __m128i {
+ let mut dst: __m128i = src;
+ asm!(
+ vpl!("vpexpandd {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 32-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_expandloadu_epi32)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_maskz_expandloadu_epi32(k: __mmask8, mem_addr: *const i32) -> __m128i {
+ let mut dst: __m128i;
+ asm!(
+ vpl!("vpexpandd {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 64-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_mask_expandloadu_epi64(
+ src: __m512i,
+ k: __mmask8,
+ mem_addr: *const i64,
+) -> __m512i {
+ let mut dst: __m512i = src;
+ asm!(
+ vpl!("vpexpandq {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 64-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_maskz_expandloadu_epi64(k: __mmask8, mem_addr: *const i64) -> __m512i {
+ let mut dst: __m512i;
+ asm!(
+ vpl!("vpexpandq {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 64-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_expandloadu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_mask_expandloadu_epi64(
+ src: __m256i,
+ k: __mmask8,
+ mem_addr: *const i64,
+) -> __m256i {
+ let mut dst: __m256i = src;
+ asm!(
+ vpl!("vpexpandq {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 64-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_expandloadu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_maskz_expandloadu_epi64(k: __mmask8, mem_addr: *const i64) -> __m256i {
+ let mut dst: __m256i;
+ asm!(
+ vpl!("vpexpandq {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 64-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_expandloadu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_mask_expandloadu_epi64(
+ src: __m128i,
+ k: __mmask8,
+ mem_addr: *const i64,
+) -> __m128i {
+ let mut dst: __m128i = src;
+ asm!(
+ vpl!("vpexpandq {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 64-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_expandloadu_epi64)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_maskz_expandloadu_epi64(k: __mmask8, mem_addr: *const i64) -> __m128i {
+ let mut dst: __m128i;
+ asm!(
+ vpl!("vpexpandq {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (32-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_ps)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_mask_expandloadu_ps(
+ src: __m512,
+ k: __mmask16,
+ mem_addr: *const f32,
+) -> __m512 {
+ let mut dst: __m512 = src;
+ asm!(
+ vpl!("vexpandps {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (32-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_ps)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_maskz_expandloadu_ps(k: __mmask16, mem_addr: *const f32) -> __m512 {
+ let mut dst: __m512;
+ asm!(
+ vpl!("vexpandps {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (32-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_expandloadu_ps)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_mask_expandloadu_ps(src: __m256, k: __mmask8, mem_addr: *const f32) -> __m256 {
+ let mut dst: __m256 = src;
+ asm!(
+ vpl!("vexpandps {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (32-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_expandloadu_ps)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_maskz_expandloadu_ps(k: __mmask8, mem_addr: *const f32) -> __m256 {
+ let mut dst: __m256;
+ asm!(
+ vpl!("vexpandps {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (32-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_expandloadu_ps)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_mask_expandloadu_ps(src: __m128, k: __mmask8, mem_addr: *const f32) -> __m128 {
+ let mut dst: __m128 = src;
+ asm!(
+ vpl!("vexpandps {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (32-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_expandloadu_ps)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_maskz_expandloadu_ps(k: __mmask8, mem_addr: *const f32) -> __m128 {
+ let mut dst: __m128;
+ asm!(
+ vpl!("vexpandps {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (64-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_pd)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_mask_expandloadu_pd(
+ src: __m512d,
+ k: __mmask8,
+ mem_addr: *const f64,
+) -> __m512d {
+ let mut dst: __m512d = src;
+ asm!(
+ vpl!("vexpandpd {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (64-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_pd)
+#[inline]
+#[target_feature(enable = "avx512f")]
+pub unsafe fn _mm512_maskz_expandloadu_pd(k: __mmask8, mem_addr: *const f64) -> __m512d {
+ let mut dst: __m512d;
+ asm!(
+ vpl!("vexpandpd {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (64-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_expandloadu_pd)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_mask_expandloadu_pd(
+ src: __m256d,
+ k: __mmask8,
+ mem_addr: *const f64,
+) -> __m256d {
+ let mut dst: __m256d = src;
+ asm!(
+ vpl!("vexpandpd {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (64-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_expandloadu_pd)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx")]
+pub unsafe fn _mm256_maskz_expandloadu_pd(k: __mmask8, mem_addr: *const f64) -> __m256d {
+ let mut dst: __m256d;
+ asm!(
+ vpl!("vexpandpd {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (64-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_expandloadu_pd)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_mask_expandloadu_pd(src: __m128d, k: __mmask8, mem_addr: *const f64) -> __m128d {
+ let mut dst: __m128d = src;
+ asm!(
+ vpl!("vexpandpd {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active single-precision (64-bit) floating-point elements from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_expandloadu_pd)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vl,avx,sse")]
+pub unsafe fn _mm_maskz_expandloadu_pd(k: __mmask8, mem_addr: *const f64) -> __m128d {
+ let mut dst: __m128d;
+ asm!(
+ vpl!("vexpandpd {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
/// Set packed double-precision (64-bit) floating-point elements in dst with the supplied values in reverse order.
///
/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_pd&expand=5002)
@@ -38007,6 +38571,34 @@
#[link_name = "llvm.x86.avx512.mask.compress.pd.128"]
fn vcompresspd128(a: f64x2, src: f64x2, mask: u8) -> f64x2;
+ #[link_name = "llvm.x86.avx512.mask.compress.store.d.512"]
+ fn vcompressstored(mem: *mut i8, data: i32x16, mask: u16);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.d.256"]
+ fn vcompressstored256(mem: *mut i8, data: i32x8, mask: u8);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.d.128"]
+ fn vcompressstored128(mem: *mut i8, data: i32x4, mask: u8);
+
+ #[link_name = "llvm.x86.avx512.mask.compress.store.q.512"]
+ fn vcompressstoreq(mem: *mut i8, data: i64x8, mask: u8);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.q.256"]
+ fn vcompressstoreq256(mem: *mut i8, data: i64x4, mask: u8);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.q.128"]
+ fn vcompressstoreq128(mem: *mut i8, data: i64x2, mask: u8);
+
+ #[link_name = "llvm.x86.avx512.mask.compress.store.ps.512"]
+ fn vcompressstoreps(mem: *mut i8, data: f32x16, mask: u16);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.ps.256"]
+ fn vcompressstoreps256(mem: *mut i8, data: f32x8, mask: u8);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.ps.128"]
+ fn vcompressstoreps128(mem: *mut i8, data: f32x4, mask: u8);
+
+ #[link_name = "llvm.x86.avx512.mask.compress.store.pd.512"]
+ fn vcompressstorepd(mem: *mut i8, data: f64x8, mask: u8);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.pd.256"]
+ fn vcompressstorepd256(mem: *mut i8, data: f64x4, mask: u8);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.pd.128"]
+ fn vcompressstorepd128(mem: *mut i8, data: f64x2, mask: u8);
+
#[link_name = "llvm.x86.avx512.mask.expand.d.512"]
fn vpexpandd(a: i32x16, src: i32x16, mask: u16) -> i32x16;
#[link_name = "llvm.x86.avx512.mask.expand.d.256"]
@@ -51358,6 +51950,138 @@
}
#[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_compressstoreu_epi32() {
+ let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+ let mut r = [0_i32; 16];
+ _mm512_mask_compressstoreu_epi32(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i32; 16]);
+ _mm512_mask_compressstoreu_epi32(r.as_mut_ptr() as *mut _, 0b1111000011001010, a);
+ assert_eq!(&r, &[2, 4, 7, 8, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0]);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_compressstoreu_epi32() {
+ let a = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8);
+ let mut r = [0_i32; 8];
+ _mm256_mask_compressstoreu_epi32(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i32; 8]);
+ _mm256_mask_compressstoreu_epi32(r.as_mut_ptr() as *mut _, 0b11001010, a);
+ assert_eq!(&r, &[2, 4, 7, 8, 0, 0, 0, 0]);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_compressstoreu_epi32() {
+ let a = _mm_setr_epi32(1, 2, 3, 4);
+ let mut r = [0_i32; 4];
+ _mm_mask_compressstoreu_epi32(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i32; 4]);
+ _mm_mask_compressstoreu_epi32(r.as_mut_ptr() as *mut _, 0b1011, a);
+ assert_eq!(&r, &[1, 2, 4, 0]);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_compressstoreu_epi64() {
+ let a = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8);
+ let mut r = [0_i64; 8];
+ _mm512_mask_compressstoreu_epi64(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i64; 8]);
+ _mm512_mask_compressstoreu_epi64(r.as_mut_ptr() as *mut _, 0b11001010, a);
+ assert_eq!(&r, &[2, 4, 7, 8, 0, 0, 0, 0]);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_compressstoreu_epi64() {
+ let a = _mm256_setr_epi64x(1, 2, 3, 4);
+ let mut r = [0_i64; 4];
+ _mm256_mask_compressstoreu_epi64(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i64; 4]);
+ _mm256_mask_compressstoreu_epi64(r.as_mut_ptr() as *mut _, 0b1011, a);
+ assert_eq!(&r, &[1, 2, 4, 0]);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_compressstoreu_epi64() {
+ let a = _mm_setr_epi64x(1, 2);
+ let mut r = [0_i64; 2];
+ _mm_mask_compressstoreu_epi64(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i64; 2]);
+ _mm_mask_compressstoreu_epi64(r.as_mut_ptr() as *mut _, 0b10, a);
+ assert_eq!(&r, &[2, 0]);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_compressstoreu_ps() {
+ let a = _mm512_setr_ps(
+ 1_f32, 2_f32, 3_f32, 4_f32, 5_f32, 6_f32, 7_f32, 8_f32, 9_f32, 10_f32, 11_f32, 12_f32,
+ 13_f32, 14_f32, 15_f32, 16_f32,
+ );
+ let mut r = [0_f32; 16];
+ _mm512_mask_compressstoreu_ps(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_f32; 16]);
+ _mm512_mask_compressstoreu_ps(r.as_mut_ptr() as *mut _, 0b1111000011001010, a);
+ assert_eq!(
+ &r,
+ &[
+ 2_f32, 4_f32, 7_f32, 8_f32, 13_f32, 14_f32, 15_f32, 16_f32, 0_f32, 0_f32, 0_f32,
+ 0_f32, 0_f32, 0_f32, 0_f32, 0_f32
+ ]
+ );
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_compressstoreu_ps() {
+ let a = _mm256_setr_ps(1_f32, 2_f32, 3_f32, 4_f32, 5_f32, 6_f32, 7_f32, 8_f32);
+ let mut r = [0_f32; 8];
+ _mm256_mask_compressstoreu_ps(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_f32; 8]);
+ _mm256_mask_compressstoreu_ps(r.as_mut_ptr() as *mut _, 0b11001010, a);
+ assert_eq!(
+ &r,
+ &[2_f32, 4_f32, 7_f32, 8_f32, 0_f32, 0_f32, 0_f32, 0_f32]
+ );
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_compressstoreu_ps() {
+ let a = _mm_setr_ps(1_f32, 2_f32, 3_f32, 4_f32);
+ let mut r = [0.; 4];
+ _mm_mask_compressstoreu_ps(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0.; 4]);
+ _mm_mask_compressstoreu_ps(r.as_mut_ptr() as *mut _, 0b1011, a);
+ assert_eq!(&r, &[1_f32, 2_f32, 4_f32, 0_f32]);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_compressstoreu_pd() {
+ let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.);
+ let mut r = [0.; 8];
+ _mm512_mask_compressstoreu_pd(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0.; 8]);
+ _mm512_mask_compressstoreu_pd(r.as_mut_ptr() as *mut _, 0b11001010, a);
+ assert_eq!(&r, &[2., 4., 7., 8., 0., 0., 0., 0.]);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_compressstoreu_pd() {
+ let a = _mm256_setr_pd(1., 2., 3., 4.);
+ let mut r = [0.; 4];
+ _mm256_mask_compressstoreu_pd(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0.; 4]);
+ _mm256_mask_compressstoreu_pd(r.as_mut_ptr() as *mut _, 0b1011, a);
+ assert_eq!(&r, &[1., 2., 4., 0.]);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_compressstoreu_pd() {
+ let a = _mm_setr_pd(1., 2.);
+ let mut r = [0.; 2];
+ _mm_mask_compressstoreu_pd(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0.; 2]);
+ _mm_mask_compressstoreu_pd(r.as_mut_ptr() as *mut _, 0b10, a);
+ assert_eq!(&r, &[2., 0.]);
+ }
+
+ #[simd_test(enable = "avx512f")]
unsafe fn test_mm512_mask_expand_epi32() {
let src = _mm512_set1_epi32(200);
let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
@@ -54843,4 +55567,264 @@
let e = _mm512_setr_pd(4., 3., 8., 7., 0., 0., 0., 0.);
assert_eq_m512d(r, e);
}
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_expandloadu_epi32() {
+ let src = _mm512_set1_epi32(42);
+ let a = &[1_i32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm512_mask_expandloadu_epi32(src, m, black_box(p));
+ let e = _mm512_set_epi32(8, 7, 6, 42, 5, 42, 42, 42, 4, 3, 42, 42, 2, 42, 1, 42);
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_maskz_expandloadu_epi32() {
+ let a = &[1_i32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm512_maskz_expandloadu_epi32(m, black_box(p));
+ let e = _mm512_set_epi32(8, 7, 6, 0, 5, 0, 0, 0, 4, 3, 0, 0, 2, 0, 1, 0);
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_expandloadu_epi32() {
+ let src = _mm256_set1_epi32(42);
+ let a = &[1_i32, 2, 3, 4, 5, 6, 7, 8];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_mask_expandloadu_epi32(src, m, black_box(p));
+ let e = _mm256_set_epi32(4, 3, 2, 42, 1, 42, 42, 42);
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_maskz_expandloadu_epi32() {
+ let a = &[1_i32, 2, 3, 4, 5, 6, 7, 8];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_maskz_expandloadu_epi32(m, black_box(p));
+ let e = _mm256_set_epi32(4, 3, 2, 0, 1, 0, 0, 0);
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_expandloadu_epi32() {
+ let src = _mm_set1_epi32(42);
+ let a = &[1_i32, 2, 3, 4];
+ let p = a.as_ptr();
+ let m = 0b11111000;
+ let r = _mm_mask_expandloadu_epi32(src, m, black_box(p));
+ let e = _mm_set_epi32(1, 42, 42, 42);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_maskz_expandloadu_epi32() {
+ let a = &[1_i32, 2, 3, 4];
+ let p = a.as_ptr();
+ let m = 0b11111000;
+ let r = _mm_maskz_expandloadu_epi32(m, black_box(p));
+ let e = _mm_set_epi32(1, 0, 0, 0);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_expandloadu_epi64() {
+ let src = _mm512_set1_epi64(42);
+ let a = &[1_i64, 2, 3, 4, 5, 6, 7, 8];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm512_mask_expandloadu_epi64(src, m, black_box(p));
+ let e = _mm512_set_epi64(4, 3, 2, 42, 1, 42, 42, 42);
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_maskz_expandloadu_epi64() {
+ let a = &[1_i64, 2, 3, 4, 5, 6, 7, 8];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm512_maskz_expandloadu_epi64(m, black_box(p));
+ let e = _mm512_set_epi64(4, 3, 2, 0, 1, 0, 0, 0);
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_expandloadu_epi64() {
+ let src = _mm256_set1_epi64x(42);
+ let a = &[1_i64, 2, 3, 4];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_mask_expandloadu_epi64(src, m, black_box(p));
+ let e = _mm256_set_epi64x(1, 42, 42, 42);
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_maskz_expandloadu_epi64() {
+ let a = &[1_i64, 2, 3, 4];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_maskz_expandloadu_epi64(m, black_box(p));
+ let e = _mm256_set_epi64x(1, 0, 0, 0);
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_expandloadu_epi64() {
+ let src = _mm_set1_epi64x(42);
+ let a = &[1_i64, 2];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_mask_expandloadu_epi64(src, m, black_box(p));
+ let e = _mm_set_epi64x(42, 42);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_maskz_expandloadu_epi64() {
+ let a = &[1_i64, 2];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_maskz_expandloadu_epi64(m, black_box(p));
+ let e = _mm_set_epi64x(0, 0);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_expandloadu_ps() {
+ let src = _mm512_set1_ps(42.);
+ let a = &[
+ 1.0f32, 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm512_mask_expandloadu_ps(src, m, black_box(p));
+ let e = _mm512_set_ps(
+ 8., 7., 6., 42., 5., 42., 42., 42., 4., 3., 42., 42., 2., 42., 1., 42.,
+ );
+ assert_eq_m512(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_maskz_expandloadu_ps() {
+ let a = &[
+ 1.0f32, 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm512_maskz_expandloadu_ps(m, black_box(p));
+ let e = _mm512_set_ps(
+ 8., 7., 6., 0., 5., 0., 0., 0., 4., 3., 0., 0., 2., 0., 1., 0.,
+ );
+ assert_eq_m512(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_expandloadu_ps() {
+ let src = _mm256_set1_ps(42.);
+ let a = &[1.0f32, 2., 3., 4., 5., 6., 7., 8.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_mask_expandloadu_ps(src, m, black_box(p));
+ let e = _mm256_set_ps(4., 3., 2., 42., 1., 42., 42., 42.);
+ assert_eq_m256(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_maskz_expandloadu_ps() {
+ let a = &[1.0f32, 2., 3., 4., 5., 6., 7., 8.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_maskz_expandloadu_ps(m, black_box(p));
+ let e = _mm256_set_ps(4., 3., 2., 0., 1., 0., 0., 0.);
+ assert_eq_m256(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_expandloadu_ps() {
+ let src = _mm_set1_ps(42.);
+ let a = &[1.0f32, 2., 3., 4.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_mask_expandloadu_ps(src, m, black_box(p));
+ let e = _mm_set_ps(1., 42., 42., 42.);
+ assert_eq_m128(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_maskz_expandloadu_ps() {
+ let a = &[1.0f32, 2., 3., 4.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_maskz_expandloadu_ps(m, black_box(p));
+ let e = _mm_set_ps(1., 0., 0., 0.);
+ assert_eq_m128(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_mask_expandloadu_pd() {
+ let src = _mm512_set1_pd(42.);
+ let a = &[1.0f64, 2., 3., 4., 5., 6., 7., 8.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm512_mask_expandloadu_pd(src, m, black_box(p));
+ let e = _mm512_set_pd(4., 3., 2., 42., 1., 42., 42., 42.);
+ assert_eq_m512d(r, e);
+ }
+
+ #[simd_test(enable = "avx512f")]
+ unsafe fn test_mm512_maskz_expandloadu_pd() {
+ let a = &[1.0f64, 2., 3., 4., 5., 6., 7., 8.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm512_maskz_expandloadu_pd(m, black_box(p));
+ let e = _mm512_set_pd(4., 3., 2., 0., 1., 0., 0., 0.);
+ assert_eq_m512d(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_mask_expandloadu_pd() {
+ let src = _mm256_set1_pd(42.);
+ let a = &[1.0f64, 2., 3., 4.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_mask_expandloadu_pd(src, m, black_box(p));
+ let e = _mm256_set_pd(1., 42., 42., 42.);
+ assert_eq_m256d(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm256_maskz_expandloadu_pd() {
+ let a = &[1.0f64, 2., 3., 4.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm256_maskz_expandloadu_pd(m, black_box(p));
+ let e = _mm256_set_pd(1., 0., 0., 0.);
+ assert_eq_m256d(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_mask_expandloadu_pd() {
+ let src = _mm_set1_pd(42.);
+ let a = &[1.0f64, 2.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_mask_expandloadu_pd(src, m, black_box(p));
+ let e = _mm_set_pd(42., 42.);
+ assert_eq_m128d(r, e);
+ }
+
+ #[simd_test(enable = "avx512f,avx512vl")]
+ unsafe fn test_mm_maskz_expandloadu_pd() {
+ let a = &[1.0f64, 2.];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_maskz_expandloadu_pd(m, black_box(p));
+ let e = _mm_set_pd(0., 0.);
+ assert_eq_m128d(r, e);
+ }
}
diff --git a/library/stdarch/crates/core_arch/src/x86/avx512vbmi2.rs b/library/stdarch/crates/core_arch/src/x86/avx512vbmi2.rs
index b7a385d..1c81840 100644
--- a/library/stdarch/crates/core_arch/src/x86/avx512vbmi2.rs
+++ b/library/stdarch/crates/core_arch/src/x86/avx512vbmi2.rs
@@ -1,8 +1,299 @@
-use crate::core_arch::{simd::*, simd_llvm::*, x86::*};
+use crate::{
+ arch::asm,
+ core_arch::{simd::*, simd_llvm::*, x86::*},
+};
#[cfg(test)]
use stdarch_test::assert_instr;
+/// Load contiguous active 16-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi16)
+#[inline]
+#[target_feature(enable = "avx512f,avx512bw,avx512vbmi2")]
+pub unsafe fn _mm512_mask_expandloadu_epi16(
+ src: __m512i,
+ k: __mmask32,
+ mem_addr: *const i16,
+) -> __m512i {
+ let mut dst: __m512i = src;
+ asm!(
+ vpl!("vpexpandw {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 16-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi16)
+#[inline]
+#[target_feature(enable = "avx512f,avx512bw,avx512vbmi2")]
+pub unsafe fn _mm512_maskz_expandloadu_epi16(k: __mmask32, mem_addr: *const i16) -> __m512i {
+ let mut dst: __m512i;
+ asm!(
+ vpl!("vpexpandw {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 16-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_expandloadu_epi16)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vbmi2,avx512vl,avx")]
+pub unsafe fn _mm256_mask_expandloadu_epi16(
+ src: __m256i,
+ k: __mmask16,
+ mem_addr: *const i16,
+) -> __m256i {
+ let mut dst: __m256i = src;
+ asm!(
+ vpl!("vpexpandw {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 16-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_expandloadu_epi16)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vbmi2,avx512vl,avx")]
+pub unsafe fn _mm256_maskz_expandloadu_epi16(k: __mmask16, mem_addr: *const i16) -> __m256i {
+ let mut dst: __m256i;
+ asm!(
+ vpl!("vpexpandw {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 16-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_expandloadu_epi16)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vbmi2,avx512vl,avx,sse")]
+pub unsafe fn _mm_mask_expandloadu_epi16(
+ src: __m128i,
+ k: __mmask8,
+ mem_addr: *const i16,
+) -> __m128i {
+ let mut dst: __m128i = src;
+ asm!(
+ vpl!("vpexpandw {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 16-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_expandloadu_epi16)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vbmi2,avx512vl,avx,sse")]
+pub unsafe fn _mm_maskz_expandloadu_epi16(k: __mmask8, mem_addr: *const i16) -> __m128i {
+ let mut dst: __m128i;
+ asm!(
+ vpl!("vpexpandw {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 8-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi8)
+#[inline]
+#[target_feature(enable = "avx512f,avx512bw,avx512vbmi2")]
+pub unsafe fn _mm512_mask_expandloadu_epi8(
+ src: __m512i,
+ k: __mmask64,
+ mem_addr: *const i8,
+) -> __m512i {
+ let mut dst: __m512i = src;
+ asm!(
+ vpl!("vpexpandb {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 8-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi8)
+#[inline]
+#[target_feature(enable = "avx512f,avx512bw,avx512vbmi2")]
+pub unsafe fn _mm512_maskz_expandloadu_epi8(k: __mmask64, mem_addr: *const i8) -> __m512i {
+ let mut dst: __m512i;
+ asm!(
+ vpl!("vpexpandb {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(zmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 8-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_expandloadu_epi8)
+#[inline]
+#[target_feature(enable = "avx512f,avx512bw,avx512vbmi2,avx512vl,avx")]
+pub unsafe fn _mm256_mask_expandloadu_epi8(
+ src: __m256i,
+ k: __mmask32,
+ mem_addr: *const i8,
+) -> __m256i {
+ let mut dst: __m256i = src;
+ asm!(
+ vpl!("vpexpandb {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 8-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_expandloadu_epi8)
+#[inline]
+#[target_feature(enable = "avx512f,avx512bw,avx512vbmi2,avx512vl,avx")]
+pub unsafe fn _mm256_maskz_expandloadu_epi8(k: __mmask32, mem_addr: *const i8) -> __m256i {
+ let mut dst: __m256i;
+ asm!(
+ vpl!("vpexpandb {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(ymm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 8-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_expandloadu_epi8)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vbmi2,avx512vl,avx,sse")]
+pub unsafe fn _mm_mask_expandloadu_epi8(
+ src: __m128i,
+ k: __mmask16,
+ mem_addr: *const i8,
+) -> __m128i {
+ let mut dst: __m128i = src;
+ asm!(
+ vpl!("vpexpandb {dst}{{{k}}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = inout(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Load contiguous active 8-bit integers from unaligned memory at mem_addr (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_expandloadu_epi8)
+#[inline]
+#[target_feature(enable = "avx512f,avx512vbmi2,avx512vl,avx,sse")]
+pub unsafe fn _mm_maskz_expandloadu_epi8(k: __mmask16, mem_addr: *const i8) -> __m128i {
+ let mut dst: __m128i;
+ asm!(
+ vpl!("vpexpandb {dst}{{{k}}} {{z}}"),
+ p = in(reg) mem_addr,
+ k = in(kreg) k,
+ dst = out(xmm_reg) dst,
+ options(pure, readonly, nostack)
+ );
+ dst
+}
+
+/// Contiguously store the active 16-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi16)
+#[inline]
+#[target_feature(enable = "avx512vbmi2")]
+#[cfg_attr(test, assert_instr(vpcompressw))]
+pub unsafe fn _mm512_mask_compressstoreu_epi16(base_addr: *mut u8, k: __mmask32, a: __m512i) {
+ vcompressstorew(base_addr as *mut _, a.as_i16x32(), k)
+}
+
+/// Contiguously store the active 16-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_compressstoreu_epi16)
+#[inline]
+#[target_feature(enable = "avx512vbmi2,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressw))]
+pub unsafe fn _mm256_mask_compressstoreu_epi16(base_addr: *mut u8, k: __mmask16, a: __m256i) {
+ vcompressstorew256(base_addr as *mut _, a.as_i16x16(), k)
+}
+
+/// Contiguously store the active 16-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_compressstoreu_epi16)
+#[inline]
+#[target_feature(enable = "avx512vbmi2,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressw))]
+pub unsafe fn _mm_mask_compressstoreu_epi16(base_addr: *mut u8, k: __mmask8, a: __m128i) {
+ vcompressstorew128(base_addr as *mut _, a.as_i16x8(), k)
+}
+
+/// Contiguously store the active 8-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi8)
+#[inline]
+#[target_feature(enable = "avx512vbmi2")]
+#[cfg_attr(test, assert_instr(vpcompressb))]
+pub unsafe fn _mm512_mask_compressstoreu_epi8(base_addr: *mut u8, k: __mmask64, a: __m512i) {
+ vcompressstoreb(base_addr as *mut _, a.as_i8x64(), k)
+}
+
+/// Contiguously store the active 8-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_compressstoreu_epi8)
+#[inline]
+#[target_feature(enable = "avx512vbmi2,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressb))]
+pub unsafe fn _mm256_mask_compressstoreu_epi8(base_addr: *mut u8, k: __mmask32, a: __m256i) {
+ vcompressstoreb256(base_addr as *mut _, a.as_i8x32(), k)
+}
+
+/// Contiguously store the active 8-bit integers in a (those with their respective bit set in writemask k) to unaligned memory at base_addr.
+///
+/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_compressstoreu_epi8)
+#[inline]
+#[target_feature(enable = "avx512vbmi2,avx512vl")]
+#[cfg_attr(test, assert_instr(vpcompressb))]
+pub unsafe fn _mm_mask_compressstoreu_epi8(base_addr: *mut u8, k: __mmask16, a: __m128i) {
+ vcompressstoreb128(base_addr as *mut _, a.as_i8x16(), k)
+}
+
/// Contiguously store the active 16-bit integers in a (those with their respective bit set in writemask k) to dst, and pass through the remaining elements from src.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi16&expand=1192)
@@ -1990,6 +2281,20 @@
#[allow(improper_ctypes)]
extern "C" {
+ #[link_name = "llvm.x86.avx512.mask.compress.store.w.512"]
+ fn vcompressstorew(mem: *mut i8, data: i16x32, mask: u32);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.w.256"]
+ fn vcompressstorew256(mem: *mut i8, data: i16x16, mask: u16);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.w.128"]
+ fn vcompressstorew128(mem: *mut i8, data: i16x8, mask: u8);
+
+ #[link_name = "llvm.x86.avx512.mask.compress.store.b.512"]
+ fn vcompressstoreb(mem: *mut i8, data: i8x64, mask: u64);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.b.256"]
+ fn vcompressstoreb256(mem: *mut i8, data: i8x32, mask: u32);
+ #[link_name = "llvm.x86.avx512.mask.compress.store.b.128"]
+ fn vcompressstoreb128(mem: *mut i8, data: i8x16, mask: u16);
+
#[link_name = "llvm.x86.avx512.mask.compress.w.512"]
fn vpcompressw(a: i16x32, src: i16x32, mask: u32) -> i16x32;
#[link_name = "llvm.x86.avx512.mask.compress.w.256"]
@@ -2063,6 +2368,7 @@
use stdarch_test::simd_test;
use crate::core_arch::x86::*;
+ use crate::hint::black_box;
#[simd_test(enable = "avx512vbmi2")]
unsafe fn test_mm512_mask_compress_epi16() {
@@ -3545,4 +3851,271 @@
let e = _mm_set1_epi16(1);
assert_eq_m128i(r, e);
}
+
+ #[simd_test(enable = "avx512vbmi2")]
+ unsafe fn test_mm512_mask_expandloadu_epi16() {
+ let src = _mm512_set1_epi16(42);
+ let a = &[
+ 1_i16, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010_11110000_00001111;
+ let r = _mm512_mask_expandloadu_epi16(src, m, black_box(p));
+ let e = _mm512_set_epi16(
+ 16, 15, 14, 42, 13, 42, 42, 42, 12, 11, 42, 42, 10, 42, 9, 42, 8, 7, 6, 5, 42, 42, 42,
+ 42, 42, 42, 42, 42, 4, 3, 2, 1,
+ );
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2")]
+ unsafe fn test_mm512_maskz_expandloadu_epi16() {
+ let a = &[
+ 1_i16, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010_11110000_00001111;
+ let r = _mm512_maskz_expandloadu_epi16(m, black_box(p));
+ let e = _mm512_set_epi16(
+ 16, 15, 14, 0, 13, 0, 0, 0, 12, 11, 0, 0, 10, 0, 9, 0, 8, 7, 6, 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 4, 3, 2, 1,
+ );
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm256_mask_expandloadu_epi16() {
+ let src = _mm256_set1_epi16(42);
+ let a = &[1_i16, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm256_mask_expandloadu_epi16(src, m, black_box(p));
+ let e = _mm256_set_epi16(8, 7, 6, 42, 5, 42, 42, 42, 4, 3, 42, 42, 2, 42, 1, 42);
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm256_maskz_expandloadu_epi16() {
+ let a = &[1_i16, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm256_maskz_expandloadu_epi16(m, black_box(p));
+ let e = _mm256_set_epi16(8, 7, 6, 0, 5, 0, 0, 0, 4, 3, 0, 0, 2, 0, 1, 0);
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm_mask_expandloadu_epi16() {
+ let src = _mm_set1_epi16(42);
+ let a = &[1_i16, 2, 3, 4, 5, 6, 7, 8];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_mask_expandloadu_epi16(src, m, black_box(p));
+ let e = _mm_set_epi16(4, 3, 2, 42, 1, 42, 42, 42);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm_maskz_expandloadu_epi16() {
+ let a = &[1_i16, 2, 3, 4, 5, 6, 7, 8];
+ let p = a.as_ptr();
+ let m = 0b11101000;
+ let r = _mm_maskz_expandloadu_epi16(m, black_box(p));
+ let e = _mm_set_epi16(4, 3, 2, 0, 1, 0, 0, 0);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2")]
+ unsafe fn test_mm512_mask_expandloadu_epi8() {
+ let src = _mm512_set1_epi8(42);
+ let a = &[
+ 1_i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010_11110000_00001111_11111111_00000000_10101010_01010101;
+ let r = _mm512_mask_expandloadu_epi8(src, m, black_box(p));
+ let e = _mm512_set_epi8(
+ 32, 31, 30, 42, 29, 42, 42, 42, 28, 27, 42, 42, 26, 42, 25, 42, 24, 23, 22, 21, 42, 42,
+ 42, 42, 42, 42, 42, 42, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 42, 42, 42, 42,
+ 42, 42, 42, 42, 8, 42, 7, 42, 6, 42, 5, 42, 42, 4, 42, 3, 42, 2, 42, 1,
+ );
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2")]
+ unsafe fn test_mm512_maskz_expandloadu_epi8() {
+ let a = &[
+ 1_i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010_11110000_00001111_11111111_00000000_10101010_01010101;
+ let r = _mm512_maskz_expandloadu_epi8(m, black_box(p));
+ let e = _mm512_set_epi8(
+ 32, 31, 30, 0, 29, 0, 0, 0, 28, 27, 0, 0, 26, 0, 25, 0, 24, 23, 22, 21, 0, 0, 0, 0, 0,
+ 0, 0, 0, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,
+ 7, 0, 6, 0, 5, 0, 0, 4, 0, 3, 0, 2, 0, 1,
+ );
+ assert_eq_m512i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm256_mask_expandloadu_epi8() {
+ let src = _mm256_set1_epi8(42);
+ let a = &[
+ 1_i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010_11110000_00001111;
+ let r = _mm256_mask_expandloadu_epi8(src, m, black_box(p));
+ let e = _mm256_set_epi8(
+ 16, 15, 14, 42, 13, 42, 42, 42, 12, 11, 42, 42, 10, 42, 9, 42, 8, 7, 6, 5, 42, 42, 42,
+ 42, 42, 42, 42, 42, 4, 3, 2, 1,
+ );
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm256_maskz_expandloadu_epi8() {
+ let a = &[
+ 1_i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ ];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010_11110000_00001111;
+ let r = _mm256_maskz_expandloadu_epi8(m, black_box(p));
+ let e = _mm256_set_epi8(
+ 16, 15, 14, 0, 13, 0, 0, 0, 12, 11, 0, 0, 10, 0, 9, 0, 8, 7, 6, 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 4, 3, 2, 1,
+ );
+ assert_eq_m256i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm_mask_expandloadu_epi8() {
+ let src = _mm_set1_epi8(42);
+ let a = &[1_i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm_mask_expandloadu_epi8(src, m, black_box(p));
+ let e = _mm_set_epi8(8, 7, 6, 42, 5, 42, 42, 42, 4, 3, 42, 42, 2, 42, 1, 42);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm_maskz_expandloadu_epi8() {
+ let a = &[1_i8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ let p = a.as_ptr();
+ let m = 0b11101000_11001010;
+ let r = _mm_maskz_expandloadu_epi8(m, black_box(p));
+ let e = _mm_set_epi8(8, 7, 6, 0, 5, 0, 0, 0, 4, 3, 0, 0, 2, 0, 1, 0);
+ assert_eq_m128i(r, e);
+ }
+
+ #[simd_test(enable = "avx512vbmi2")]
+ unsafe fn test_mm512_mask_compressstoreu_epi16() {
+ let a = _mm512_set_epi16(
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
+ );
+ let mut r = [0_i16; 32];
+ _mm512_mask_compressstoreu_epi16(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i16; 32]);
+ _mm512_mask_compressstoreu_epi16(
+ r.as_mut_ptr() as *mut _,
+ 0b11110000_11001010_11111111_00000000,
+ a,
+ );
+ assert_eq!(
+ &r,
+ &[
+ 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 23, 24, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+ ]
+ );
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm256_mask_compressstoreu_epi16() {
+ let a = _mm256_set_epi16(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
+ let mut r = [0_i16; 16];
+ _mm256_mask_compressstoreu_epi16(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i16; 16]);
+ _mm256_mask_compressstoreu_epi16(r.as_mut_ptr() as *mut _, 0b11110000_11001010, a);
+ assert_eq!(&r, &[2, 4, 7, 8, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0]);
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm_mask_compressstoreu_epi16() {
+ let a = _mm_set_epi16(8, 7, 6, 5, 4, 3, 2, 1);
+ let mut r = [0_i16; 8];
+ _mm_mask_compressstoreu_epi16(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i16; 8]);
+ _mm_mask_compressstoreu_epi16(r.as_mut_ptr() as *mut _, 0b11110000, a);
+ assert_eq!(&r, &[5, 6, 7, 8, 0, 0, 0, 0]);
+ }
+
+ #[simd_test(enable = "avx512vbmi2")]
+ unsafe fn test_mm512_mask_compressstoreu_epi8() {
+ let a = _mm512_set_epi8(
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43,
+ 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
+ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
+ );
+ let mut r = [0_i8; 64];
+ _mm512_mask_compressstoreu_epi8(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i8; 64]);
+ _mm512_mask_compressstoreu_epi8(
+ r.as_mut_ptr() as *mut _,
+ 0b11110000_11001010_11111111_00000000_10101010_01010101_11110000_00001111,
+ a,
+ );
+ assert_eq!(
+ &r,
+ &[
+ 1, 2, 3, 4, 13, 14, 15, 16, 17, 19, 21, 23, 26, 28, 30, 32, 41, 42, 43, 44, 45, 46,
+ 47, 48, 50, 52, 55, 56, 61, 62, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ ]
+ );
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm256_mask_compressstoreu_epi8() {
+ let a = _mm256_set_epi8(
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
+ );
+ let mut r = [0_i8; 32];
+ _mm256_mask_compressstoreu_epi8(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i8; 32]);
+ _mm256_mask_compressstoreu_epi8(
+ r.as_mut_ptr() as *mut _,
+ 0b11110000_11001010_11111111_00000000,
+ a,
+ );
+ assert_eq!(
+ &r,
+ &[
+ 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 23, 24, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+ ]
+ );
+ }
+
+ #[simd_test(enable = "avx512vbmi2,avx512vl")]
+ unsafe fn test_mm_mask_compressstoreu_epi8() {
+ let a = _mm_set_epi8(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
+ let mut r = [0_i8; 16];
+ _mm_mask_compressstoreu_epi8(r.as_mut_ptr() as *mut _, 0, a);
+ assert_eq!(&r, &[0_i8; 16]);
+ _mm_mask_compressstoreu_epi8(r.as_mut_ptr() as *mut _, 0b11110000_11001010, a);
+ assert_eq!(&r, &[2, 4, 7, 8, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0]);
+ }
}
diff --git a/library/stdarch/crates/core_arch/src/x86/sse42.rs b/library/stdarch/crates/core_arch/src/x86/sse42.rs
index fb3a22b..f474b06 100644
--- a/library/stdarch/crates/core_arch/src/x86/sse42.rs
+++ b/library/stdarch/crates/core_arch/src/x86/sse42.rs
@@ -520,7 +520,7 @@
}
/// Starting with the initial value in `crc`, return the accumulated
-/// CRC32 value for unsigned 8-bit integer `v`.
+/// CRC32-C value for unsigned 8-bit integer `v`.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_crc32_u8)
#[inline]
@@ -532,7 +532,7 @@
}
/// Starting with the initial value in `crc`, return the accumulated
-/// CRC32 value for unsigned 16-bit integer `v`.
+/// CRC32-C value for unsigned 16-bit integer `v`.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_crc32_u16)
#[inline]
@@ -544,7 +544,7 @@
}
/// Starting with the initial value in `crc`, return the accumulated
-/// CRC32 value for unsigned 32-bit integer `v`.
+/// CRC32-C value for unsigned 32-bit integer `v`.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_crc32_u32)
#[inline]
diff --git a/library/stdarch/crates/core_arch/src/x86_64/sse42.rs b/library/stdarch/crates/core_arch/src/x86_64/sse42.rs
index 4050732..6b5d087 100644
--- a/library/stdarch/crates/core_arch/src/x86_64/sse42.rs
+++ b/library/stdarch/crates/core_arch/src/x86_64/sse42.rs
@@ -10,7 +10,7 @@
}
/// Starting with the initial value in `crc`, return the accumulated
-/// CRC32 value for unsigned 64-bit integer `v`.
+/// CRC32-C value for unsigned 64-bit integer `v`.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_crc32_u64)
#[inline]
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs
index 2f90555..f32f961 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: aarch64;
+ @CFG: target_arch = "aarch64";
@MACRO_NAME: is_aarch64_feature_detected;
@MACRO_ATTRS:
/// This macro tests, at runtime, whether an `aarch64` feature is enabled on aarch64 platforms.
@@ -31,7 +32,8 @@
/// * `"flagm"` - FEAT_FLAGM
/// * `"ssbs"` - FEAT_SSBS
/// * `"sb"` - FEAT_SB
- /// * `"pauth"` - FEAT_PAuth
+ /// * `"paca"` - FEAT_PAuth (address authentication)
+ /// * `"pacg"` - FEAT_Pauth (generic authentication)
/// * `"dpb"` - FEAT_DPB
/// * `"dpb2"` - FEAT_DPB2
/// * `"sve2"` - FEAT_SVE2
@@ -55,7 +57,7 @@
/// * `"sm4"` - FEAT_SM3 & FEAT_SM4
///
/// [docs]: https://developer.arm.com/documentation/ddi0487/latest
- #[unstable(feature = "stdsimd", issue = "27731")]
+ #[stable(feature = "simd_aarch64", since = "1.60.0")]
@BIND_FEATURE_NAME: "asimd"; "neon";
@NO_RUNTIME_DETECTION: "ras";
@NO_RUNTIME_DETECTION: "v8.1a";
@@ -65,84 +67,86 @@
@NO_RUNTIME_DETECTION: "v8.5a";
@NO_RUNTIME_DETECTION: "v8.6a";
@NO_RUNTIME_DETECTION: "v8.7a";
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] asimd: "neon";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] asimd: "neon";
/// FEAT_AdvSIMD (Advanced SIMD/NEON)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] pmull: "pmull";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pmull: "pmull";
/// FEAT_PMULL (Polynomial Multiply)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] fp: "fp";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp: "fp";
/// FEAT_FP (Floating point support)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] fp16: "fp16";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fp16: "fp16";
/// FEAT_FP16 (Half-float support)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve: "sve";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve: "sve";
/// FEAT_SVE (Scalable Vector Extension)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] crc: "crc";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] crc: "crc";
/// FEAT_CRC32 (Cyclic Redundancy Check)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] lse: "lse";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] lse: "lse";
/// FEAT_LSE (Large System Extension - atomics)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] lse2: "lse2";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] lse2: "lse2";
/// FEAT_LSE2 (unaligned and register-pair atomics)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rdm: "rdm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rdm: "rdm";
/// FEAT_RDM (Rounding Doubling Multiply - ASIMDRDM)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rcpc: "rcpc";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rcpc: "rcpc";
/// FEAT_LRCPC (Release consistent Processor consistent)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rcpc2: "rcpc2";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rcpc2: "rcpc2";
/// FEAT_LRCPC2 (RCPC with immediate offsets)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] dotprod: "dotprod";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dotprod: "dotprod";
/// FEAT_DotProd (Vector Dot-Product - ASIMDDP)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] tme: "tme";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] tme: "tme";
/// FEAT_TME (Transactional Memory Extensions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] fhm: "fhm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fhm: "fhm";
/// FEAT_FHM (fp16 multiplication instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] dit: "dit";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dit: "dit";
/// FEAT_DIT (Data Independent Timing instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] flagm: "flagm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] flagm: "flagm";
/// FEAT_FLAGM (flag manipulation instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] ssbs: "ssbs";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] ssbs: "ssbs";
/// FEAT_SSBS (speculative store bypass safe)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sb: "sb";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sb: "sb";
/// FEAT_SB (speculation barrier)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] pauth: "pauth";
- /// FEAT_PAuth (pointer authentication)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] dpb: "dpb";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] paca: "paca";
+ /// FEAT_PAuth (address authentication)
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] pacg: "pacg";
+ /// FEAT_PAuth (generic authentication)
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dpb: "dpb";
/// FEAT_DPB (aka dcpop - data cache clean to point of persistence)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] dpb2: "dpb2";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] dpb2: "dpb2";
/// FEAT_DPB2 (aka dcpodp - data cache clean to point of deep persistence)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve2: "sve2";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2: "sve2";
/// FEAT_SVE2 (Scalable Vector Extension 2)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve2_aes: "sve2-aes";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_aes: "sve2-aes";
/// FEAT_SVE_AES (SVE2 AES crypto)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve2_sm4: "sve2-sm4";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_sm4: "sve2-sm4";
/// FEAT_SVE_SM4 (SVE2 SM4 crypto)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve2_sha3: "sve2-sha3";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_sha3: "sve2-sha3";
/// FEAT_SVE_SHA3 (SVE2 SHA3 crypto)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve2_bitperm: "sve2-bitperm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sve2_bitperm: "sve2-bitperm";
/// FEAT_SVE_BitPerm (SVE2 bit permutation instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] frintts: "frintts";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] frintts: "frintts";
/// FEAT_FRINTTS (float to integer rounding instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] i8mm: "i8mm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] i8mm: "i8mm";
/// FEAT_I8MM (integer matrix multiplication, plus ASIMD support)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] f32mm: "f32mm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] f32mm: "f32mm";
/// FEAT_F32MM (single-precision matrix multiplication)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] f64mm: "f64mm";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] f64mm: "f64mm";
/// FEAT_F64MM (double-precision matrix multiplication)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] bf16: "bf16";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] bf16: "bf16";
/// FEAT_BF16 (BFloat16 type, plus MM instructions, plus ASIMD support)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rand: "rand";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] rand: "rand";
/// FEAT_RNG (Random Number Generator)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] bti: "bti";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] bti: "bti";
/// FEAT_BTI (Branch Target Identification)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] mte: "mte";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] mte: "mte";
/// FEAT_MTE (Memory Tagging Extension)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] jsconv: "jsconv";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] jsconv: "jsconv";
/// FEAT_JSCVT (JavaScript float conversion instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] fcma: "fcma";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] fcma: "fcma";
/// FEAT_FCMA (float complex number operations)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] aes: "aes";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] aes: "aes";
/// FEAT_AES (AES instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sha2: "sha2";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sha2: "sha2";
/// FEAT_SHA1 & FEAT_SHA256 (SHA1 & SHA2-256 instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sha3: "sha3";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sha3: "sha3";
/// FEAT_SHA512 & FEAT_SHA3 (SHA2-512 & SHA3 instructions)
- @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sm4: "sm4";
+ @FEATURE: #[stable(feature = "simd_aarch64", since = "1.60.0")] sm4: "sm4";
/// FEAT_SM3 & FEAT_SM4 (SM3 & SM4 instructions)
}
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/arm.rs b/library/stdarch/crates/std_detect/src/detect/arch/arm.rs
index 9e7dda0..897dc31 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/arm.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/arm.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: arm;
+ @CFG: target_arch = "arm";
@MACRO_NAME: is_arm_feature_detected;
@MACRO_ATTRS:
/// Checks if `arm` feature is enabled.
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mips.rs b/library/stdarch/crates/std_detect/src/detect/arch/mips.rs
index ada81b8..ae27d00 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/mips.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/mips.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: mips;
+ @CFG: target_arch = "mips";
@MACRO_NAME: is_mips_feature_detected;
@MACRO_ATTRS:
/// Checks if `mips` feature is enabled.
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs b/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs
index 6a0bb15..7182ec2 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: mips64;
+ @CFG: target_arch = "mips64";
@MACRO_NAME: is_mips64_feature_detected;
@MACRO_ATTRS:
/// Checks if `mips64` feature is enabled.
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mod.rs b/library/stdarch/crates/std_detect/src/detect/arch/mod.rs
new file mode 100644
index 0000000..81a1f23
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/arch/mod.rs
@@ -0,0 +1,56 @@
+#![allow(dead_code)]
+
+use cfg_if::cfg_if;
+
+// Export the macros for all supported architectures.
+#[macro_use]
+mod x86;
+#[macro_use]
+mod arm;
+#[macro_use]
+mod aarch64;
+#[macro_use]
+mod riscv;
+#[macro_use]
+mod powerpc;
+#[macro_use]
+mod powerpc64;
+#[macro_use]
+mod mips;
+#[macro_use]
+mod mips64;
+
+cfg_if! {
+ if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+ pub use x86::*;
+ } else if #[cfg(target_arch = "arm")] {
+ pub use arm::*;
+ } else if #[cfg(target_arch = "aarch64")] {
+ pub use aarch64::*;
+ } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
+ pub use riscv::*;
+ } else if #[cfg(target_arch = "powerpc")] {
+ pub use powerpc::*;
+ } else if #[cfg(target_arch = "powerpc64")] {
+ pub use powerpc64::*;
+ } else if #[cfg(target_arch = "mips")] {
+ pub use mips::*;
+ } else if #[cfg(target_arch = "mips64")] {
+ pub use mips64::*;
+ } else {
+ // Unimplemented architecture:
+ #[doc(hidden)]
+ pub(crate) enum Feature {
+ Null
+ }
+ #[doc(hidden)]
+ pub mod __is_feature_detected {}
+
+ impl Feature {
+ #[doc(hidden)]
+ pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
+ #[doc(hidden)]
+ pub(crate) fn to_str(self) -> &'static str { "" }
+ }
+ }
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs b/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs
index 44bd7f3..d135cd9 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: powerpc;
+ @CFG: target_arch = "powerpc";
@MACRO_NAME: is_powerpc_feature_detected;
@MACRO_ATTRS:
/// Checks if `powerpc` feature is enabled.
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs b/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs
index 17e4d95..773afd6 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: powerpc64;
+ @CFG: target_arch = "powerpc64";
@MACRO_NAME: is_powerpc64_feature_detected;
@MACRO_ATTRS:
/// Checks if `powerpc` feature is enabled.
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs b/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs
index ac43b2c..5ea36e7 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/riscv.rs
@@ -2,6 +2,7 @@
features! {
@TARGET: riscv;
+ @CFG: any(target_arch = "riscv32", target_arch = "riscv64");
@MACRO_NAME: is_riscv_feature_detected;
@MACRO_ATTRS:
/// A macro to test at *runtime* whether instruction sets are available on
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/x86.rs b/library/stdarch/crates/std_detect/src/detect/arch/x86.rs
index 22dbb98..893e1a8 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/x86.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/x86.rs
@@ -17,6 +17,7 @@
features! {
@TARGET: x86;
+ @CFG: any(target_arch = "x86", target_arch = "x86_64");
@MACRO_NAME: is_x86_feature_detected;
@MACRO_ATTRS:
/// A macro to test at *runtime* whether a CPU feature is available on
diff --git a/library/stdarch/crates/std_detect/src/detect/error_macros.rs b/library/stdarch/crates/std_detect/src/detect/error_macros.rs
deleted file mode 100644
index 1e70da4..0000000
--- a/library/stdarch/crates/std_detect/src/detect/error_macros.rs
+++ /dev/null
@@ -1,171 +0,0 @@
-//! The `is_{target_arch}_feature_detected!` macro are only available on their
-//! architecture. These macros provide a better error messages when the user
-//! attempts to call them in a different architecture.
-
-/// Prevents compilation if `is_x86_feature_detected` is used somewhere
-/// else than `x86` and `x86_64` targets.
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_x86_feature_detected {
- ($t: tt) => {
- compile_error!(
- r#"
- is_x86_feature_detected can only be used on x86 and x86_64 targets.
- You can prevent it from being used in other architectures by
- guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
- if is_x86_feature_detected(...) { ... }
- }
- "#
- )
- };
-}
-
-/// Prevents compilation if `is_arm_feature_detected` is used somewhere else
-/// than `ARM` targets.
-#[cfg(not(target_arch = "arm"))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_arm_feature_detected {
- ($t:tt) => {
- compile_error!(
- r#"
- is_arm_feature_detected can only be used on ARM targets.
- You can prevent it from being used in other architectures by
- guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(target_arch = "arm")] {
- if is_arm_feature_detected(...) { ... }
- }
- "#
- )
- };
-}
-
-/// Prevents compilation if `is_aarch64_feature_detected` is used somewhere else
-/// than `aarch64` targets.
-#[cfg(not(target_arch = "aarch64"))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_aarch64_feature_detected {
- ($t: tt) => {
- compile_error!(
- r#"
- is_aarch64_feature_detected can only be used on AArch64 targets.
- You can prevent it from being used in other architectures by
- guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(target_arch = "aarch64")] {
- if is_aarch64_feature_detected(...) { ... }
- }
- "#
- )
- };
-}
-
-/// Prevents compilation if `is_riscv_feature_detected` is used somewhere else
-/// than `riscv32` or `riscv64` targets.
-#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_riscv_feature_detected {
- ($t: tt) => {
- compile_error!(
- r#"
- is_riscv_feature_detected can only be used on RISC-V targets.
- You can prevent it from being used in other architectures by
- guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
- if is_riscv_feature_detected(...) { ... }
- }
- "#
- )
- };
-}
-
-/// Prevents compilation if `is_powerpc_feature_detected` is used somewhere else
-/// than `PowerPC` targets.
-#[cfg(not(target_arch = "powerpc"))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_powerpc_feature_detected {
- ($t:tt) => {
- compile_error!(
- r#"
-is_powerpc_feature_detected can only be used on PowerPC targets.
-You can prevent it from being used in other architectures by
-guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(target_arch = "powerpc")] {
- if is_powerpc_feature_detected(...) { ... }
- }
-"#
- )
- };
-}
-
-/// Prevents compilation if `is_powerpc64_feature_detected` is used somewhere
-/// else than `PowerPC64` targets.
-#[cfg(not(target_arch = "powerpc64"))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_powerpc64_feature_detected {
- ($t:tt) => {
- compile_error!(
- r#"
-is_powerpc64_feature_detected can only be used on PowerPC64 targets.
-You can prevent it from being used in other architectures by
-guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(target_arch = "powerpc64")] {
- if is_powerpc64_feature_detected(...) { ... }
- }
-"#
- )
- };
-}
-
-/// Prevents compilation if `is_mips_feature_detected` is used somewhere else
-/// than `MIPS` targets.
-#[cfg(not(target_arch = "mips"))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_mips_feature_detected {
- ($t:tt) => {
- compile_error!(
- r#"
- is_mips_feature_detected can only be used on MIPS targets.
- You can prevent it from being used in other architectures by
- guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(target_arch = "mips")] {
- if is_mips_feature_detected(...) { ... }
- }
- "#
- )
- };
-}
-
-/// Prevents compilation if `is_mips64_feature_detected` is used somewhere else
-/// than `MIPS64` targets.
-#[cfg(not(target_arch = "mips64"))]
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-macro_rules! is_mips64_feature_detected {
- ($t:tt) => {
- compile_error!(
- r#"
- is_mips64_feature_detected can only be used on MIPS64 targets.
- You can prevent it from being used in other architectures by
- guarding it behind a cfg(target_arch) as follows:
-
- #[cfg(target_arch = "mips64")] {
- if is_mips64_feature_detected(...) { ... }
- }
- "#
- )
- };
-}
diff --git a/library/stdarch/crates/std_detect/src/detect/macros.rs b/library/stdarch/crates/std_detect/src/detect/macros.rs
index b83fe71..fa71893 100644
--- a/library/stdarch/crates/std_detect/src/detect/macros.rs
+++ b/library/stdarch/crates/std_detect/src/detect/macros.rs
@@ -2,6 +2,7 @@
macro_rules! features {
(
@TARGET: $target:ident;
+ @CFG: $cfg:meta;
@MACRO_NAME: $macro_name:ident;
@MACRO_ATTRS: $(#[$macro_attrs:meta])*
$(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; )*
@@ -11,6 +12,8 @@
#[macro_export]
$(#[$macro_attrs])*
#[allow_internal_unstable(stdsimd_internal)]
+ #[cfg($cfg)]
+ #[doc(cfg($cfg))]
macro_rules! $macro_name {
$(
($feature_lit) => {
@@ -44,6 +47,50 @@
};
}
+ $(#[$macro_attrs])*
+ #[macro_export]
+ #[cfg(not($cfg))]
+ #[doc(cfg($cfg))]
+ macro_rules! $macro_name {
+ $(
+ ($feature_lit) => {
+ compile_error!(
+ concat!(
+ r#"This macro cannot be used on the current target.
+ You can prevent it from being used in other architectures by
+ guarding it behind a cfg("#,
+ stringify!($cfg),
+ ")."
+ )
+ )
+ };
+ )*
+ $(
+ ($bind_feature) => { $macro_name!($feature_impl) };
+ )*
+ $(
+ ($nort_feature) => {
+ compile_error!(
+ concat!(
+ stringify!($nort_feature),
+ " feature cannot be detected at run-time"
+ )
+ )
+ };
+ )*
+ ($t:tt,) => {
+ $macro_name!($t);
+ };
+ ($t:tt) => {
+ compile_error!(
+ concat!(
+ concat!("unknown ", stringify!($target)),
+ concat!(" target feature: ", $t)
+ )
+ )
+ };
+ }
+
/// Each variant denotes a position in a bitset for a particular feature.
///
/// PLEASE: do not use this, it is an implementation detail subject
@@ -53,6 +100,7 @@
#[derive(Copy, Clone)]
#[repr(u8)]
#[unstable(feature = "stdsimd_internal", issue = "none")]
+ #[cfg($cfg)]
pub(crate) enum Feature {
$(
$(#[$feature_comment])*
@@ -63,6 +111,7 @@
_last
}
+ #[cfg($cfg)]
impl Feature {
pub(crate) fn to_str(self) -> &'static str {
match self {
@@ -86,6 +135,7 @@
/// PLEASE: do not use this, it is an implementation detail subject
/// to change.
#[doc(hidden)]
+ #[cfg($cfg)]
pub mod __is_feature_detected {
$(
diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs
index e4eea72..2bca84c 100644
--- a/library/stdarch/crates/std_detect/src/detect/mod.rs
+++ b/library/stdarch/crates/std_detect/src/detect/mod.rs
@@ -20,64 +20,9 @@
use cfg_if::cfg_if;
#[macro_use]
-mod error_macros;
-
-#[macro_use]
mod macros;
-cfg_if! {
- if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
- #[path = "arch/x86.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(target_arch = "arm")] {
- #[path = "arch/arm.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(target_arch = "aarch64")] {
- #[path = "arch/aarch64.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
- #[path = "arch/riscv.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(target_arch = "powerpc")] {
- #[path = "arch/powerpc.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(target_arch = "powerpc64")] {
- #[path = "arch/powerpc64.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(target_arch = "mips")] {
- #[path = "arch/mips.rs"]
- #[macro_use]
- mod arch;
- } else if #[cfg(target_arch = "mips64")] {
- #[path = "arch/mips64.rs"]
- #[macro_use]
- mod arch;
- } else {
- // Unimplemented architecture:
- #[allow(dead_code)]
- mod arch {
- #[doc(hidden)]
- pub(crate) enum Feature {
- Null
- }
- #[doc(hidden)]
- pub mod __is_feature_detected {}
-
- impl Feature {
- #[doc(hidden)]
- pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
- #[doc(hidden)]
- pub(crate) fn to_str(self) -> &'static str { "" }
- }
- }
- }
-}
+mod arch;
// This module needs to be public because the `is_{arch}_feature_detected!`
// macros expand calls to items within it in user crates.
diff --git a/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs
index 0fd2702..169c51b 100644
--- a/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/os/aarch64.rs
@@ -87,7 +87,11 @@
);
}
+ // Check for either APA or API field
+ enable_feature(Feature::paca, bits_shift(aa64isar1, 11, 4) >= 1);
enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
+ // Check for either GPA or GPI field
+ enable_feature(Feature::pacg, bits_shift(aa64isar1, 31, 24) >= 1);
}
value
diff --git a/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs
index 4dc6362..b6a2e52 100644
--- a/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs
@@ -230,8 +230,8 @@
enable_feature(Feature::flagm, self.flagm);
enable_feature(Feature::ssbs, self.ssbs);
enable_feature(Feature::sb, self.sb);
- // FEAT_PAuth provides both paca & pacg
- enable_feature(Feature::pauth, self.paca && self.pacg);
+ enable_feature(Feature::paca, self.paca);
+ enable_feature(Feature::pacg, self.pacg);
enable_feature(Feature::dpb, self.dcpop);
enable_feature(Feature::dpb2, self.dcpodp);
enable_feature(Feature::rand, self.rng);
diff --git a/library/stdarch/crates/std_detect/src/lib.rs b/library/stdarch/crates/std_detect/src/lib.rs
index a17bd40..c0e0de0 100644
--- a/library/stdarch/crates/std_detect/src/lib.rs
+++ b/library/stdarch/crates/std_detect/src/lib.rs
@@ -18,18 +18,17 @@
#![allow(clippy::shadow_reuse)]
#![deny(clippy::missing_inline_in_public_items)]
#![cfg_attr(test, allow(unused_imports))]
-#![cfg_attr(feature = "std_detect_file_io", feature(vec_spare_capacity))]
#![no_std]
-// rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare_capacity` is unknown
-#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))]
-#[cfg(feature = "std_detect_file_io")]
-extern crate alloc;
-
#[cfg(test)]
#[macro_use]
extern crate std;
+// rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare>
+#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))]
+#[cfg(feature = "std_detect_file_io")]
+extern crate alloc;
+
#[doc(hidden)]
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod detect;
diff --git a/library/stdarch/crates/std_detect/tests/cpu-detection.rs b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
index adbe4fa..ca8bf28 100644
--- a/library/stdarch/crates/std_detect/tests/cpu-detection.rs
+++ b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
@@ -55,7 +55,8 @@
println!("flagm: {}", is_aarch64_feature_detected!("flagm"));
println!("ssbs: {}", is_aarch64_feature_detected!("ssbs"));
println!("sb: {}", is_aarch64_feature_detected!("sb"));
- println!("pauth: {}", is_aarch64_feature_detected!("pauth"));
+ println!("paca: {}", is_aarch64_feature_detected!("paca"));
+ println!("pacg: {}", is_aarch64_feature_detected!("pacg"));
println!("dpb: {}", is_aarch64_feature_detected!("dpb"));
println!("dpb2: {}", is_aarch64_feature_detected!("dpb2"));
println!("sve2: {}", is_aarch64_feature_detected!("sve2"));
diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml
index 04dab6b..2da4148 100644
--- a/library/test/Cargo.toml
+++ b/library/test/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "test"
version = "0.0.0"
-edition = "2018"
+edition = "2021"
[lib]
crate-type = ["dylib", "rlib"]
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index cb40b4e..b39701a 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -109,12 +109,10 @@
unstable-options = Allow use of experimental features",
"unstable-options",
)
- .optflagopt(
+ .optflag(
"",
"report-time",
- "Show execution time of each test. Available values:
- plain = do not colorize the execution time (default);
- colored = colorize output according to the `color` parameter value;
+ "Show execution time of each test.
Threshold values for colorized output can be configured via
`RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
@@ -125,7 +123,6 @@
is 0.5 seconds, and the critical time is 2 seconds.
Not available for --format=terse",
- "plain|colored",
)
.optflag(
"",
@@ -319,17 +316,12 @@
allow_unstable: bool,
) -> OptPartRes<Option<TestTimeOptions>> {
let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
- let colored_opt_str = matches.opt_str("report-time");
- let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time");
// If `ensure-test-time` option is provided, time output is enforced,
// so user won't be confused if any of tests will silently fail.
let options = if report_time || ensure_test_time {
- if ensure_test_time && !report_time {
- report_time_colored = true;
- }
- Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored))
+ Some(TestTimeOptions::new_from_env(ensure_test_time))
} else {
None
};
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 9c261e8..920f55a 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -47,7 +47,6 @@
pub passed: usize,
pub failed: usize,
pub ignored: usize,
- pub allowed_fail: usize,
pub filtered_out: usize,
pub measured: usize,
pub exec_time: Option<TestSuiteExecTime>,
@@ -71,7 +70,6 @@
passed: 0,
failed: 0,
ignored: 0,
- allowed_fail: 0,
filtered_out: 0,
measured: 0,
exec_time: None,
@@ -112,7 +110,6 @@
TestResult::TrFailed => "failed".to_owned(),
TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
TestResult::TrIgnored => "ignored".to_owned(),
- TestResult::TrAllowedFail => "failed (allowed)".to_owned(),
TestResult::TrBench(ref bs) => fmt_bench_samples(bs),
TestResult::TrTimedFail => "failed (time limit exceeded)".to_owned(),
},
@@ -126,7 +123,7 @@
}
fn current_test_count(&self) -> usize {
- self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
+ self.passed + self.failed + self.ignored + self.measured
}
}
@@ -191,7 +188,6 @@
st.not_failures.push((test, stdout));
}
TestResult::TrIgnored => st.ignored += 1,
- TestResult::TrAllowedFail => st.allowed_fail += 1,
TestResult::TrBench(bs) => {
st.metrics.insert_metric(
test.name.as_slice(),
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 424d3ef..c089bfc 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -124,15 +124,6 @@
self.write_event("test", desc.name.as_slice(), "ignored", exec_time, stdout, None)
}
- TestResult::TrAllowedFail => self.write_event(
- "test",
- desc.name.as_slice(),
- "allowed_failure",
- exec_time,
- stdout,
- None,
- ),
-
TestResult::TrBench(ref bs) => {
let median = bs.ns_iter_summ.median as usize;
let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
@@ -172,14 +163,12 @@
\"event\": \"{}\", \
\"passed\": {}, \
\"failed\": {}, \
- \"allowed_fail\": {}, \
\"ignored\": {}, \
\"measured\": {}, \
\"filtered_out\": {}",
if state.failed == 0 { "ok" } else { "failed" },
state.passed,
- state.failed + state.allowed_fail,
- state.allowed_fail,
+ state.failed,
state.ignored,
state.measured,
state.filtered_out,
diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs
index fa23cf2..54e9860 100644
--- a/library/test/src/formatters/junit.rs
+++ b/library/test/src/formatters/junit.rs
@@ -33,7 +33,6 @@
_shuffle_seed: Option<u64>,
) -> io::Result<()> {
// We write xml header on run start
- self.out.write_all(b"\n")?;
self.write_message("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
}
@@ -122,7 +121,7 @@
))?;
}
- TestResult::TrOk | TestResult::TrAllowedFail => {
+ TestResult::TrOk => {
self.write_message(&*format!(
"<testcase classname=\"{}\" \
name=\"{}\" time=\"{}\"/>",
@@ -138,7 +137,7 @@
self.write_message("</testsuite>")?;
self.write_message("</testsuites>")?;
- self.out.write_all(b"\n\n")?;
+ self.out.write_all(b"\n")?;
Ok(state.failed == 0)
}
diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs
index 4a03b4b..041df52 100644
--- a/library/test/src/formatters/pretty.rs
+++ b/library/test/src/formatters/pretty.rs
@@ -49,10 +49,6 @@
self.write_short_result("ignored", term::color::YELLOW)
}
- pub fn write_allowed_fail(&mut self) -> io::Result<()> {
- self.write_short_result("FAILED (allowed)", term::color::YELLOW)
- }
-
pub fn write_time_failed(&mut self) -> io::Result<()> {
self.write_short_result("FAILED (time limit exceeded)", term::color::RED)
}
@@ -102,7 +98,7 @@
if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
let time_str = format!(" <{}>", time);
- let color = if opts.colored {
+ let color = if self.use_color {
if opts.is_critical(desc, time) {
Some(term::color::RED)
} else if opts.is_warn(desc, time) {
@@ -219,7 +215,6 @@
TestResult::TrOk => self.write_ok()?,
TestResult::TrFailed | TestResult::TrFailedMsg(_) => self.write_failed()?,
TestResult::TrIgnored => self.write_ignored()?,
- TestResult::TrAllowedFail => self.write_allowed_fail()?,
TestResult::TrBench(ref bs) => {
self.write_bench()?;
self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?;
@@ -263,22 +258,10 @@
self.write_pretty("FAILED", term::color::RED)?;
}
- let s = if state.allowed_fail > 0 {
- format!(
- ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
- state.passed,
- state.failed + state.allowed_fail,
- state.allowed_fail,
- state.ignored,
- state.measured,
- state.filtered_out
- )
- } else {
- format!(
- ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
- state.passed, state.failed, state.ignored, state.measured, state.filtered_out
- )
- };
+ let s = format!(
+ ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
+ state.passed, state.failed, state.ignored, state.measured, state.filtered_out
+ );
self.write_plain(&s)?;
diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs
index 1f2c410..12aca7c 100644
--- a/library/test/src/formatters/terse.rs
+++ b/library/test/src/formatters/terse.rs
@@ -54,10 +54,6 @@
self.write_short_result("i", term::color::YELLOW)
}
- pub fn write_allowed_fail(&mut self) -> io::Result<()> {
- self.write_short_result("a", term::color::YELLOW)
- }
-
pub fn write_bench(&mut self) -> io::Result<()> {
self.write_pretty("bench", term::color::CYAN)
}
@@ -207,7 +203,6 @@
self.write_failed()
}
TestResult::TrIgnored => self.write_ignored(),
- TestResult::TrAllowedFail => self.write_allowed_fail(),
TestResult::TrBench(ref bs) => {
if self.is_multithreaded {
self.write_test_name(desc)?;
@@ -244,22 +239,10 @@
self.write_pretty("FAILED", term::color::RED)?;
}
- let s = if state.allowed_fail > 0 {
- format!(
- ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
- state.passed,
- state.failed + state.allowed_fail,
- state.allowed_fail,
- state.ignored,
- state.measured,
- state.filtered_out
- )
- } else {
- format!(
- ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
- state.passed, state.failed, state.ignored, state.measured, state.filtered_out
- )
- };
+ let s = format!(
+ ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
+ state.passed, state.failed, state.ignored, state.measured, state.filtered_out
+ );
self.write_plain(&s)?;
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index fad8309..8fc2b4e 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -20,6 +20,7 @@
#![feature(internal_output_capture)]
#![feature(staged_api)]
#![feature(termination_trait_lib)]
+#![feature(process_exitcode_placeholder)]
#![feature(test)]
#![feature(total_cmp)]
@@ -182,7 +183,7 @@
/// Tests is considered a failure. By default, invokes `report()`
/// and checks for a `0` result.
pub fn assert_test_result<T: Termination>(result: T) {
- let code = result.report();
+ let code = result.report().to_i32();
assert_eq!(
code, 0,
"the test returned a termination value with a non-zero status code ({}) \
diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs
index c5c56ca..8c216a1 100644
--- a/library/test/src/test_result.rs
+++ b/library/test/src/test_result.rs
@@ -19,7 +19,6 @@
TrFailed,
TrFailedMsg(String),
TrIgnored,
- TrAllowedFail,
TrBench(BenchSamples),
TrTimedFail,
}
@@ -42,8 +41,6 @@
if maybe_panic_str.map(|e| e.contains(msg)).unwrap_or(false) {
TestResult::TrOk
- } else if desc.allow_fail {
- TestResult::TrAllowedFail
} else if let Some(panic_str) = maybe_panic_str {
TestResult::TrFailedMsg(format!(
r#"panic did not contain expected string
@@ -64,7 +61,6 @@
(&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
TestResult::TrFailedMsg("test did not panic as expected".to_string())
}
- _ if desc.allow_fail => TestResult::TrAllowedFail,
_ => TestResult::TrFailed,
};
@@ -90,11 +86,10 @@
time_opts: &Option<time::TestTimeOptions>,
exec_time: &Option<time::TestExecTime>,
) -> TestResult {
- let result = match (desc.allow_fail, code) {
- (_, TR_OK) => TestResult::TrOk,
- (true, TR_FAILED) => TestResult::TrAllowedFail,
- (false, TR_FAILED) => TestResult::TrFailed,
- (_, _) => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+ let result = match code {
+ TR_OK => TestResult::TrOk,
+ TR_FAILED => TestResult::TrFailed,
+ _ => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
};
// If test is already failed (or allowed to fail), do not change the result.
diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs
index 7186138..d566dbc 100644
--- a/library/test/src/tests.rs
+++ b/library/test/src/tests.rs
@@ -62,10 +62,11 @@
name: StaticTestName("1"),
ignore: true,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
},
@@ -74,10 +75,11 @@
name: StaticTestName("2"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
},
@@ -94,10 +96,11 @@
name: StaticTestName("whatever"),
ignore: true,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -115,10 +118,11 @@
name: StaticTestName("whatever"),
ignore: true,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -140,10 +144,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::Yes,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -165,10 +170,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage("error message"),
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -195,10 +201,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -229,10 +236,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -255,10 +263,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -289,10 +298,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -324,10 +334,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
@@ -363,10 +374,11 @@
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type,
+ #[cfg(bootstrap)]
+ allow_fail: false,
}
}
@@ -382,7 +394,6 @@
let options = TestTimeOptions {
error_on_excess: false,
- colored: false,
unit_threshold: unit.clone(),
integration_threshold: integration.clone(),
doctest_threshold: doc.clone(),
@@ -476,10 +487,11 @@
name: StaticTestName("3"),
ignore: false,
should_panic: ShouldPanic::Yes,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
});
@@ -493,17 +505,18 @@
#[test]
pub fn exact_filter_match() {
fn tests() -> Vec<TestDescAndFn> {
- vec!["base", "base::test", "base::test1", "base::test2"]
+ ["base", "base::test", "base::test1", "base::test2"]
.into_iter()
.map(|name| TestDescAndFn {
desc: TestDesc {
name: StaticTestName(name),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
})
@@ -589,10 +602,11 @@
name: DynTestName((*name).clone()),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(testfn)),
};
@@ -740,10 +754,11 @@
name: StaticTestName("f"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
crate::bench::benchmark(TestId(0), desc, tx, true, f);
@@ -762,10 +777,11 @@
name: StaticTestName("f"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
crate::bench::benchmark(TestId(0), desc, tx, true, f);
@@ -778,20 +794,22 @@
name: StaticTestName("a"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
let test_b = TestDesc {
name: StaticTestName("b"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None);
@@ -802,7 +820,6 @@
passed: 0,
failed: 0,
ignored: 0,
- allowed_fail: 0,
filtered_out: 0,
measured: 0,
exec_time: None,
diff --git a/library/test/src/time.rs b/library/test/src/time.rs
index e0b6ead..8c64e5d 100644
--- a/library/test/src/time.rs
+++ b/library/test/src/time.rs
@@ -137,14 +137,13 @@
/// Denotes if the test critical execution time limit excess should be considered
/// a test failure.
pub error_on_excess: bool,
- pub colored: bool,
pub unit_threshold: TimeThreshold,
pub integration_threshold: TimeThreshold,
pub doctest_threshold: TimeThreshold,
}
impl TestTimeOptions {
- pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self {
+ pub fn new_from_env(error_on_excess: bool) -> Self {
let unit_threshold = TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME)
.unwrap_or_else(Self::default_unit);
@@ -155,7 +154,7 @@
let doctest_threshold = TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME)
.unwrap_or_else(Self::default_doctest);
- Self { error_on_excess, colored, unit_threshold, integration_threshold, doctest_threshold }
+ Self { error_on_excess, unit_threshold, integration_threshold, doctest_threshold }
}
pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool {
diff --git a/library/test/src/types.rs b/library/test/src/types.rs
index 37bb38f..43e5a10 100644
--- a/library/test/src/types.rs
+++ b/library/test/src/types.rs
@@ -118,10 +118,11 @@
pub name: TestName,
pub ignore: bool,
pub should_panic: options::ShouldPanic,
- pub allow_fail: bool,
pub compile_fail: bool,
pub no_run: bool,
pub test_type: TestType,
+ #[cfg(bootstrap)]
+ pub allow_fail: bool,
}
impl TestDesc {
@@ -150,9 +151,6 @@
}
options::ShouldPanic::No => {}
}
- if self.allow_fail {
- return Some("allow fail");
- }
if self.compile_fail {
return Some("compile fail");
}
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index 1941f2b..69fce8d 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -3,7 +3,7 @@
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
-edition = "2018"
+edition = "2021"
include = [
'/libunwind/*',
]
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index 5e15fe7..c8c5528 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -42,6 +42,9 @@
#[cfg(all(target_arch = "aarch64", target_pointer_width = "32"))]
pub const unwinder_private_data_size: usize = 5;
+#[cfg(target_arch = "m68k")]
+pub const unwinder_private_data_size: usize = 2;
+
#[cfg(target_arch = "mips")]
pub const unwinder_private_data_size: usize = 2;