diff --git a/Cargo.lock b/Cargo.lock index ad634e9f794a4..e4f1c4ec96a3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.152" +version = "0.1.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2153cf213eb259361567720ce55f6446f17acd0ccca87fb6dc05360578228a58" +checksum = "341e0830ca6170a4fcf02e92e57daf4b6f10142d48da32a547023867a6c8b35e" dependencies = [ "cc", "rustc-std-workspace-core", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", "compiler_builtins", diff --git a/alloc/Cargo.toml b/alloc/Cargo.toml index 1d2dd1e60819f..cedbd330cbde8 100644 --- a/alloc/Cargo.toml +++ b/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.155", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/alloc/src/alloc.rs b/alloc/src/alloc.rs index 1e03a191276ca..e1cc4ba25c4ea 100644 --- a/alloc/src/alloc.rs +++ b/alloc/src/alloc.rs @@ -16,22 +16,22 @@ unsafe extern "Rust" { // otherwise. #[rustc_allocator] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_alloc(size: usize, align: usize) -> *mut u8; #[rustc_deallocator] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_reallocator] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; #[rustc_allocator_zeroed] #[rustc_nounwind] - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] static __rust_no_alloc_shim_is_unstable: u8; } @@ -360,7 +360,7 @@ unsafe extern "Rust" { // 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. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } @@ -427,7 +427,7 @@ pub mod __alloc_error_handler { unsafe extern "Rust" { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] static __rust_alloc_error_handler_should_panic: u8; } diff --git a/alloc/src/boxed.rs b/alloc/src/boxed.rs index 4644e37f809c1..4536f55544354 100644 --- a/alloc/src/boxed.rs +++ b/alloc/src/boxed.rs @@ -952,7 +952,7 @@ impl Box, A> { /// assert_eq!(*x, i); /// } /// ``` - #[stable(feature = "box_uninit_write", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "box_uninit_write", since = "1.87.0")] #[inline] pub fn write(mut boxed: Self, value: T) -> Box { unsafe { diff --git a/alloc/src/collections/btree/set_val.rs b/alloc/src/collections/btree/set_val.rs index cf30160bfbbc2..5037b6578e80a 100644 --- a/alloc/src/collections/btree/set_val.rs +++ b/alloc/src/collections/btree/set_val.rs @@ -9,7 +9,7 @@ pub(super) struct SetValZST; /// Returns `true` only for type `SetValZST`, `false` for all other types (blanket implementation). /// `TypeId` requires a `'static` lifetime, use of this trait avoids that restriction. /// -/// [`TypeId`]: std::any::TypeId +/// [`TypeId`]: core::any::TypeId pub(super) trait IsSetVal { fn is_set_val() -> bool; } diff --git a/alloc/src/collections/linked_list.rs b/alloc/src/collections/linked_list.rs index 3183268b4b32e..cc42a120e4fa7 100644 --- a/alloc/src/collections/linked_list.rs +++ b/alloc/src/collections/linked_list.rs @@ -1151,7 +1151,7 @@ impl LinkedList { /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); /// ``` - #[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "extract_if", since = "1.87.0")] pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -1931,7 +1931,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { } /// An iterator produced by calling `extract_if` on LinkedList. -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1946,7 +1946,7 @@ pub struct ExtractIf< old_len: usize, } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -1975,7 +1975,7 @@ where } } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl fmt::Debug for ExtractIf<'_, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExtractIf").field(&self.list).finish() diff --git a/alloc/src/fmt.rs b/alloc/src/fmt.rs index e40de13f3d4a9..30f42050ac8ac 100644 --- a/alloc/src/fmt.rs +++ b/alloc/src/fmt.rs @@ -109,7 +109,7 @@ //! parameters (corresponding to `format_spec` in [the syntax](#syntax)). These //! parameters affect the string representation of what's being formatted. //! -//! The colon `:` in format syntax divides indentifier of the input data and +//! The colon `:` in format syntax divides identifier of the input data and //! the formatting options, the colon itself does not change anything, only //! introduces the options. //! diff --git a/alloc/src/lib.rs b/alloc/src/lib.rs index f0cdb1e4e0f78..e70e6ca0d55d3 100644 --- a/alloc/src/lib.rs +++ b/alloc/src/lib.rs @@ -104,6 +104,7 @@ #![feature(async_iterator)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(char_internals)] #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] @@ -135,6 +136,7 @@ #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] #![feature(pointer_like_trait)] +#![feature(ptr_alignment_type)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(set_ptr_value)] diff --git a/alloc/src/raw_vec/mod.rs b/alloc/src/raw_vec/mod.rs index 99ebc5c4bfca8..a989e5b55b3d1 100644 --- a/alloc/src/raw_vec/mod.rs +++ b/alloc/src/raw_vec/mod.rs @@ -6,7 +6,7 @@ use core::marker::PhantomData; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; -use core::ptr::{self, NonNull, Unique}; +use core::ptr::{self, Alignment, NonNull, Unique}; use core::{cmp, hint}; #[cfg(not(no_global_oom_handling))] @@ -177,7 +177,7 @@ impl RawVec { /// the returned `RawVec`. #[inline] pub(crate) const fn new_in(alloc: A) -> Self { - Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } + Self { inner: RawVecInner::new_in(alloc, Alignment::of::()), _marker: PhantomData } } /// Like `with_capacity`, but parameterized over the choice of @@ -409,8 +409,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { impl RawVecInner { #[inline] - const fn new_in(alloc: A, align: usize) -> Self { - let ptr = unsafe { core::mem::transmute(align) }; + const fn new_in(alloc: A, align: Alignment) -> Self { + let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero())); // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr, cap: ZERO_CAP, alloc } } @@ -465,7 +465,7 @@ impl RawVecInner { // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. if layout.size() == 0 { - return Ok(Self::new_in(alloc, elem_layout.align())); + return Ok(Self::new_in(alloc, elem_layout.alignment())); } if let Err(err) = alloc_guard(layout.size()) { diff --git a/alloc/src/string.rs b/alloc/src/string.rs index 9236f5cb8d1f0..9a161d057db09 100644 --- a/alloc/src/string.rs +++ b/alloc/src/string.rs @@ -1043,7 +1043,7 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_bytes(self) -> Vec { self.vec @@ -1062,7 +1062,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[rustc_diagnostic_item = "string_as_str"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_str(&self) -> &str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1085,7 +1085,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[rustc_diagnostic_item = "string_as_mut_str"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_mut_str(&mut self) -> &mut str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1134,7 +1134,7 @@ impl String { /// assert_eq!(string, "abcdecdeabecde"); /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "string_extend_from_within", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "string_extend_from_within", since = "1.87.0")] pub fn extend_from_within(&mut self, src: R) where R: RangeBounds, @@ -1159,7 +1159,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1401,11 +1401,14 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, ch: char) { - match ch.len_utf8() { - 1 => self.vec.push(ch as u8), - _ => { - self.vec.extend_from_slice(ch.encode_utf8(&mut [0; char::MAX_LEN_UTF8]).as_bytes()) - } + let len = self.len(); + let ch_len = ch.len_utf8(); + self.reserve(ch_len); + + // SAFETY: Just reserved capacity for at least the length needed to encode `ch`. + unsafe { + core::char::encode_utf8_raw_unchecked(ch as u32, self.vec.as_mut_ptr().add(self.len())); + self.vec.set_len(len + ch_len); } } @@ -1425,7 +1428,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_bytes(&self) -> &[u8] { self.vec.as_slice() } @@ -1702,24 +1705,31 @@ impl String { #[rustc_confusables("set")] pub fn insert(&mut self, idx: usize, ch: char) { assert!(self.is_char_boundary(idx)); - let mut bits = [0; char::MAX_LEN_UTF8]; - let bits = ch.encode_utf8(&mut bits).as_bytes(); + let len = self.len(); + let ch_len = ch.len_utf8(); + self.reserve(ch_len); + + // SAFETY: Move the bytes starting from `idx` to their new location `ch_len` + // bytes ahead. This is safe because sufficient capacity was reserved, and `idx` + // is a char boundary. unsafe { - self.insert_bytes(idx, bits); + ptr::copy( + self.vec.as_ptr().add(idx), + self.vec.as_mut_ptr().add(idx + ch_len), + len - idx, + ); } - } - #[cfg(not(no_global_oom_handling))] - unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { - let len = self.len(); - let amt = bytes.len(); - self.vec.reserve(amt); + // SAFETY: Encode the character into the vacated region if `idx != len`, + // or into the uninitialized spare capacity otherwise. + unsafe { + core::char::encode_utf8_raw_unchecked(ch as u32, self.vec.as_mut_ptr().add(idx)); + } + // SAFETY: Update the length to include the newly added bytes. unsafe { - ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); - ptr::copy_nonoverlapping(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); - self.vec.set_len(len + amt); + self.vec.set_len(len + ch_len); } } @@ -1749,8 +1759,27 @@ impl String { pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); + let len = self.len(); + let amt = string.len(); + self.reserve(amt); + + // SAFETY: Move the bytes starting from `idx` to their new location `amt` bytes + // ahead. This is safe because sufficient capacity was just reserved, and `idx` + // is a char boundary. + unsafe { + ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); + } + + // SAFETY: Copy the new string slice into the vacated region if `idx != len`, + // or into the uninitialized spare capacity otherwise. The borrow checker + // ensures that the source and destination do not overlap. + unsafe { + ptr::copy_nonoverlapping(string.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + } + + // SAFETY: Update the length to include the newly added bytes. unsafe { - self.insert_bytes(idx, string.as_bytes()); + self.vec.set_len(len + amt); } } @@ -1779,7 +1808,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec { &mut self.vec } @@ -1801,7 +1830,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { self.vec.len() @@ -1821,7 +1850,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -3140,7 +3169,7 @@ impl From for Vec { } } -#[stable(feature = "try_from_vec_u8_for_string", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "try_from_vec_u8_for_string", since = "1.87.0")] impl TryFrom> for String { type Error = FromUtf8Error; /// Converts the given [`Vec`] into a [`String`] if it contains valid UTF-8 data. diff --git a/alloc/src/vec/extract_if.rs b/alloc/src/vec/extract_if.rs index be869553ef4e1..8a591a8779643 100644 --- a/alloc/src/vec/extract_if.rs +++ b/alloc/src/vec/extract_if.rs @@ -15,7 +15,7 @@ use crate::alloc::{Allocator, Global}; /// let mut v = vec![0, 1, 2]; /// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] #[derive(Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< @@ -57,7 +57,7 @@ impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { } } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -93,7 +93,7 @@ where } } -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 633ef717e04dc..68e4add30e5d0 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -66,7 +66,7 @@ use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; use core::{fmt, intrinsics}; -#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; @@ -1267,7 +1267,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn capacity(&self) -> usize { self.buf.capacity() } @@ -1582,7 +1582,7 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[rustc_diagnostic_item = "vec_as_slice"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_slice(&self) -> &[T] { // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size // `len` containing properly-initialized `T`s. Data must not be mutated for the returned @@ -1614,7 +1614,7 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[rustc_diagnostic_item = "vec_as_mut_slice"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any @@ -1686,7 +1686,7 @@ impl Vec { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -1749,7 +1749,7 @@ impl Vec { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -2700,7 +2700,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { let len = self.len; @@ -2726,7 +2726,7 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_is_empty"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2803,6 +2803,10 @@ impl Vec { /// want to use the [`Default`] trait to generate values, you can /// pass [`Default::default`] as the second argument. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -3010,6 +3014,10 @@ impl Vec { /// [`Clone`]), use [`Vec::resize_with`]. /// If you only need to resize to a smaller size, use [`Vec::truncate`]. /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// /// # Examples /// /// ``` @@ -3707,7 +3715,7 @@ impl Vec { /// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); /// assert_eq!(ones.len(), 3); /// ``` - #[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "extract_if", since = "1.87.0")] pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, diff --git a/alloctests/benches/string.rs b/alloctests/benches/string.rs index 3d79ab78c6950..0bbec12e4fdc6 100644 --- a/alloctests/benches/string.rs +++ b/alloctests/benches/string.rs @@ -4,7 +4,7 @@ use test::{Bencher, black_box}; #[bench] fn bench_with_capacity(b: &mut Bencher) { - b.iter(|| String::with_capacity(100)); + b.iter(|| String::with_capacity(black_box(100))); } #[bench] @@ -12,7 +12,8 @@ fn bench_push_str(b: &mut Bencher) { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; b.iter(|| { let mut r = String::new(); - r.push_str(s); + black_box(&mut r).push_str(black_box(s)); + r }); } @@ -24,8 +25,9 @@ fn bench_push_str_one_byte(b: &mut Bencher) { b.iter(|| { let mut r = String::new(); for _ in 0..REPETITIONS { - r.push_str("a") + black_box(&mut r).push_str(black_box("a")); } + r }); } @@ -35,8 +37,9 @@ fn bench_push_char_one_byte(b: &mut Bencher) { b.iter(|| { let mut r = String::new(); for _ in 0..REPETITIONS { - r.push('a') + black_box(&mut r).push(black_box('a')); } + r }); } @@ -46,8 +49,9 @@ fn bench_push_char_two_bytes(b: &mut Bencher) { b.iter(|| { let mut r = String::new(); for _ in 0..REPETITIONS { - r.push('â') + black_box(&mut r).push(black_box('â')); } + r }); } @@ -57,34 +61,26 @@ fn from_utf8_lossy_100_ascii(b: &mut Bencher) { Lorem ipsum dolor sit amet, consectetur. "; assert_eq!(100, s.len()); - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); + b.iter(|| String::from_utf8_lossy(black_box(s))); } #[bench] fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); assert_eq!(100, s.len()); - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); + b.iter(|| String::from_utf8_lossy(black_box(s))); } #[bench] fn from_utf8_lossy_invalid(b: &mut Bencher) { let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); + b.iter(|| String::from_utf8_lossy(black_box(s))); } #[bench] fn from_utf8_lossy_100_invalid(b: &mut Bencher) { let s = repeat(0xf5).take(100).collect::>(); - b.iter(|| { - let _ = String::from_utf8_lossy(&s); - }); + b.iter(|| String::from_utf8_lossy(black_box(&s))); } #[bench] @@ -96,8 +92,8 @@ fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { r.push_str(s); assert_eq!(r.len(), r.capacity()); b.iter(|| { - let mut r = String::with_capacity(s.len()); - r.push_str(s); + let mut r = String::with_capacity(black_box(s.len())); + r.push_str(black_box(s)); r.shrink_to_fit(); r }); @@ -107,21 +103,21 @@ fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { fn bench_from_str(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| String::from(s)) + b.iter(|| String::from(black_box(s))) } #[bench] fn bench_from(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| String::from(s)) + b.iter(|| String::from(black_box(s))) } #[bench] fn bench_to_string(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| s.to_string()) + b.iter(|| black_box(s).to_string()) } #[bench] @@ -129,7 +125,7 @@ fn bench_insert_char_short(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert(6, black_box(' ')); + black_box(&mut x).insert(black_box(6), black_box(' ')); x }) } @@ -139,7 +135,7 @@ fn bench_insert_char_long(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert(6, black_box('❤')); + black_box(&mut x).insert(black_box(6), black_box('❤')); x }) } @@ -149,7 +145,7 @@ fn bench_insert_str_short(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert_str(6, black_box(" ")); + black_box(&mut x).insert_str(black_box(6), black_box(" ")); x }) } @@ -159,7 +155,7 @@ fn bench_insert_str_long(b: &mut Bencher) { let s = "Hello, World!"; b.iter(|| { let mut x = String::from(s); - black_box(&mut x).insert_str(6, black_box(" rustic ")); + black_box(&mut x).insert_str(black_box(6), black_box(" rustic ")); x }) } diff --git a/alloctests/lib.rs b/alloctests/lib.rs index 6ce8a6d9ca174..56e60ed4c8448 100644 --- a/alloctests/lib.rs +++ b/alloctests/lib.rs @@ -28,6 +28,8 @@ #![feature(iter_next_chunk)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] +#![feature(nonnull_provenance)] +#![feature(ptr_alignment_type)] #![feature(ptr_internals)] #![feature(sized_type_properties)] #![feature(slice_iter_mut_as_mut_slice)] diff --git a/core/Cargo.toml b/core/Cargo.toml index b60826ee4e6c7..fe61f552a49de 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -32,8 +32,6 @@ check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', 'cfg(stdarch_intel_sde)', - # #[cfg(bootstrap)] - 'cfg(target_feature, values("vector-enhancements-1"))', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/core/src/alloc/layout.rs b/core/src/alloc/layout.rs index 1595a3af883d1..e8a03aadc3390 100644 --- a/core/src/alloc/layout.rs +++ b/core/src/alloc/layout.rs @@ -520,6 +520,14 @@ impl Layout { unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) } } } + + /// Perma-unstable access to `align` as `Alignment` type. + #[unstable(issue = "none", feature = "std_internals")] + #[doc(hidden)] + #[inline] + pub const fn alignment(&self) -> Alignment { + self.align + } } #[stable(feature = "alloc_layout", since = "1.28.0")] diff --git a/core/src/array/iter.rs b/core/src/array/iter.rs index 1edade41597f7..90f76d6d4c7be 100644 --- a/core/src/array/iter.rs +++ b/core/src/array/iter.rs @@ -1,38 +1,35 @@ //! Defines the `IntoIter` owned iterator for arrays. use crate::intrinsics::transmute_unchecked; -use crate::iter::{self, FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}; use crate::mem::MaybeUninit; use crate::num::NonZero; -use crate::ops::{IndexRange, Range}; +use crate::ops::{IndexRange, Range, Try}; use crate::{fmt, ptr}; +mod iter_inner; + +type InnerSized = iter_inner::PolymorphicIter<[MaybeUninit; N]>; +type InnerUnsized = iter_inner::PolymorphicIter<[MaybeUninit]>; + /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] #[rustc_insignificant_dtor] #[rustc_diagnostic_item = "ArrayIntoIter"] +#[derive(Clone)] pub struct IntoIter { - /// This is the array we are iterating over. - /// - /// Elements with index `i` where `alive.start <= i < alive.end` have not - /// been yielded yet and are valid array entries. Elements with indices `i - /// < alive.start` or `i >= alive.end` have been yielded already and must - /// not be accessed anymore! Those dead elements might even be in a - /// completely uninitialized state! - /// - /// So the invariants are: - /// - `data[alive]` is alive (i.e. contains valid elements) - /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the - /// elements were already read and must not be touched anymore!) - data: [MaybeUninit; N], + inner: InnerSized, +} - /// The elements in `data` that have not been yielded yet. - /// - /// Invariants: - /// - `alive.end <= N` - /// - /// (And the `IndexRange` type requires `alive.start <= alive.end`.) - alive: IndexRange, +impl IntoIter { + #[inline] + fn unsize(&self) -> &InnerUnsized { + &self.inner + } + #[inline] + fn unsize_mut(&mut self) -> &mut InnerUnsized { + &mut self.inner + } } // Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator` @@ -53,6 +50,7 @@ impl IntoIterator for [T; N] { /// 2021 edition -- see the [array] Editions section for more information. /// /// [array]: prim@array + #[inline] fn into_iter(self) -> Self::IntoIter { // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit` // promise: @@ -68,7 +66,10 @@ impl IntoIterator for [T; N] { // FIXME: If normal `transmute` ever gets smart enough to allow this // directly, use it instead of `transmute_unchecked`. let data: [MaybeUninit; N] = unsafe { transmute_unchecked(self) }; - IntoIter { data, alive: IndexRange::zero_to(N) } + // SAFETY: The original array was entirely initialized and the the alive + // range we're passing here represents that fact. + let inner = unsafe { InnerSized::new_unchecked(IndexRange::zero_to(N), data) }; + IntoIter { inner } } } @@ -136,13 +137,16 @@ impl IntoIter { /// assert_eq!(r.collect::>(), vec![10, 11, 12, 13, 14, 15]); /// ``` #[unstable(feature = "array_into_iter_constructors", issue = "91583")] + #[inline] pub const unsafe fn new_unchecked( buffer: [MaybeUninit; N], initialized: Range, ) -> Self { // SAFETY: one of our safety conditions is that the range is canonical. let alive = unsafe { IndexRange::new_unchecked(initialized.start, initialized.end) }; - Self { data: buffer, alive } + // SAFETY: one of our safety condition is that these items are initialized. + let inner = unsafe { InnerSized::new_unchecked(alive, buffer) }; + IntoIter { inner } } /// Creates an iterator over `T` which returns no elements. @@ -198,172 +202,134 @@ impl IntoIter { /// assert_eq!(get_bytes(false).collect::>(), vec![]); /// ``` #[unstable(feature = "array_into_iter_constructors", issue = "91583")] + #[inline] pub const fn empty() -> Self { - let buffer = [const { MaybeUninit::uninit() }; N]; - let initialized = 0..0; - - // SAFETY: We're telling it that none of the elements are initialized, - // which is trivially true. And ∀N: usize, 0 <= N. - unsafe { Self::new_unchecked(buffer, initialized) } + let inner = InnerSized::empty(); + IntoIter { inner } } /// Returns an immutable slice of all elements that have not been yielded /// yet. #[stable(feature = "array_value_iter", since = "1.51.0")] + #[inline] pub fn as_slice(&self) -> &[T] { - // SAFETY: We know that all elements within `alive` are properly initialized. - unsafe { - let slice = self.data.get_unchecked(self.alive.clone()); - slice.assume_init_ref() - } + self.unsize().as_slice() } /// Returns a mutable slice of all elements that have not been yielded yet. #[stable(feature = "array_value_iter", since = "1.51.0")] + #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { - // SAFETY: We know that all elements within `alive` are properly initialized. - unsafe { - let slice = self.data.get_unchecked_mut(self.alive.clone()); - slice.assume_init_mut() - } + self.unsize_mut().as_mut_slice() } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Iterator for IntoIter { type Item = T; + + #[inline] fn next(&mut self) -> Option { - // Get the next index from the front. - // - // Increasing `alive.start` by 1 maintains the invariant regarding - // `alive`. However, due to this change, for a short time, the alive - // zone is not `data[alive]` anymore, but `data[idx..alive.end]`. - self.alive.next().map(|idx| { - // Read the element from the array. - // SAFETY: `idx` is an index into the former "alive" region of the - // array. Reading this element means that `data[idx]` is regarded as - // dead now (i.e. do not touch). As `idx` was the start of the - // alive-zone, the alive zone is now `data[alive]` again, restoring - // all invariants. - unsafe { self.data.get_unchecked(idx).assume_init_read() } - }) + self.unsize_mut().next() } + #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) + self.unsize().size_hint() } #[inline] - fn fold(mut self, init: Acc, mut fold: Fold) -> Acc + fn fold(mut self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let data = &mut self.data; - iter::ByRefSized(&mut self.alive).fold(init, |acc, idx| { - // SAFETY: idx is obtained by folding over the `alive` range, which implies the - // value is currently considered alive but as the range is being consumed each value - // we read here will only be read once and then considered dead. - fold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) - }) + self.unsize_mut().fold(init, fold) } + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.unsize_mut().try_fold(init, f) + } + + #[inline] fn count(self) -> usize { self.len() } + #[inline] fn last(mut self) -> Option { self.next_back() } + #[inline] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - // This also moves the start, which marks them as conceptually "dropped", - // so if anything goes bad then our drop impl won't double-free them. - let range_to_drop = self.alive.take_prefix(n); - let remaining = n - range_to_drop.len(); - - // SAFETY: These elements are currently initialized, so it's fine to drop them. - unsafe { - let slice = self.data.get_unchecked_mut(range_to_drop); - slice.assume_init_drop(); - } - - NonZero::new(remaining).map_or(Ok(()), Err) + self.unsize_mut().advance_by(n) } #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: The caller must provide an idx that is in bound of the remainder. - unsafe { self.data.as_ptr().add(self.alive.start()).add(idx).cast::().read() } + let elem_ref = unsafe { self.as_mut_slice().get_unchecked_mut(idx) }; + // SAFETY: We only implement `TrustedRandomAccessNoCoerce` for types + // which are actually `Copy`, so cannot have multiple-drop issues. + unsafe { ptr::read(elem_ref) } } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl DoubleEndedIterator for IntoIter { + #[inline] fn next_back(&mut self) -> Option { - // Get the next index from the back. - // - // Decreasing `alive.end` by 1 maintains the invariant regarding - // `alive`. However, due to this change, for a short time, the alive - // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`. - self.alive.next_back().map(|idx| { - // Read the element from the array. - // SAFETY: `idx` is an index into the former "alive" region of the - // array. Reading this element means that `data[idx]` is regarded as - // dead now (i.e. do not touch). As `idx` was the end of the - // alive-zone, the alive zone is now `data[alive]` again, restoring - // all invariants. - unsafe { self.data.get_unchecked(idx).assume_init_read() } - }) + self.unsize_mut().next_back() } #[inline] - fn rfold(mut self, init: Acc, mut rfold: Fold) -> Acc + fn rfold(mut self, init: Acc, rfold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - let data = &mut self.data; - iter::ByRefSized(&mut self.alive).rfold(init, |acc, idx| { - // SAFETY: idx is obtained by folding over the `alive` range, which implies the - // value is currently considered alive but as the range is being consumed each value - // we read here will only be read once and then considered dead. - rfold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) - }) + self.unsize_mut().rfold(init, rfold) + } + + #[inline] + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.unsize_mut().try_rfold(init, f) } + #[inline] fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - // This also moves the end, which marks them as conceptually "dropped", - // so if anything goes bad then our drop impl won't double-free them. - let range_to_drop = self.alive.take_suffix(n); - let remaining = n - range_to_drop.len(); - - // SAFETY: These elements are currently initialized, so it's fine to drop them. - unsafe { - let slice = self.data.get_unchecked_mut(range_to_drop); - slice.assume_init_drop(); - } - - NonZero::new(remaining).map_or(Ok(()), Err) + self.unsize_mut().advance_back_by(n) } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Drop for IntoIter { + #[inline] fn drop(&mut self) { - // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice - // of elements that have not been moved out yet and that remain - // to be dropped. - unsafe { ptr::drop_in_place(self.as_mut_slice()) } + // `inner` now handles this, but it'd technically be a breaking change + // to remove this `impl`, even though it's useless. } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl ExactSizeIterator for IntoIter { + #[inline] fn len(&self) -> usize { - self.alive.len() + self.inner.len() } + #[inline] fn is_empty(&self) -> bool { - self.alive.is_empty() + self.inner.len() == 0 } } @@ -396,32 +362,9 @@ where const MAY_HAVE_SIDE_EFFECT: bool = false; } -#[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl Clone for IntoIter { - fn clone(&self) -> Self { - // Note, we don't really need to match the exact same alive range, so - // we can just clone into offset 0 regardless of where `self` is. - let mut new = - Self { data: [const { MaybeUninit::uninit() }; N], alive: IndexRange::zero_to(0) }; - - // Clone all alive elements. - for (src, dst) in iter::zip(self.as_slice(), &mut new.data) { - // Write a clone into the new array, then update its alive range. - // If cloning panics, we'll correctly drop the previous items. - dst.write(src.clone()); - // This addition cannot overflow as we're iterating a slice - new.alive = IndexRange::zero_to(new.alive.end() + 1); - } - - new - } -} - #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Only print the elements that were not yielded yet: we cannot - // access the yielded elements anymore. - f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + self.unsize().fmt(f) } } diff --git a/core/src/array/iter/iter_inner.rs b/core/src/array/iter/iter_inner.rs new file mode 100644 index 0000000000000..3c2343591f8cf --- /dev/null +++ b/core/src/array/iter/iter_inner.rs @@ -0,0 +1,281 @@ +//! Defines the `IntoIter` owned iterator for arrays. + +use crate::mem::MaybeUninit; +use crate::num::NonZero; +use crate::ops::{IndexRange, NeverShortCircuit, Try}; +use crate::{fmt, iter}; + +#[allow(private_bounds)] +trait PartialDrop { + /// # Safety + /// `self[alive]` are all initialized before the call, + /// then are never used (without reinitializing them) after it. + unsafe fn partial_drop(&mut self, alive: IndexRange); +} +impl PartialDrop for [MaybeUninit] { + unsafe fn partial_drop(&mut self, alive: IndexRange) { + // SAFETY: We know that all elements within `alive` are properly initialized. + unsafe { self.get_unchecked_mut(alive).assume_init_drop() } + } +} +impl PartialDrop for [MaybeUninit; N] { + unsafe fn partial_drop(&mut self, alive: IndexRange) { + let slice: &mut [MaybeUninit] = self; + // SAFETY: Initialized elements in the array are also initialized in the slice. + unsafe { slice.partial_drop(alive) } + } +} + +/// The internals of a by-value array iterator. +/// +/// The real `array::IntoIter` stores a `PolymorphicIter<[MaybeUninit, N]>` +/// which it unsizes to `PolymorphicIter<[MaybeUninit]>` to iterate. +#[allow(private_bounds)] +pub(super) struct PolymorphicIter +where + DATA: PartialDrop, +{ + /// The elements in `data` that have not been yielded yet. + /// + /// Invariants: + /// - `alive.end <= N` + /// + /// (And the `IndexRange` type requires `alive.start <= alive.end`.) + alive: IndexRange, + + /// This is the array we are iterating over. + /// + /// Elements with index `i` where `alive.start <= i < alive.end` have not + /// been yielded yet and are valid array entries. Elements with indices `i + /// < alive.start` or `i >= alive.end` have been yielded already and must + /// not be accessed anymore! Those dead elements might even be in a + /// completely uninitialized state! + /// + /// So the invariants are: + /// - `data[alive]` is alive (i.e. contains valid elements) + /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the + /// elements were already read and must not be touched anymore!) + data: DATA, +} + +#[allow(private_bounds)] +impl PolymorphicIter +where + DATA: PartialDrop, +{ + #[inline] + pub(super) const fn len(&self) -> usize { + self.alive.len() + } +} + +#[allow(private_bounds)] +impl Drop for PolymorphicIter +where + DATA: PartialDrop, +{ + #[inline] + fn drop(&mut self) { + // SAFETY: by our type invariant `self.alive` is exactly the initialized + // items, and this is drop so nothing can use the items afterwards. + unsafe { self.data.partial_drop(self.alive.clone()) } + } +} + +impl PolymorphicIter<[MaybeUninit; N]> { + #[inline] + pub(super) const fn empty() -> Self { + Self { alive: IndexRange::zero_to(0), data: [const { MaybeUninit::uninit() }; N] } + } + + /// # Safety + /// `data[alive]` are all initialized. + #[inline] + pub(super) const unsafe fn new_unchecked(alive: IndexRange, data: [MaybeUninit; N]) -> Self { + Self { alive, data } + } +} + +impl Clone for PolymorphicIter<[MaybeUninit; N]> { + #[inline] + fn clone(&self) -> Self { + // Note, we don't really need to match the exact same alive range, so + // we can just clone into offset 0 regardless of where `self` is. + let mut new = Self::empty(); + + fn clone_into_new( + source: &PolymorphicIter<[MaybeUninit]>, + target: &mut PolymorphicIter<[MaybeUninit]>, + ) { + // Clone all alive elements. + for (src, dst) in iter::zip(source.as_slice(), &mut target.data) { + // Write a clone into the new array, then update its alive range. + // If cloning panics, we'll correctly drop the previous items. + dst.write(src.clone()); + // This addition cannot overflow as we're iterating a slice, + // the length of which always fits in usize. + target.alive = IndexRange::zero_to(target.alive.end() + 1); + } + } + + clone_into_new(self, &mut new); + new + } +} + +impl PolymorphicIter<[MaybeUninit]> { + #[inline] + pub(super) fn as_slice(&self) -> &[T] { + // SAFETY: We know that all elements within `alive` are properly initialized. + unsafe { + let slice = self.data.get_unchecked(self.alive.clone()); + slice.assume_init_ref() + } + } + + #[inline] + pub(super) fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: We know that all elements within `alive` are properly initialized. + unsafe { + let slice = self.data.get_unchecked_mut(self.alive.clone()); + slice.assume_init_mut() + } + } +} + +impl fmt::Debug for PolymorphicIter<[MaybeUninit]> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Only print the elements that were not yielded yet: we cannot + // access the yielded elements anymore. + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} + +/// Iterator-equivalent methods. +/// +/// We don't implement the actual iterator traits because we want to implement +/// things like `try_fold` that require `Self: Sized` (which we're not). +impl PolymorphicIter<[MaybeUninit]> { + #[inline] + pub(super) fn next(&mut self) -> Option { + // Get the next index from the front. + // + // Increasing `alive.start` by 1 maintains the invariant regarding + // `alive`. However, due to this change, for a short time, the alive + // zone is not `data[alive]` anymore, but `data[idx..alive.end]`. + self.alive.next().map(|idx| { + // Read the element from the array. + // SAFETY: `idx` is an index into the former "alive" region of the + // array. Reading this element means that `data[idx]` is regarded as + // dead now (i.e. do not touch). As `idx` was the start of the + // alive-zone, the alive zone is now `data[alive]` again, restoring + // all invariants. + unsafe { self.data.get_unchecked(idx).assume_init_read() } + }) + } + + #[inline] + pub(super) fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + #[inline] + pub(super) fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + // This also moves the start, which marks them as conceptually "dropped", + // so if anything goes bad then our drop impl won't double-free them. + let range_to_drop = self.alive.take_prefix(n); + let remaining = n - range_to_drop.len(); + + // SAFETY: These elements are currently initialized, so it's fine to drop them. + unsafe { + let slice = self.data.get_unchecked_mut(range_to_drop); + slice.assume_init_drop(); + } + + NonZero::new(remaining).map_or(Ok(()), Err) + } + + #[inline] + pub(super) fn fold(&mut self, init: B, f: impl FnMut(B, T) -> B) -> B { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + pub(super) fn try_fold(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, T) -> R, + R: Try, + { + // `alive` is an `IndexRange`, not an arbitrary iterator, so we can + // trust that its `try_fold` isn't going to do something weird like + // call the fold-er multiple times for the same index. + let data = &mut self.data; + self.alive.try_fold(init, move |accum, idx| { + // SAFETY: `idx` has been removed from the alive range, so we're not + // going to drop it (even if `f` panics) and thus its ok to give + // out ownership of that item to `f` to handle. + let elem = unsafe { data.get_unchecked(idx).assume_init_read() }; + f(accum, elem) + }) + } + + #[inline] + pub(super) fn next_back(&mut self) -> Option { + // Get the next index from the back. + // + // Decreasing `alive.end` by 1 maintains the invariant regarding + // `alive`. However, due to this change, for a short time, the alive + // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`. + self.alive.next_back().map(|idx| { + // Read the element from the array. + // SAFETY: `idx` is an index into the former "alive" region of the + // array. Reading this element means that `data[idx]` is regarded as + // dead now (i.e. do not touch). As `idx` was the end of the + // alive-zone, the alive zone is now `data[alive]` again, restoring + // all invariants. + unsafe { self.data.get_unchecked(idx).assume_init_read() } + }) + } + + #[inline] + pub(super) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + // This also moves the end, which marks them as conceptually "dropped", + // so if anything goes bad then our drop impl won't double-free them. + let range_to_drop = self.alive.take_suffix(n); + let remaining = n - range_to_drop.len(); + + // SAFETY: These elements are currently initialized, so it's fine to drop them. + unsafe { + let slice = self.data.get_unchecked_mut(range_to_drop); + slice.assume_init_drop(); + } + + NonZero::new(remaining).map_or(Ok(()), Err) + } + + #[inline] + pub(super) fn rfold(&mut self, init: B, f: impl FnMut(B, T) -> B) -> B { + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + pub(super) fn try_rfold(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, T) -> R, + R: Try, + { + // `alive` is an `IndexRange`, not an arbitrary iterator, so we can + // trust that its `try_rfold` isn't going to do something weird like + // call the fold-er multiple times for the same index. + let data = &mut self.data; + self.alive.try_rfold(init, move |accum, idx| { + // SAFETY: `idx` has been removed from the alive range, so we're not + // going to drop it (even if `f` panics) and thus its ok to give + // out ownership of that item to `f` to handle. + let elem = unsafe { data.get_unchecked(idx).assume_init_read() }; + f(accum, elem) + }) + } +} diff --git a/core/src/array/mod.rs b/core/src/array/mod.rs index 28329bb090845..efa7bed7c8e17 100644 --- a/core/src/array/mod.rs +++ b/core/src/array/mod.rs @@ -55,12 +55,16 @@ pub fn repeat(val: T) -> [T; N] { from_trusted_iterator(repeat_n(val, N)) } -/// Creates an array of type [T; N], where each element `T` is the returned value from `cb` -/// using that element's index. +/// Creates an array where each element is produced by calling `f` with +/// that element's index while walking forward through the array. /// -/// # Arguments +/// This is essentially the same as writing +/// ```text +/// [f(0), f(1), f(2), …, f(N - 2), f(N - 1)] +/// ``` +/// and is similar to `(0..i).map(f)`, just for arrays not iterators. /// -/// * `cb`: Callback where the passed argument is the current array index. +/// If `N == 0`, this produces an empty array without ever calling `f`. /// /// # Example /// @@ -82,13 +86,30 @@ pub fn repeat(val: T) -> [T; N] { /// // indexes are: 0 1 2 3 4 /// assert_eq!(bool_arr, [true, false, true, false, true]); /// ``` +/// +/// You can also capture things, for example to create an array full of clones +/// where you can't just use `[item; N]` because it's not `Copy`: +/// ``` +/// # // TBH `array::repeat` would be better for this, but it's not stable yet. +/// let my_string = String::from("Hello"); +/// let clones: [String; 42] = std::array::from_fn(|_| my_string.clone()); +/// assert!(clones.iter().all(|x| *x == my_string)); +/// ``` +/// +/// The array is generated in ascending index order, starting from the front +/// and going towards the back, so you can use closures with mutable state: +/// ``` +/// let mut state = 1; +/// let a = std::array::from_fn(|_| { let x = state; state *= 2; x }); +/// assert_eq!(a, [1, 2, 4, 8, 16, 32]); +/// ``` #[inline] #[stable(feature = "array_from_fn", since = "1.63.0")] -pub fn from_fn(cb: F) -> [T; N] +pub fn from_fn(f: F) -> [T; N] where F: FnMut(usize) -> T, { - try_from_fn(NeverShortCircuit::wrap_mut_1(cb)).0 + try_from_fn(NeverShortCircuit::wrap_mut_1(f)).0 } /// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call. diff --git a/core/src/bool.rs b/core/src/bool.rs index d525ab425e60d..2016ece007eba 100644 --- a/core/src/bool.rs +++ b/core/src/bool.rs @@ -61,52 +61,4 @@ impl bool { pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } } - - /// Returns either `true_val` or `false_val` depending on the value of - /// `self`, with a hint to the compiler that `self` is unlikely - /// to be correctly predicted by a CPU’s branch predictor. - /// - /// This method is functionally equivalent to - /// ```ignore (this is just for illustrative purposes) - /// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { - /// if b { true_val } else { false_val } - /// } - /// ``` - /// but might generate different assembly. In particular, on platforms with - /// a conditional move or select instruction (like `cmov` on x86 or `csel` - /// on ARM) the optimizer might use these instructions to avoid branches, - /// which can benefit performance if the branch predictor is struggling - /// with predicting `condition`, such as in an implementation of binary - /// search. - /// - /// Note however that this lowering is not guaranteed (on any platform) and - /// should not be relied upon when trying to write constant-time code. Also - /// be aware that this lowering might *decrease* performance if `condition` - /// is well-predictable. It is advisable to perform benchmarks to tell if - /// this function is useful. - /// - /// # Examples - /// - /// Distribute values evenly between two buckets: - /// ``` - /// #![feature(select_unpredictable)] - /// - /// use std::hash::BuildHasher; - /// - /// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { - /// let hash = hasher.hash_one(&v); - /// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two); - /// bucket.push(v); - /// } - /// # let hasher = std::collections::hash_map::RandomState::new(); - /// # let mut bucket_one = Vec::new(); - /// # let mut bucket_two = Vec::new(); - /// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); - /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); - /// ``` - #[inline(always)] - #[unstable(feature = "select_unpredictable", issue = "133962")] - pub fn select_unpredictable(self, true_val: T, false_val: T) -> T { - crate::intrinsics::select_unpredictable(self, true_val, false_val) - } } diff --git a/core/src/cell.rs b/core/src/cell.rs index 09117e4968db6..17231df731d13 100644 --- a/core/src/cell.rs +++ b/core/src/cell.rs @@ -1156,7 +1156,9 @@ impl RefCell { /// Since this method borrows `RefCell` mutably, it is statically guaranteed /// that no borrows to the underlying data exist. The dynamic checks inherent /// in [`borrow_mut`] and most other methods of `RefCell` are therefore - /// unnecessary. + /// unnecessary. Note that this method does not reset the borrowing state if borrows were previously leaked + /// (e.g., via [`forget()`] on a [`Ref`] or [`RefMut`]). For that purpose, + /// consider using the unstable [`undo_leak`] method. /// /// This method can only be called if `RefCell` can be mutably borrowed, /// which in general is only the case directly after the `RefCell` has @@ -1167,6 +1169,8 @@ impl RefCell { /// Use [`borrow_mut`] to get mutable access to the underlying data then. /// /// [`borrow_mut`]: RefCell::borrow_mut() + /// [`forget()`]: mem::forget + /// [`undo_leak`]: RefCell::undo_leak() /// /// # Examples /// diff --git a/core/src/char/methods.rs b/core/src/char/methods.rs index fa584953bed5c..042925a352f39 100644 --- a/core/src/char/methods.rs +++ b/core/src/char/methods.rs @@ -337,7 +337,7 @@ impl char { /// '1'.is_digit(1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_char_classify", since = "1.87.0")] #[inline] pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() @@ -886,7 +886,7 @@ impl char { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_char_classify", since = "1.87.0")] #[inline] pub const fn is_whitespace(self) -> bool { match self { @@ -1806,39 +1806,71 @@ const fn len_utf16(code: u32) -> usize { #[inline] pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { let len = len_utf8(code); - match (len, &mut *dst) { - (1, [a, ..]) => { - *a = code as u8; - } - (2, [a, b, ..]) => { - *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *b = (code & 0x3F) as u8 | TAG_CONT; - } - (3, [a, b, c, ..]) => { - *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *b = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *c = (code & 0x3F) as u8 | TAG_CONT; - } - (4, [a, b, c, d, ..]) => { - *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *b = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *d = (code & 0x3F) as u8 | TAG_CONT; - } - _ => { - const_panic!( - "encode_utf8: buffer does not have enough bytes to encode code point", - "encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", - code: u32 = code, - len: usize = len, - dst_len: usize = dst.len(), - ) - } - }; + if dst.len() < len { + const_panic!( + "encode_utf8: buffer does not have enough bytes to encode code point", + "encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}", + code: u32 = code, + len: usize = len, + dst_len: usize = dst.len(), + ); + } + + // SAFETY: `dst` is checked to be at least the length needed to encode the codepoint. + unsafe { encode_utf8_raw_unchecked(code, dst.as_mut_ptr()) }; + // SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds. unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } } +/// Encodes a raw `u32` value as UTF-8 into the byte buffer pointed to by `dst`. +/// +/// Unlike `char::encode_utf8`, this method also handles codepoints in the surrogate range. +/// (Creating a `char` in the surrogate range is UB.) +/// The result is valid [generalized UTF-8] but not valid UTF-8. +/// +/// [generalized UTF-8]: https://simonsapin.github.io/wtf-8/#generalized-utf8 +/// +/// # Safety +/// +/// The behavior is undefined if the buffer pointed to by `dst` is not +/// large enough to hold the encoded codepoint. A buffer of length four +/// is large enough to encode any `char`. +/// +/// For a safe version of this function, see the [`encode_utf8_raw`] function. +#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +#[doc(hidden)] +#[inline] +pub const unsafe fn encode_utf8_raw_unchecked(code: u32, dst: *mut u8) { + let len = len_utf8(code); + // SAFETY: The caller must guarantee that the buffer pointed to by `dst` + // is at least `len` bytes long. + unsafe { + match len { + 1 => { + *dst = code as u8; + } + 2 => { + *dst = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.add(1) = (code & 0x3F) as u8 | TAG_CONT; + } + 3 => { + *dst = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.add(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.add(2) = (code & 0x3F) as u8 | TAG_CONT; + } + 4 => { + *dst = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.add(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.add(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.add(3) = (code & 0x3F) as u8 | TAG_CONT; + } + // SAFETY: `char` always takes between 1 and 4 bytes to encode in UTF-8. + _ => crate::hint::unreachable_unchecked(), + } + } +} + /// Encodes a raw `u32` value as native endian UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// diff --git a/core/src/char/mod.rs b/core/src/char/mod.rs index 088c709f1a2af..5b9f0e2143f5d 100644 --- a/core/src/char/mod.rs +++ b/core/src/char/mod.rs @@ -38,7 +38,7 @@ pub use self::decode::{DecodeUtf16, DecodeUtf16Error}; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf16_raw; // perma-unstable #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -pub use self::methods::encode_utf8_raw; // perma-unstable +pub use self::methods::{encode_utf8_raw, encode_utf8_raw_unchecked}; // perma-unstable #[rustfmt::skip] use crate::ascii; diff --git a/core/src/clone.rs b/core/src/clone.rs index e0ac0bfc5289f..c237ac84cf407 100644 --- a/core/src/clone.rs +++ b/core/src/clone.rs @@ -216,7 +216,7 @@ pub macro Clone($item:item) { /// Use closures allow captured values to be automatically used. /// This is similar to have a closure that you would call `.use` over each captured value. #[unstable(feature = "ergonomic_clones", issue = "132290")] -#[cfg_attr(not(bootstrap), lang = "use_cloned")] +#[lang = "use_cloned"] pub trait UseCloned: Clone { // Empty. } @@ -427,7 +427,7 @@ pub unsafe trait CloneToUninit { /// read or dropped, because even if it was previously valid, it may have been partially /// overwritten. /// - /// The caller may wish to to take care to deallocate the allocation pointed to by `dest`, + /// The caller may wish to take care to deallocate the allocation pointed to by `dest`, /// if applicable, to avoid a memory leak (but this is not a requirement). /// /// Implementors should avoid leaking values by, upon unwinding, dropping all component values diff --git a/core/src/cmp.rs b/core/src/cmp.rs index 0dc2cc72e06cc..c315131f4136c 100644 --- a/core/src/cmp.rs +++ b/core/src/cmp.rs @@ -2053,6 +2053,22 @@ mod impls { fn ge(&self, other: &&B) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn __chaining_lt(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &&B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &A @@ -2108,6 +2124,22 @@ mod impls { fn ge(&self, other: &&mut B) -> bool { PartialOrd::ge(*self, *other) } + #[inline] + fn __chaining_lt(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_lt(*self, *other) + } + #[inline] + fn __chaining_le(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_le(*self, *other) + } + #[inline] + fn __chaining_gt(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_gt(*self, *other) + } + #[inline] + fn __chaining_ge(&self, other: &&mut B) -> ControlFlow { + PartialOrd::__chaining_ge(*self, *other) + } } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for &mut A diff --git a/core/src/contracts.rs b/core/src/contracts.rs index 8b79a3a7eba86..495f84bce4bf2 100644 --- a/core/src/contracts.rs +++ b/core/src/contracts.rs @@ -2,19 +2,23 @@ pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires}; -/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }` -/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }` -/// (including the implicit return of the tail expression, if any). +/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute. +/// +/// This is an existing hack to allow users to omit the type of the return value in their ensures +/// attribute. +/// +/// Ideally, rustc should be able to generate the type annotation. +/// The existing lowering logic makes it rather hard to add the explicit type annotation, +/// while the function call is fairly straight forward. #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +// Similar to `contract_check_requires`, we need to use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals`. +// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. +#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_build_check_ensures"] -#[track_caller] -pub fn build_check_ensures(cond: C) -> impl (Fn(Ret) -> Ret) + Copy +pub const fn build_check_ensures(cond: C) -> C where - C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static, + C: Fn(&Ret) -> bool + Copy + 'static, { - #[track_caller] - move |ret| { - crate::intrinsics::contract_check_ensures(&ret, cond); - ret - } + cond } diff --git a/core/src/fmt/mod.rs b/core/src/fmt/mod.rs index ec7c1705fb860..580f95eddce71 100644 --- a/core/src/fmt/mod.rs +++ b/core/src/fmt/mod.rs @@ -7,7 +7,7 @@ use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8}; use crate::marker::PhantomData; use crate::num::fmt as numfmt; use crate::ops::Deref; -use crate::{iter, mem, result, str}; +use crate::{iter, result, str}; mod builders; #[cfg(not(no_fp_fmt_parse))] @@ -1515,19 +1515,6 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume // which guarantees the indexes are always within bounds. unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) }; - #[cfg(bootstrap)] - let options = - *FormattingOptions { flags: flags::ALWAYS_SET | arg.flags << 21, width: 0, precision: 0 } - .align(match arg.align { - rt::Alignment::Left => Some(Alignment::Left), - rt::Alignment::Right => Some(Alignment::Right), - rt::Alignment::Center => Some(Alignment::Center), - rt::Alignment::Unknown => None, - }) - .fill(arg.fill) - .width(width) - .precision(precision); - #[cfg(not(bootstrap))] let options = FormattingOptions { flags: arg.flags, width, precision }; // Extract the correct argument @@ -1544,21 +1531,6 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume unsafe { value.fmt(fmt) } } -#[cfg(bootstrap)] -unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { - match *cnt { - rt::Count::Is(n) => Some(n as u16), - rt::Count::Implied => None, - rt::Count::Param(i) => { - debug_assert!(i < args.len()); - // SAFETY: cnt and args come from the same Arguments, - // which guarantees this index is always within bounds. - unsafe { args.get_unchecked(i).as_u16() } - } - } -} - -#[cfg(not(bootstrap))] unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 { match *cnt { rt::Count::Is(n) => n, diff --git a/core/src/fmt/rt.rs b/core/src/fmt/rt.rs index 0b04ebccae2bd..adcfdd309b7e8 100644 --- a/core/src/fmt/rt.rs +++ b/core/src/fmt/rt.rs @@ -11,10 +11,6 @@ use crate::ptr::NonNull; #[derive(Copy, Clone)] pub struct Placeholder { pub position: usize, - #[cfg(bootstrap)] - pub fill: char, - #[cfg(bootstrap)] - pub align: Alignment, pub flags: u32, pub precision: Count, pub width: Count, @@ -23,38 +19,17 @@ pub struct Placeholder { #[cfg(bootstrap)] impl Placeholder { #[inline] - pub const fn new( - position: usize, - fill: char, - align: Alignment, - flags: u32, - precision: Count, - width: Count, - ) -> Self { - Self { position, fill, align, flags, precision, width } + pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self { + Self { position, flags, precision, width } } } -#[cfg(bootstrap)] -#[lang = "format_alignment"] -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum Alignment { - Left, - Right, - Center, - Unknown, -} - /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) /// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. #[lang = "format_count"] #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value - #[cfg(bootstrap)] - Is(usize), - /// Specified with a literal number, stores the value - #[cfg(not(bootstrap))] Is(u16), /// Specified using `$` and `*` syntaxes, stores the index into `args` Param(usize), @@ -90,61 +65,92 @@ pub struct Argument<'a> { ty: ArgumentType<'a>, } -#[rustc_diagnostic_item = "ArgumentMethods"] -impl Argument<'_> { - #[inline] - const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { +macro_rules! argument_new { + ($t:ty, $x:expr, $f:expr) => { Argument { // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { - value: NonNull::from_ref(x).cast(), - // SAFETY: function pointers always have the same layout. - formatter: unsafe { mem::transmute(f) }, + value: NonNull::<$t>::from_ref($x).cast(), + // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to + // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed. + // However, the CFI sanitizer does not allow this, and triggers a crash when it + // happens. + // + // To avoid this crash, we use a helper function when CFI is enabled. To avoid the + // cost of this helper function (mainly code-size) when it is not needed, we + // transmute the function pointer otherwise. + // + // This is similar to what the Rust compiler does internally with vtables when KCFI + // is enabled, where it generates trampoline functions that only serve to adjust the + // expected type of the argument. `ArgumentType::Placeholder` is a bit like a + // manually constructed trait object, so it is not surprising that the same approach + // has to be applied here as well. + // + // It is still considered problematic (from the Rust side) that CFI rejects entirely + // legal Rust programs, so we do not consider anything done here a stable guarantee, + // but meanwhile we carry this work-around to keep Rust compatible with CFI and + // KCFI. + #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))] + formatter: { + let f: fn(&$t, &mut Formatter<'_>) -> Result = $f; + // SAFETY: This is only called with `value`, which has the right type. + unsafe { core::mem::transmute(f) } + }, + #[cfg(any(sanitize = "cfi", sanitize = "kcfi"))] + formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| { + let func = $f; + // SAFETY: This is the same type as the `value` field. + let r = unsafe { ptr.cast::<$t>().as_ref() }; + (func)(r, fmt) + }, _lifetime: PhantomData, }, } - } + }; +} +#[rustc_diagnostic_item = "ArgumentMethods"] +impl Argument<'_> { #[inline] pub fn new_display(x: &T) -> Argument<'_> { - Self::new(x, Display::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_debug(x: &T) -> Argument<'_> { - Self::new(x, Debug::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_debug_noop(x: &T) -> Argument<'_> { - Self::new(x, |_, _| Ok(())) + argument_new!(T, x, |_: &T, _| Ok(())) } #[inline] pub fn new_octal(x: &T) -> Argument<'_> { - Self::new(x, Octal::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_lower_hex(x: &T) -> Argument<'_> { - Self::new(x, LowerHex::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_upper_hex(x: &T) -> Argument<'_> { - Self::new(x, UpperHex::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_pointer(x: &T) -> Argument<'_> { - Self::new(x, Pointer::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_binary(x: &T) -> Argument<'_> { - Self::new(x, Binary::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_lower_exp(x: &T) -> Argument<'_> { - Self::new(x, LowerExp::fmt) + argument_new!(T, x, ::fmt) } #[inline] pub fn new_upper_exp(x: &T) -> Argument<'_> { - Self::new(x, UpperExp::fmt) + argument_new!(T, x, ::fmt) } #[inline] #[track_caller] @@ -160,11 +166,6 @@ impl Argument<'_> { /// # Safety /// /// This argument must actually be a placeholder argument. - /// - // FIXME: Transmuting formatter in new and indirectly branching to/calling - // it here is an explicit CFI violation. - #[allow(inline_no_sanitize)] - #[no_sanitize(cfi, kcfi)] #[inline] pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.ty { diff --git a/core/src/hint.rs b/core/src/hint.rs index 5ce282b05de73..1ca23ab6eea66 100644 --- a/core/src/hint.rs +++ b/core/src/hint.rs @@ -4,6 +4,7 @@ //! //! Hints may be compile time or runtime. +use crate::mem::MaybeUninit; use crate::{intrinsics, ub_checks}; /// Informs the compiler that the site which is calling this function is not @@ -734,3 +735,63 @@ pub const fn unlikely(b: bool) -> bool { pub const fn cold_path() { crate::intrinsics::cold_path() } + +/// Returns either `true_val` or `false_val` depending on the value of +/// `condition`, with a hint to the compiler that `condition` is unlikely to be +/// correctly predicted by a CPU’s branch predictor. +/// +/// This method is functionally equivalent to +/// ```ignore (this is just for illustrative purposes) +/// fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { +/// if b { true_val } else { false_val } +/// } +/// ``` +/// but might generate different assembly. In particular, on platforms with +/// a conditional move or select instruction (like `cmov` on x86 or `csel` +/// on ARM) the optimizer might use these instructions to avoid branches, +/// which can benefit performance if the branch predictor is struggling +/// with predicting `condition`, such as in an implementation of binary +/// search. +/// +/// Note however that this lowering is not guaranteed (on any platform) and +/// should not be relied upon when trying to write cryptographic constant-time +/// code. Also be aware that this lowering might *decrease* performance if +/// `condition` is well-predictable. It is advisable to perform benchmarks to +/// tell if this function is useful. +/// +/// # Examples +/// +/// Distribute values evenly between two buckets: +/// ``` +/// #![feature(select_unpredictable)] +/// +/// use std::hash::BuildHasher; +/// use std::hint; +/// +/// fn append(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { +/// let hash = hasher.hash_one(&v); +/// let bucket = hint::select_unpredictable(hash % 2 == 0, bucket_one, bucket_two); +/// bucket.push(v); +/// } +/// # let hasher = std::collections::hash_map::RandomState::new(); +/// # let mut bucket_one = Vec::new(); +/// # let mut bucket_two = Vec::new(); +/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two); +/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); +/// ``` +#[inline(always)] +#[unstable(feature = "select_unpredictable", issue = "133962")] +pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { + // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): + // Change this to use ManuallyDrop instead. + let mut true_val = MaybeUninit::new(true_val); + let mut false_val = MaybeUninit::new(false_val); + // SAFETY: The value that is not selected is dropped, and the selected one + // is returned. This is necessary because the intrinsic doesn't drop the + // value that is not selected. + unsafe { + crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val) + .assume_init_drop(); + crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init() + } +} diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index afd6192d7c473..a01efb2adebe3 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -5,14 +5,11 @@ //! //! # Const intrinsics //! -//! Note: any changes to the constness of intrinsics should be discussed with the language team. -//! This includes changes in the stability of the constness. -//! -//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" -//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the -//! implementation from to +//! In order to make an intrinsic unstable usable at compile-time, copy the implementation from +//! to //! -//! and make the intrinsic declaration a `const fn`. +//! and make the intrinsic declaration below a `const fn`. This should be done in coordination with +//! wg-const-eval. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires @@ -1329,7 +1326,9 @@ pub const fn unlikely(b: bool) -> bool { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The public form of this instrinsic is [`bool::select_unpredictable`]. +/// The public form of this instrinsic is [`core::hint::select_unpredictable`]. +/// However unlike the public form, the intrinsic will not drop the value that +/// is not selected. #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -2307,20 +2306,8 @@ pub unsafe fn truncf128(x: f128) -> f128; /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f16(x: f16) -> f16; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f16(x: f16) -> f16 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf16(x: f16) -> f16; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf16(x) } -} - /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number with an even /// least significant digit. /// @@ -2328,20 +2315,8 @@ pub fn round_ties_even_f16(x: f16) -> f16 { /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f32(x: f32) -> f32; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f32(x: f32) -> f32 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf32(x: f32) -> f32; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf32(x) } -} - /// Provided for compatibility with stdarch. DO NOT USE. #[inline(always)] pub unsafe fn rintf32(x: f32) -> f32 { @@ -2355,20 +2330,8 @@ pub unsafe fn rintf32(x: f32) -> f32 { /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f64(x: f64) -> f64; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f64(x: f64) -> f64 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf64(x: f64) -> f64; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf64(x) } -} - /// Provided for compatibility with stdarch. DO NOT USE. #[inline(always)] pub unsafe fn rintf64(x: f64) -> f64 { @@ -2382,20 +2345,8 @@ pub unsafe fn rintf64(x: f64) -> f64 { /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn round_ties_even_f128(x: f128) -> f128; -/// To be removed on next bootstrap bump. -#[cfg(bootstrap)] -pub fn round_ties_even_f128(x: f128) -> f128 { - #[rustc_intrinsic] - #[rustc_nounwind] - unsafe fn rintf128(x: f128) -> f128; - - // SAFETY: this intrinsic isn't actually unsafe - unsafe { rintf128(x) } -} - /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is @@ -2679,13 +2630,15 @@ pub const fn bswap(x: T) -> T; #[rustc_intrinsic] pub const fn bitreverse(x: T) -> T; -/// Does a three-way comparison between the two integer arguments. +/// Does a three-way comparison between the two arguments, +/// which must be of character or integer (signed or unsigned) type. /// -/// This is included as an intrinsic as it's useful to let it be one thing -/// in MIR, rather than the multiple checks and switches that make its IR -/// large and difficult to optimize. +/// This was originally added because it greatly simplified the MIR in `cmp` +/// implementations, and then LLVM 20 added a backend intrinsic for it too. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. +#[rustc_intrinsic_const_stable_indirect] +#[rustc_nounwind] #[rustc_intrinsic] pub const fn three_way_compare(lhs: T, rhss: T) -> crate::cmp::Ordering; @@ -2786,6 +2739,7 @@ pub const fn carrying_mul_add, /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// /// This intrinsic does not have a stable counterpart. +#[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] pub const unsafe fn exact_div(x: T, y: T) -> T; @@ -3450,20 +3404,62 @@ pub const fn contract_checks() -> bool { /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. -#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] +/// +/// Note that this function is a no-op during constant evaluation. +#[unstable(feature = "contracts_internals", issue = "128044")] +// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of +// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking +// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals` +#[rustc_const_unstable(feature = "contracts", issue = "128044")] #[lang = "contract_check_requires"] #[rustc_intrinsic] -pub fn contract_check_requires bool>(cond: C) { - if contract_checks() && !cond() { - // Emit no unwind panic in case this was a safety requirement. - crate::panicking::panic_nounwind("failed requires check"); - } +pub const fn contract_check_requires bool + Copy>(cond: C) { + const_eval_select!( + @capture[C: Fn() -> bool + Copy] { cond: C } : + if const { + // Do nothing + } else { + if contract_checks() && !cond() { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed requires check"); + } + } + ) } /// Check if the post-condition `cond` has been met. /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. +/// +/// Note that this function is a no-op during constant evaluation. +#[cfg(not(bootstrap))] +#[unstable(feature = "contracts_internals", issue = "128044")] +// Similar to `contract_check_requires`, we need to use the user-facing +// `contracts` feature rather than the perma-unstable `contracts_internals`. +// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion. +#[rustc_const_unstable(feature = "contracts", issue = "128044")] +#[lang = "contract_check_ensures"] +#[rustc_intrinsic] +pub const fn contract_check_ensures bool + Copy, Ret>(cond: C, ret: Ret) -> Ret { + const_eval_select!( + @capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret : + if const { + // Do nothing + ret + } else { + if contract_checks() && !cond(&ret) { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed ensures check"); + } + ret + } + ) +} + +/// This is the old version of contract_check_ensures kept here for bootstrap only. +#[cfg(bootstrap)] #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { @@ -3723,7 +3719,7 @@ pub const fn ptr_metadata + ?Sized, M>(ptr: *const /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -3826,7 +3822,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -3906,7 +3902,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces diff --git a/core/src/intrinsics/simd.rs b/core/src/intrinsics/simd.rs index ae6e1a779ed58..9ac6ee8553558 100644 --- a/core/src/intrinsics/simd.rs +++ b/core/src/intrinsics/simd.rs @@ -4,7 +4,7 @@ /// Inserts an element into a vector, returning the updated vector. /// -/// `T` must be a vector with element type `U`. +/// `T` must be a vector with element type `U`, and `idx` must be `const`. /// /// # Safety /// @@ -15,15 +15,48 @@ pub const unsafe fn simd_insert(x: T, idx: u32, val: U) -> T; /// Extracts an element from a vector. /// -/// `T` must be a vector with element type `U`. +/// `T` must be a vector with element type `U`, and `idx` must be `const`. /// /// # Safety /// -/// `idx` must be in-bounds of the vector. +/// `idx` must be const and in-bounds of the vector. #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn simd_extract(x: T, idx: u32) -> U; +/// Inserts an element into a vector, returning the updated vector. +/// +/// `T` must be a vector with element type `U`. +/// +/// If the index is `const`, [`simd_insert`] may emit better assembly. +/// +/// # Safety +/// +/// `idx` must be in-bounds of the vector. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub unsafe fn simd_insert_dyn(mut x: T, idx: u32, val: U) -> T { + // SAFETY: `idx` must be in-bounds + unsafe { (&raw mut x).cast::().add(idx as usize).write(val) } + x +} + +/// Extracts an element from a vector. +/// +/// `T` must be a vector with element type `U`. +/// +/// If the index is `const`, [`simd_extract`] may emit better assembly. +/// +/// # Safety +/// +/// `idx` must be in-bounds of the vector. +#[rustc_nounwind] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +pub unsafe fn simd_extract_dyn(x: T, idx: u32) -> U { + // SAFETY: `idx` must be in-bounds + unsafe { (&raw const x).cast::().add(idx as usize).read() } +} + /// Adds two simd vectors elementwise. /// /// `T` must be a vector of integers or floats. diff --git a/core/src/iter/adapters/cloned.rs b/core/src/iter/adapters/cloned.rs index aea6d64281aec..72d746289711b 100644 --- a/core/src/iter/adapters/cloned.rs +++ b/core/src/iter/adapters/cloned.rs @@ -1,5 +1,6 @@ use core::num::NonZero; +use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; @@ -41,13 +42,31 @@ where self.it.next().cloned() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + #[inline] + fn count(self) -> usize { + self.it.count() + } + + fn last(self) -> Option { + self.it.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).cloned() + } + fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -61,6 +80,58 @@ where self.it.map(T::clone).fold(init, f) } + fn find

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.find(move |x| predicate(&x)).cloned() + } + + fn max_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.max_by(move |&x, &y| compare(x, y)).cloned() + } + + fn min_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.min_by(move |&x, &y| compare(x, y)).cloned() + } + + fn cmp(self, other: O) -> Ordering + where + O: IntoIterator, + Self::Item: Ord, + { + self.it.cmp_by(other, |x, y| x.cmp(&y)) + } + + fn partial_cmp(self, other: O) -> Option + where + O: IntoIterator, + Self::Item: PartialOrd, + { + self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + fn eq(self, other: O) -> bool + where + O: IntoIterator, + Self::Item: PartialEq, + { + self.it.eq_by(other, |x, y| x == &y) + } + + fn is_sorted_by(self, mut compare: F) -> bool + where + F: FnMut(&Self::Item, &Self::Item) -> bool, + { + self.it.is_sorted_by(move |&x, &y| compare(x, y)) + } + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, @@ -81,9 +152,13 @@ where self.it.next_back().cloned() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) + } + fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -96,6 +171,13 @@ where { self.it.map(T::clone).rfold(init, f) } + + fn rfind

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.rfind(move |x| predicate(&x)).cloned() + } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -104,10 +186,12 @@ where I: ExactSizeIterator, T: Clone, { + #[inline] fn len(&self) -> usize { self.it.len() } + #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/core/src/iter/adapters/copied.rs b/core/src/iter/adapters/copied.rs index 23e4e25ab5388..73913aa34a9e8 100644 --- a/core/src/iter/adapters/copied.rs +++ b/core/src/iter/adapters/copied.rs @@ -1,3 +1,4 @@ +use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; @@ -48,20 +49,35 @@ where fn next_chunk( &mut self, - ) -> Result<[Self::Item; N], array::IntoIter> - where - Self: Sized, - { + ) -> Result<[Self::Item; N], array::IntoIter> { >::spec_next_chunk(&mut self.it) } + #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + #[inline] + fn count(self) -> usize { + self.it.count() + } + + fn last(self) -> Option { + self.it.last().copied() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() + } + fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -75,21 +91,56 @@ where self.it.fold(init, copy_fold(f)) } - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() + fn find

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.find(move |x| predicate(&x)).copied() } - fn last(self) -> Option { - self.it.last().copied() + fn max_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.max_by(move |&x, &y| compare(x, y)).copied() } - fn count(self) -> usize { - self.it.count() + fn min_by(self, mut compare: F) -> Option + where + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + self.it.min_by(move |&x, &y| compare(x, y)).copied() } - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) + fn cmp(self, other: O) -> Ordering + where + O: IntoIterator, + Self::Item: Ord, + { + self.it.cmp_by(other, |x, y| x.cmp(&y)) + } + + fn partial_cmp(self, other: O) -> Option + where + O: IntoIterator, + Self::Item: PartialOrd, + { + self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + } + + fn eq(self, other: O) -> bool + where + O: IntoIterator, + Self::Item: PartialEq, + { + self.it.eq_by(other, |x, y| x == &y) + } + + fn is_sorted_by(self, mut compare: F) -> bool + where + F: FnMut(&Self::Item, &Self::Item) -> bool, + { + self.it.is_sorted_by(move |&x, &y| compare(x, y)) } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T @@ -112,9 +163,13 @@ where self.it.next_back().copied() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) + } + fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -128,9 +183,11 @@ where self.it.rfold(init, copy_fold(f)) } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) + fn rfind

(&mut self, mut predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.it.rfind(move |x| predicate(&x)).copied() } } @@ -140,10 +197,12 @@ where I: ExactSizeIterator, T: Copy, { + #[inline] fn len(&self) -> usize { self.it.len() } + #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/core/src/iter/adapters/enumerate.rs b/core/src/iter/adapters/enumerate.rs index f9c388e8564d3..bd093e279c38e 100644 --- a/core/src/iter/adapters/enumerate.rs +++ b/core/src/iter/adapters/enumerate.rs @@ -36,7 +36,7 @@ where /// /// The method does no guarding against overflows, so enumerating more than /// `usize::MAX` elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. + /// overflow checks are enabled, a panic is guaranteed. /// /// # Panics /// diff --git a/core/src/iter/traits/iterator.rs b/core/src/iter/traits/iterator.rs index 3bbb52fdbcb5f..d9534a445980f 100644 --- a/core/src/iter/traits/iterator.rs +++ b/core/src/iter/traits/iterator.rs @@ -199,7 +199,7 @@ pub trait Iterator { /// /// The method does no guarding against overflows, so counting elements of /// an iterator with more than [`usize::MAX`] elements either produces the - /// wrong result or panics. If debug assertions are enabled, a panic is + /// wrong result or panics. If overflow checks are enabled, a panic is /// guaranteed. /// /// # Panics @@ -931,7 +931,7 @@ pub trait Iterator { /// /// The method does no guarding against overflows, so enumerating more than /// [`usize::MAX`] elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. + /// overflow checks are enabled, a panic is guaranteed. /// /// # Panics /// @@ -2964,7 +2964,7 @@ pub trait Iterator { /// /// The method does no guarding against overflows, so if there are more /// than [`usize::MAX`] non-matching elements, it either produces the wrong - /// result or panics. If debug assertions are enabled, a panic is + /// result or panics. If overflow checks are enabled, a panic is /// guaranteed. /// /// # Panics @@ -3516,7 +3516,7 @@ pub trait Iterator { /// # Panics /// /// When calling `sum()` and a primitive integer type is being returned, this - /// method will panic if the computation overflows and debug assertions are + /// method will panic if the computation overflows and overflow checks are /// enabled. /// /// # Examples @@ -3550,7 +3550,7 @@ pub trait Iterator { /// # Panics /// /// When calling `product()` and a primitive integer type is being returned, - /// method will panic if the computation overflows and debug assertions are + /// method will panic if the computation overflows and overflow checks are /// enabled. /// /// # Examples diff --git a/core/src/lib.rs b/core/src/lib.rs index dc06aa4c38d55..9625475e617ea 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -101,7 +101,6 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(cfg_match)] -#![feature(closure_track_caller)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -127,6 +126,7 @@ #![feature(ub_checks)] #![feature(unchecked_neg)] #![feature(unchecked_shifts)] +#![feature(unsafe_pinned)] #![feature(utf16_extra)] #![feature(variant_count)] // tidy-alphabetical-end @@ -169,7 +169,6 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(no_core)] -#![feature(no_sanitize)] #![feature(optimize_attribute)] #![feature(prelude_import)] #![feature(repr_simd)] diff --git a/core/src/macros/mod.rs b/core/src/macros/mod.rs index 5f200b31d1ae7..330b409876453 100644 --- a/core/src/macros/mod.rs +++ b/core/src/macros/mod.rs @@ -237,9 +237,10 @@ pub macro assert_matches { /// ``` #[unstable(feature = "cfg_match", issue = "115585")] #[rustc_diagnostic_item = "cfg_match"] +#[rustc_macro_transparency = "semitransparent"] pub macro cfg_match { ({ $($tt:tt)* }) => {{ - cfg_match! { $($tt)* } + $crate::cfg_match! { $($tt)* } }}, (_ => { $($output:tt)* }) => { $($output)* @@ -249,10 +250,10 @@ pub macro cfg_match { $($( $rest:tt )+)? ) => { #[cfg($cfg)] - cfg_match! { _ => $output } + $crate::cfg_match! { _ => $output } $( #[cfg(not($cfg))] - cfg_match! { $($rest)+ } + $crate::cfg_match! { $($rest)+ } )? }, } @@ -1753,7 +1754,6 @@ pub(crate) mod builtin { reason = "`type_alias_impl_trait` has open design concerns" )] #[rustc_builtin_macro] - #[cfg(not(bootstrap))] pub macro define_opaque($($tt:tt)*) { /* compiler built-in */ } diff --git a/core/src/marker.rs b/core/src/marker.rs index 68011310d2cad..9dc20beda6c64 100644 --- a/core/src/marker.rs +++ b/core/src/marker.rs @@ -17,6 +17,7 @@ use crate::cell::UnsafeCell; use crate::cmp; use crate::fmt::Debug; use crate::hash::{Hash, Hasher}; +use crate::pin::UnsafePinned; /// Implements a given marker trait for multiple types at the same time. /// @@ -878,6 +879,23 @@ marker_impls! { {T: ?Sized} &mut T, } +/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally, +/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata +/// for `&mut T` or not. +/// +/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is +/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735). +#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")] +#[cfg_attr(bootstrap, allow(dead_code))] +pub(crate) unsafe auto trait UnsafeUnpin {} + +impl !UnsafeUnpin for UnsafePinned {} +unsafe impl UnsafeUnpin for PhantomData {} +unsafe impl UnsafeUnpin for *const T {} +unsafe impl UnsafeUnpin for *mut T {} +unsafe impl UnsafeUnpin for &T {} +unsafe impl UnsafeUnpin for &mut T {} + /// Types that do not require any pinning guarantees. /// /// For information on what "pinning" is, see the [`pin` module] documentation. @@ -953,6 +971,11 @@ pub auto trait Unpin {} /// A marker type which does not implement `Unpin`. /// /// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default. +// +// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet. +// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this +// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type +// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead. #[stable(feature = "pin", since = "1.33.0")] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PhantomPinned; @@ -960,6 +983,12 @@ pub struct PhantomPinned; #[stable(feature = "pin", since = "1.33.0")] impl !Unpin for PhantomPinned {} +// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to +// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same +// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking +// change. +impl !UnsafeUnpin for PhantomPinned {} + marker_impls! { #[stable(feature = "pin", since = "1.33.0")] Unpin for diff --git a/core/src/net/socket_addr.rs b/core/src/net/socket_addr.rs index 21753d0092497..936f9f64930d5 100644 --- a/core/src/net/socket_addr.rs +++ b/core/src/net/socket_addr.rs @@ -210,7 +210,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { @@ -254,7 +254,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), @@ -360,7 +360,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_ip(&mut self, new_ip: Ipv4Addr) { self.ip = new_ip; } @@ -396,7 +396,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -458,7 +458,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_ip(&mut self, new_ip: Ipv6Addr) { self.ip = new_ip; } @@ -494,7 +494,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -542,7 +542,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flowinfo = new_flowinfo; } @@ -585,7 +585,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "1.87.0")] pub const fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } diff --git a/core/src/num/f128.rs b/core/src/num/f128.rs index 08c34e852da41..d3d1eebc22753 100644 --- a/core/src/num/f128.rs +++ b/core/src/num/f128.rs @@ -224,14 +224,16 @@ impl f128 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[allow(clippy::eq_op)] #[rustc_diagnostic_item = "f128_nan"] #[unstable(feature = "f128", issue = "116909")] diff --git a/core/src/num/f16.rs b/core/src/num/f16.rs index a33e5f5301469..dceb30177e668 100644 --- a/core/src/num/f16.rs +++ b/core/src/num/f16.rs @@ -219,14 +219,16 @@ impl f16 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[allow(clippy::eq_op)] #[rustc_diagnostic_item = "f16_nan"] #[unstable(feature = "f16", issue = "116909")] diff --git a/core/src/num/f32.rs b/core/src/num/f32.rs index e473fac03935a..c97dbfb63ae17 100644 --- a/core/src/num/f32.rs +++ b/core/src/num/f32.rs @@ -470,14 +470,16 @@ impl f32 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[stable(feature = "assoc_int_consts", since = "1.43.0")] #[rustc_diagnostic_item = "f32_nan"] #[allow(clippy::eq_op)] diff --git a/core/src/num/f64.rs b/core/src/num/f64.rs index 6522a80b0b7e8..91affdb3794b0 100644 --- a/core/src/num/f64.rs +++ b/core/src/num/f64.rs @@ -469,14 +469,16 @@ impl f64 { /// Not a Number (NaN). /// - /// Note that IEEE 754 doesn't define just a single NaN value; - /// a plethora of bit patterns are considered to be NaN. - /// Furthermore, the standard makes a difference - /// between a "signaling" and a "quiet" NaN, - /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). - /// This constant isn't guaranteed to equal to any specific NaN bitpattern, - /// and the stability of its representation over Rust versions - /// and target platforms isn't guaranteed. + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. #[rustc_diagnostic_item = "f64_nan"] #[stable(feature = "assoc_int_consts", since = "1.43.0")] #[allow(clippy::eq_op)] diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index a72ca4bcb059b..05d8216ac27eb 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -244,8 +244,8 @@ macro_rules! int_impl { /// #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1355,8 +1355,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1478,8 +1478,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3571,10 +3571,7 @@ macro_rules! int_impl { // so delegate it to `Ord` which is already producing -1/0/+1 // exactly like we need and can be the place to deal with the complexity. - // FIXME(const-hack): replace with cmp - if self < 0 { -1 } - else if self == 0 { 0 } - else { 1 } + crate::intrinsics::three_way_compare(self, 0) as Self } /// Returns `true` if `self` is positive and `false` if the number is zero or diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 151e128cd78a9..348457e2c00f6 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -99,8 +99,8 @@ macro_rules! i8_xe_bytes_doc { **Note**: This function is meaningless on `i8`. Byte order does not exist as a concept for byte-sized integers. This function is only provided in symmetry -with larger integer types. You can cast from and to `u8` using `as i8` and `as -u8`. +with larger integer types. You can cast from and to `u8` using +[`cast_signed`](u8::cast_signed) and [`cast_unsigned`](Self::cast_unsigned). " }; @@ -169,8 +169,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint_signed", since = "1.87.0")] + #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -221,8 +221,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] /// ``` - #[stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint_signed", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint_signed", since = "1.87.0")] + #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/core/src/num/nonzero.rs b/core/src/num/nonzero.rs index 7585ec140e31e..1b79112aec1fe 100644 --- a/core/src/num/nonzero.rs +++ b/core/src/num/nonzero.rs @@ -1704,8 +1704,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// #[doc = concat!("assert_eq!(n.cast_signed(), NonZero::new(-1", stringify!($Sint), ").unwrap());")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -2143,8 +2143,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// #[doc = concat!("assert_eq!(n.cast_unsigned(), NonZero::<", stringify!($Uint), ">::MAX);")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/core/src/num/uint_macros.rs b/core/src/num/uint_macros.rs index 586892758398b..3678bb091e7d0 100644 --- a/core/src/num/uint_macros.rs +++ b/core/src/num/uint_macros.rs @@ -273,8 +273,8 @@ macro_rules! uint_impl { /// #[doc = concat!("assert_eq!(n.cast_signed(), -1", stringify!($SignedT), ");")] /// ``` - #[stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "integer_sign_cast", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "integer_sign_cast", since = "1.87.0")] + #[rustc_const_stable(feature = "integer_sign_cast", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1616,8 +1616,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1737,8 +1737,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] /// ``` - #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unbounded_shifts", since = "1.87.0")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3331,8 +3331,8 @@ macro_rules! uint_impl { #[doc = concat!("assert!(0_", stringify!($SelfT), ".is_multiple_of(0));")] #[doc = concat!("assert!(!6_", stringify!($SelfT), ".is_multiple_of(0));")] /// ``` - #[stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_is_multiple_of", since = "1.87.0")] + #[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "1.87.0")] #[must_use] #[inline] #[rustc_inherit_overflow_checks] @@ -3343,7 +3343,7 @@ macro_rules! uint_impl { } } - /// Returns `true` if and only if `self == 2^k` for some `k`. + /// Returns `true` if and only if `self == 2^k` for some unsigned integer `k`. /// /// # Examples /// diff --git a/core/src/ops/index_range.rs b/core/src/ops/index_range.rs index b82184b15b2f5..c645c996eb707 100644 --- a/core/src/ops/index_range.rs +++ b/core/src/ops/index_range.rs @@ -1,5 +1,6 @@ use crate::iter::{FusedIterator, TrustedLen}; use crate::num::NonZero; +use crate::ops::{NeverShortCircuit, Try}; use crate::ub_checks; /// Like a `Range`, but with a safety invariant that `start <= end`. @@ -112,6 +113,12 @@ impl IndexRange { self.end = mid; suffix } + + #[inline] + fn assume_range(&self) { + // SAFETY: This is the type invariant + unsafe { crate::hint::assert_unchecked(self.start <= self.end) } + } } impl Iterator for IndexRange { @@ -138,6 +145,30 @@ impl Iterator for IndexRange { let taken = self.take_prefix(n); NonZero::new(n - taken.len()).map_or(Ok(()), Err) } + + #[inline] + fn fold B>(mut self, init: B, f: F) -> B { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + fn try_fold(&mut self, mut accum: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + // `Range` needs to check `start < end`, but thanks to our type invariant + // we can loop on the stricter `start != end`. + + self.assume_range(); + while self.start != self.end { + // SAFETY: We just checked that the range is non-empty + let i = unsafe { self.next_unchecked() }; + accum = f(accum, i)?; + } + try { accum } + } } impl DoubleEndedIterator for IndexRange { @@ -156,6 +187,30 @@ impl DoubleEndedIterator for IndexRange { let taken = self.take_suffix(n); NonZero::new(n - taken.len()).map_or(Ok(()), Err) } + + #[inline] + fn rfold B>(mut self, init: B, f: F) -> B { + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + fn try_rfold(&mut self, mut accum: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + // `Range` needs to check `start < end`, but thanks to our type invariant + // we can loop on the stricter `start != end`. + + self.assume_range(); + while self.start != self.end { + // SAFETY: We just checked that the range is non-empty + let i = unsafe { self.next_back_unchecked() }; + accum = f(accum, i)?; + } + try { accum } + } } impl ExactSizeIterator for IndexRange { diff --git a/core/src/pat.rs b/core/src/pat.rs index f8826096df3e1..91d015b1bc53f 100644 --- a/core/src/pat.rs +++ b/core/src/pat.rs @@ -25,15 +25,15 @@ macro_rules! pattern_type { )] pub trait RangePattern { /// Trait version of the inherent `MIN` assoc const. - #[cfg_attr(not(bootstrap), lang = "RangeMin")] + #[lang = "RangeMin"] const MIN: Self; /// Trait version of the inherent `MIN` assoc const. - #[cfg_attr(not(bootstrap), lang = "RangeMax")] + #[lang = "RangeMax"] const MAX: Self; /// A compile-time helper to subtract 1 for exclusive ranges. - #[cfg_attr(not(bootstrap), lang = "RangeSub")] + #[lang = "RangeSub"] #[track_caller] fn sub_one(self) -> Self; } diff --git a/core/src/pin.rs b/core/src/pin.rs index bc097bf198d03..48ed5ae451e40 100644 --- a/core/src/pin.rs +++ b/core/src/pin.rs @@ -931,6 +931,11 @@ use crate::{ }; use crate::{cmp, fmt}; +mod unsafe_pinned; + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +pub use self::unsafe_pinned::UnsafePinned; + /// A pointer which pins its pointee in place. /// /// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its @@ -1943,7 +1948,7 @@ unsafe impl PinCoerceUnsized for *mut T {} #[stable(feature = "pin_macro", since = "1.68.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(unsafe_pin_internals)] -#[cfg_attr(not(bootstrap), rustc_macro_edition_2021)] +#[rustc_macro_edition_2021] 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): diff --git a/core/src/pin/unsafe_pinned.rs b/core/src/pin/unsafe_pinned.rs new file mode 100644 index 0000000000000..5fb628c8adbc5 --- /dev/null +++ b/core/src/pin/unsafe_pinned.rs @@ -0,0 +1,197 @@ +use crate::marker::{PointerLike, Unpin}; +use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::pin::Pin; +use crate::{fmt, ptr}; + +/// This type provides a way to opt-out of typical aliasing rules; +/// specifically, `&mut UnsafePinned` is not guaranteed to be a unique pointer. +/// +/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still +/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work +/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as +/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate +/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not +/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness. +/// +/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in +/// the public API of a library. It is an internal implementation detail of libraries that need to +/// support aliasing mutable references. +/// +/// Further note that this does *not* lift the requirement that shared references must be read-only! +/// Use `UnsafeCell` for that. +/// +/// This type blocks niches the same way `UnsafeCell` does. +#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")] +#[repr(transparent)] +#[unstable(feature = "unsafe_pinned", issue = "125735")] +pub struct UnsafePinned { + value: T, +} + +/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the +/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt +/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned. +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl !Unpin for UnsafePinned {} + +/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no +/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean +/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that +/// leaves the user more choices (as they can always wrap this in a `!Copy` type). +// FIXME(unsafe_pinned): this may be unsound or a footgun? +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Copy for UnsafePinned {} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Clone for UnsafePinned { + fn clone(&self) -> Self { + *self + } +} + +// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since +// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes +// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit +// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`. + +impl UnsafePinned { + /// Constructs a new instance of `UnsafePinned` which will wrap the specified value. + /// + /// All access to the inner value through `&UnsafePinned` or `&mut UnsafePinned` or + /// `Pin<&mut UnsafePinned>` requires `unsafe` code. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn new(value: T) -> Self { + UnsafePinned { value } + } + + /// Unwraps the value, consuming this `UnsafePinned`. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + pub const fn into_inner(self) -> T { + self.value + } +} + +impl UnsafePinned { + /// Get read-write access to the contents of a pinned `UnsafePinned`. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T { + // SAFETY: we're not using `get_unchecked_mut` to unpin anything + unsafe { self.get_unchecked_mut() }.get_mut_unchecked() + } + + /// Get read-write access to the contents of an `UnsafePinned`. + /// + /// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this + /// memory is "pinned" due to there being aliases. + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get_mut_unchecked(&mut self) -> *mut T { + ptr::from_mut(self) as *mut T + } + + /// Get read-only access to the contents of a shared `UnsafePinned`. + /// + /// Note that `&UnsafePinned` is read-only if `&T` is read-only. This means that if there is + /// mutation of the `T`, future reads from the `*const T` returned here are UB! Use + /// [`UnsafeCell`] if you also need interior mutability. + /// + /// [`UnsafeCell`]: crate::cell::UnsafeCell + /// + /// ```rust,no_run + /// #![feature(unsafe_pinned)] + /// use std::pin::UnsafePinned; + /// + /// unsafe { + /// let mut x = UnsafePinned::new(0); + /// let ptr = x.get(); // read-only pointer, assumes immutability + /// x.get_mut_unchecked().write(1); + /// ptr.read(); // UB! + /// } + /// ``` + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn get(&self) -> *const T { + ptr::from_ref(self) as *const T + } + + /// Gets an immutable pointer to the wrapped value. + /// + /// The difference from [`get`] is that this function accepts a raw pointer, which is useful to + /// avoid the creation of temporary references. + /// + /// [`get`]: UnsafePinned::get + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn raw_get(this: *const Self) -> *const T { + this as *const T + } + + /// Gets a mutable pointer to the wrapped value. + /// + /// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function + /// accepts a raw pointer, which is useful to avoid the creation of temporary references. + /// + /// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned + /// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked + #[inline(always)] + #[must_use] + #[unstable(feature = "unsafe_pinned", issue = "125735")] + pub const fn raw_get_mut(this: *mut Self) -> *mut T { + this as *mut T + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl Default for UnsafePinned { + /// Creates an `UnsafePinned`, with the `Default` value for T. + fn default() -> Self { + UnsafePinned::new(T::default()) + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl From for UnsafePinned { + /// Creates a new `UnsafePinned` containing the given value. + fn from(value: T) -> Self { + UnsafePinned::new(value) + } +} + +#[unstable(feature = "unsafe_pinned", issue = "125735")] +impl fmt::Debug for UnsafePinned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UnsafePinned").finish_non_exhaustive() + } +} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl, U> CoerceUnsized> for UnsafePinned {} + +// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn` +// and become dyn-compatible method receivers. +// Note that currently `UnsafePinned` itself cannot be a method receiver +// because it does not implement Deref. +// In other words: +// `self: UnsafePinned<&Self>` won't work +// `self: UnsafePinned` becomes possible +// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound? +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl, U> DispatchFromDyn> for UnsafePinned {} + +#[unstable(feature = "pointer_like_trait", issue = "none")] +// #[unstable(feature = "unsafe_pinned", issue = "125735")] +impl PointerLike for UnsafePinned {} + +// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned? diff --git a/core/src/prelude/v1.rs b/core/src/prelude/v1.rs index c5975c0305031..8f1b5275871e6 100644 --- a/core/src/prelude/v1.rs +++ b/core/src/prelude/v1.rs @@ -117,5 +117,4 @@ pub use crate::macros::builtin::deref; issue = "63063", reason = "`type_alias_impl_trait` has open design concerns" )] -#[cfg(not(bootstrap))] pub use crate::macros::builtin::define_opaque; diff --git a/core/src/ptr/const_ptr.rs b/core/src/ptr/const_ptr.rs index 71a84aff24606..0854e31c19979 100644 --- a/core/src/ptr/const_ptr.rs +++ b/core/src/ptr/const_ptr.rs @@ -764,8 +764,8 @@ impl *const T { /// // This would be incorrect, as the pointers are not correctly ordered: /// // ptr1.offset_from_unsigned(ptr2) /// ``` - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize @@ -809,8 +809,8 @@ impl *const T { /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from_unsigned(self, origin: *const U) -> usize { diff --git a/core/src/ptr/mod.rs b/core/src/ptr/mod.rs index ea53da78d3bd2..445c789a7de20 100644 --- a/core/src/ptr/mod.rs +++ b/core/src/ptr/mod.rs @@ -278,7 +278,7 @@ //! ### Using Strict Provenance //! //! Most code needs no changes to conform to strict provenance, as the only really concerning -//! operation is casts from usize to a pointer. For code which *does* cast a `usize` to a pointer, +//! operation is casts from `usize` to a pointer. For code which *does* cast a `usize` to a pointer, //! the scope of the change depends on exactly what you're doing. //! //! In general, you just need to make sure that if you want to convert a `usize` address to a @@ -398,6 +398,7 @@ use crate::cmp::Ordering; use crate::intrinsics::const_eval_select; use crate::marker::FnPtr; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::num::NonZero; use crate::{fmt, hash, intrinsics, ub_checks}; mod alignment; @@ -1094,51 +1095,25 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { // are pointers inside `T` we will copy them in one go rather than trying to copy a part // of a pointer (which would not work). // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } + unsafe { swap_nonoverlapping_const(x, y, count) } } else { - macro_rules! attempt_swap_as_chunks { - ($ChunkTy:ty) => { - if align_of::() >= align_of::<$ChunkTy>() - && size_of::() % size_of::<$ChunkTy>() == 0 - { - let x: *mut $ChunkTy = x.cast(); - let y: *mut $ChunkTy = y.cast(); - let count = count * (size_of::() / size_of::<$ChunkTy>()); - // SAFETY: these are the same bytes that the caller promised were - // ok, just typed as `MaybeUninit`s instead of as `T`s. - // The `if` condition above ensures that we're not violating - // alignment requirements, and that the division is exact so - // that we don't lose any bytes off the end. - return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }; - } - }; + // Going though a slice here helps codegen know the size fits in `isize` + let slice = slice_from_raw_parts_mut(x, count); + // SAFETY: This is all readable from the pointer, meaning it's one + // allocated object, and thus cannot be more than isize::MAX bytes. + let bytes = unsafe { mem::size_of_val_raw::<[T]>(slice) }; + if let Some(bytes) = NonZero::new(bytes) { + // SAFETY: These are the same ranges, just expressed in a different + // type, so they're still non-overlapping. + unsafe { swap_nonoverlapping_bytes(x.cast(), y.cast(), bytes) }; } - - // Split up the slice into small power-of-two-sized chunks that LLVM is able - // to vectorize (unless it's a special type with more-than-pointer alignment, - // because we don't want to pessimize things like slices of SIMD vectors.) - if align_of::() <= size_of::() - && (!size_of::().is_power_of_two() - || size_of::() > size_of::() * 2) - { - attempt_swap_as_chunks!(usize); - attempt_swap_as_chunks!(u8); - } - - // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } } ) } /// Same behavior and safety conditions as [`swap_nonoverlapping`] -/// -/// LLVM can vectorize this (at least it can for the power-of-two-sized types -/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] -const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, count: usize) { - let x = x.cast::>(); - let y = y.cast::>(); +const unsafe fn swap_nonoverlapping_const(x: *mut T, y: *mut T, count: usize) { let mut i = 0; while i < count { // SAFETY: By precondition, `i` is in-bounds because it's below `n` @@ -1147,26 +1122,91 @@ const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, coun // and it's distinct from `x` since the ranges are non-overlapping let y = unsafe { y.add(i) }; - // If we end up here, it's because we're using a simple type -- like - // a small power-of-two-sized thing -- or a special type with particularly - // large alignment, particularly SIMD types. - // Thus, we're fine just reading-and-writing it, as either it's small - // and that works well anyway or it's special and the type's author - // presumably wanted things to be done in the larger chunk. - // SAFETY: we're only ever given pointers that are valid to read/write, // including being aligned, and nothing here panics so it's drop-safe. unsafe { - let a: MaybeUninit = read(x); - let b: MaybeUninit = read(y); - write(x, b); - write(y, a); + // Note that it's critical that these use `copy_nonoverlapping`, + // rather than `read`/`write`, to avoid #134713 if T has padding. + let mut temp = MaybeUninit::::uninit(); + copy_nonoverlapping(x, temp.as_mut_ptr(), 1); + copy_nonoverlapping(y, x, 1); + copy_nonoverlapping(temp.as_ptr(), y, 1); } i += 1; } } +// Don't let MIR inline this, because we really want it to keep its noalias metadata +#[rustc_no_mir_inline] +#[inline] +fn swap_chunk(x: &mut MaybeUninit<[u8; N]>, y: &mut MaybeUninit<[u8; N]>) { + let a = *x; + let b = *y; + *x = b; + *y = a; +} + +#[inline] +unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, bytes: NonZero) { + // Same as `swap_nonoverlapping::<[u8; N]>`. + unsafe fn swap_nonoverlapping_chunks( + x: *mut MaybeUninit<[u8; N]>, + y: *mut MaybeUninit<[u8; N]>, + chunks: NonZero, + ) { + let chunks = chunks.get(); + for i in 0..chunks { + // SAFETY: i is in [0, chunks) so the adds and dereferences are in-bounds. + unsafe { swap_chunk(&mut *x.add(i), &mut *y.add(i)) }; + } + } + + // Same as `swap_nonoverlapping_bytes`, but accepts at most 1+2+4=7 bytes + #[inline] + unsafe fn swap_nonoverlapping_short(x: *mut u8, y: *mut u8, bytes: NonZero) { + // Tail handling for auto-vectorized code sometimes has element-at-a-time behaviour, + // see . + // By swapping as different sizes, rather than as a loop over bytes, + // we make sure not to end up with, say, seven byte-at-a-time copies. + + let bytes = bytes.get(); + let mut i = 0; + macro_rules! swap_prefix { + ($($n:literal)+) => {$( + if (bytes & $n) != 0 { + // SAFETY: `i` can only have the same bits set as those in bytes, + // so these `add`s are in-bounds of `bytes`. But the bit for + // `$n` hasn't been set yet, so the `$n` bytes that `swap_chunk` + // will read and write are within the usable range. + unsafe { swap_chunk::<$n>(&mut*x.add(i).cast(), &mut*y.add(i).cast()) }; + i |= $n; + } + )+}; + } + swap_prefix!(4 2 1); + debug_assert_eq!(i, bytes); + } + + const CHUNK_SIZE: usize = size_of::<*const ()>(); + let bytes = bytes.get(); + + let chunks = bytes / CHUNK_SIZE; + let tail = bytes % CHUNK_SIZE; + if let Some(chunks) = NonZero::new(chunks) { + // SAFETY: this is bytes/CHUNK_SIZE*CHUNK_SIZE bytes, which is <= bytes, + // so it's within the range of our non-overlapping bytes. + unsafe { swap_nonoverlapping_chunks::(x.cast(), y.cast(), chunks) }; + } + if let Some(tail) = NonZero::new(tail) { + const { assert!(CHUNK_SIZE <= 8) }; + let delta = chunks * CHUNK_SIZE; + // SAFETY: the tail length is below CHUNK SIZE because of the remainder, + // and CHUNK_SIZE is at most 8 by the const assert, so tail <= 7 + unsafe { swap_nonoverlapping_short(x.add(delta), y.add(delta), tail) }; + } +} + /// Moves `src` into the pointed `dst`, returning the previous `dst` value. /// /// Neither value is dropped. diff --git a/core/src/ptr/mut_ptr.rs b/core/src/ptr/mut_ptr.rs index 9e62beb804927..e29774963db00 100644 --- a/core/src/ptr/mut_ptr.rs +++ b/core/src/ptr/mut_ptr.rs @@ -937,8 +937,8 @@ impl *mut T { /// /// // This would be incorrect, as the pointers are not correctly ordered: /// // ptr1.offset_from(ptr2) - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize @@ -959,8 +959,8 @@ impl *mut T { /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from_unsigned(self, origin: *mut U) -> usize { diff --git a/core/src/ptr/non_null.rs b/core/src/ptr/non_null.rs index e019aafad3935..68b8f0c3e4e1d 100644 --- a/core/src/ptr/non_null.rs +++ b/core/src/ptr/non_null.rs @@ -900,8 +900,8 @@ impl NonNull { /// ``` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] pub const unsafe fn offset_from_unsigned(self, subtracted: NonNull) -> usize where T: Sized, @@ -922,8 +922,8 @@ impl NonNull { /// ignoring the metadata. #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] pub const unsafe fn byte_offset_from_unsigned(self, origin: NonNull) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_sub_ptr`. unsafe { self.as_ptr().byte_offset_from_unsigned(origin.as_ptr()) } diff --git a/core/src/ptr/unique.rs b/core/src/ptr/unique.rs index 4810ebe01f9bb..d688ce2a07a6a 100644 --- a/core/src/ptr/unique.rs +++ b/core/src/ptr/unique.rs @@ -100,6 +100,12 @@ impl Unique { } } + /// Create a new `Unique` from a `NonNull` in const context. + #[inline] + pub const fn from_non_null(pointer: NonNull) -> Self { + Unique { pointer, _marker: PhantomData } + } + /// Acquires the underlying `*mut` pointer. #[must_use = "`self` will be dropped if the result is not used"] #[inline] @@ -202,6 +208,6 @@ impl From> for Unique { /// This conversion is infallible since `NonNull` cannot be null. #[inline] fn from(pointer: NonNull) -> Self { - Unique { pointer, _marker: PhantomData } + Unique::from_non_null(pointer) } } diff --git a/core/src/slice/cmp.rs b/core/src/slice/cmp.rs index da85f42926e6b..5ce72b46eee36 100644 --- a/core/src/slice/cmp.rs +++ b/core/src/slice/cmp.rs @@ -5,6 +5,7 @@ use crate::ascii; use crate::cmp::{self, BytewiseEq, Ordering}; use crate::intrinsics::compare_bytes; use crate::num::NonZero; +use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[U]> for [T] @@ -31,12 +32,64 @@ impl Ord for [T] { } } +#[inline] +fn as_underlying(x: ControlFlow) -> u8 { + // SAFETY: This will only compile if `bool` and `ControlFlow` have the same + // size (which isn't guaranteed but this is libcore). Because they have the same + // size, it's a niched implementation, which in one byte means there can't be + // any uninitialized memory. The callers then only check for `0` or `1` from this, + // which must necessarily match the `Break` variant, and we're fine no matter + // what ends up getting picked as the value representing `Continue(())`. + unsafe { crate::mem::transmute(x) } +} + /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { + #[inline] fn partial_cmp(&self, other: &[T]) -> Option { SlicePartialOrd::partial_compare(self, other) } + #[inline] + fn lt(&self, other: &Self) -> bool { + // This is certainly not the obvious way to implement these methods. + // Unfortunately, using anything that looks at the discriminant means that + // LLVM sees a check for `2` (aka `ControlFlow::Continue(())`) and + // gets very distracted by that, ending up generating extraneous code. + // This should be changed to something simpler once either LLVM is smarter, + // see , or we generate + // niche discriminant checks in a way that doesn't trigger it. + + as_underlying(self.__chaining_lt(other)) == 1 + } + #[inline] + fn le(&self, other: &Self) -> bool { + as_underlying(self.__chaining_le(other)) != 0 + } + #[inline] + fn gt(&self, other: &Self) -> bool { + as_underlying(self.__chaining_gt(other)) == 1 + } + #[inline] + fn ge(&self, other: &Self) -> bool { + as_underlying(self.__chaining_ge(other)) != 0 + } + #[inline] + fn __chaining_lt(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_lt(self, other) + } + #[inline] + fn __chaining_le(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_le(self, other) + } + #[inline] + fn __chaining_gt(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_gt(self, other) + } + #[inline] + fn __chaining_ge(&self, other: &Self) -> ControlFlow { + SliceChain::chaining_ge(self, other) + } } #[doc(hidden)] @@ -99,24 +152,63 @@ trait SlicePartialOrd: Sized { fn partial_compare(left: &[Self], right: &[Self]) -> Option; } +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialOrd chaining methods +trait SliceChain: Sized { + fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow; + fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow; +} + +type AlwaysBreak = ControlFlow; + impl SlicePartialOrd for A { default fn partial_compare(left: &[A], right: &[A]) -> Option { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; + let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) { + Some(Ordering::Equal) => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + }; + let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b)); + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); + b + } +} - for i in 0..l { - match lhs[i].partial_cmp(&rhs[i]) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, - } - } +impl SliceChain for A { + default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt) + } + default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le) + } + default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt) + } + default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow { + chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge) + } +} - left.len().partial_cmp(&right.len()) +#[inline] +fn chaining_impl<'l, 'r, A: PartialOrd, B, C>( + left: &'l [A], + right: &'r [A], + elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow, + len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow, +) -> ControlFlow { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + elem_chain(&lhs[i], &rhs[i])?; } + + len_chain(&left.len(), &right.len()) } // This is the impl that we would like to have. Unfortunately it's not sound. @@ -165,21 +257,13 @@ trait SliceOrd: Sized { impl SliceOrd for A { default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].cmp(&rhs[i]) { - Ordering::Equal => (), - non_eq => return non_eq, - } - } - - left.len().cmp(&right.len()) + let elem_chain = |a, b| match Ord::cmp(a, b) { + Ordering::Equal => ControlFlow::Continue(()), + non_eq => ControlFlow::Break(non_eq), + }; + let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b)); + let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain); + b } } @@ -191,7 +275,7 @@ impl SliceOrd for A { /// * For every `x` and `y` of this type, `Ord(x, y)` must return the same /// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`. #[rustc_specialization_trait] -unsafe trait UnsignedBytewiseOrd {} +unsafe trait UnsignedBytewiseOrd: Ord {} unsafe impl UnsignedBytewiseOrd for bool {} unsafe impl UnsignedBytewiseOrd for u8 {} @@ -225,6 +309,38 @@ impl SliceOrd for A { } } +// Don't generate our own chaining loops for `memcmp`-able things either. +impl SliceChain for A { + #[inline] + fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_lt()), + } + } + #[inline] + fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_le()), + } + } + #[inline] + fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_gt()), + } + } + #[inline] + fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow { + match SliceOrd::compare(left, right) { + Ordering::Equal => ControlFlow::Continue(()), + ne => ControlFlow::Break(ne.is_ge()), + } + } +} + pub(super) trait SliceContains: Sized { fn slice_contains(&self, x: &[Self]) -> bool; } diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index c7e8d5f989dd2..7b2a3fac38a32 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -1287,7 +1287,6 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { @@ -1333,7 +1332,6 @@ impl [T] { /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1368,7 +1366,6 @@ impl [T] { /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1448,7 +1445,6 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { @@ -1489,7 +1485,6 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 9]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1530,7 +1525,6 @@ impl [T] { /// assert_eq!(v, &[9, 1, 1, 2, 2]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] - #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -2828,7 +2822,7 @@ impl [T] { // Binary search interacts poorly with branch prediction, so force // the compiler to use conditional moves if supported by the target // architecture. - base = (cmp == Greater).select_unpredictable(base, mid); + base = hint::select_unpredictable(cmp == Greater, base, mid); // This is imprecise in the case where `size` is odd and the // comparison returns Greater: the mid element still gets included @@ -3721,7 +3715,7 @@ impl [T] { #[doc(alias = "memcpy")] #[inline] #[stable(feature = "copy_from_slice", since = "1.9.0")] - #[rustc_const_stable(feature = "const_copy_from_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] #[track_caller] pub const fn copy_from_slice(&mut self, src: &[T]) where @@ -4331,7 +4325,7 @@ impl [T] { /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] pub fn split_off<'a, R: OneSidedRange>( self: &mut &'a Self, range: R, @@ -4397,7 +4391,7 @@ impl [T] { /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] pub fn split_off_mut<'a, R: OneSidedRange>( self: &mut &'a mut Self, range: R, @@ -4434,7 +4428,7 @@ impl [T] { /// assert_eq!(first, &'a'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { // FIXME(const-hack): Use `?` when available in const instead of `let-else`. @@ -4459,7 +4453,7 @@ impl [T] { /// assert_eq!(first, &'d'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { // FIXME(const-hack): Use `mem::take` and `?` when available in const. @@ -4484,7 +4478,7 @@ impl [T] { /// assert_eq!(last, &'c'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { // FIXME(const-hack): Use `?` when available in const instead of `let-else`. @@ -4509,7 +4503,7 @@ impl [T] { /// assert_eq!(last, &'d'); /// ``` #[inline] - #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_take", since = "1.87.0")] #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { // FIXME(const-hack): Use `mem::take` and `?` when available in const. @@ -4841,7 +4835,7 @@ impl [[T; N]] { /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - #[rustc_const_stable(feature = "const_slice_flatten", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] pub const fn as_flattened(&self) -> &[T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") @@ -4878,7 +4872,7 @@ impl [[T; N]] { /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] - #[rustc_const_stable(feature = "const_slice_flatten", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] pub const fn as_flattened_mut(&mut self) -> &mut [T] { let len = if T::IS_ZST { self.len().checked_mul(N).expect("slice len overflow") diff --git a/core/src/slice/sort/shared/smallsort.rs b/core/src/slice/sort/shared/smallsort.rs index 95f196a40d01c..4280f7570db4c 100644 --- a/core/src/slice/sort/shared/smallsort.rs +++ b/core/src/slice/sort/shared/smallsort.rs @@ -2,7 +2,7 @@ use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::slice::sort::shared::FreezeMarker; -use crate::{intrinsics, ptr, slice}; +use crate::{hint, intrinsics, ptr, slice}; // It's important to differentiate between SMALL_SORT_THRESHOLD performance for // small slices and small-sort performance sorting small sub-slices as part of @@ -408,8 +408,8 @@ where // } // The goal is to generate cmov instructions here. - let v_a_swap = should_swap.select_unpredictable(v_b, v_a); - let v_b_swap = should_swap.select_unpredictable(v_a, v_b); + let v_a_swap = hint::select_unpredictable(should_swap, v_b, v_a); + let v_b_swap = hint::select_unpredictable(should_swap, v_a, v_b); let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap)); ptr::copy(v_a_swap, v_a, 1); @@ -640,15 +640,15 @@ pub unsafe fn sort4_stable bool>( // 1, 1 | c b a d let c3 = is_less(&*c, &*a); let c4 = is_less(&*d, &*b); - let min = c3.select_unpredictable(c, a); - let max = c4.select_unpredictable(b, d); - let unknown_left = c3.select_unpredictable(a, c4.select_unpredictable(c, b)); - let unknown_right = c4.select_unpredictable(d, c3.select_unpredictable(b, c)); + let min = hint::select_unpredictable(c3, c, a); + let max = hint::select_unpredictable(c4, b, d); + let unknown_left = hint::select_unpredictable(c3, a, hint::select_unpredictable(c4, c, b)); + let unknown_right = hint::select_unpredictable(c4, d, hint::select_unpredictable(c3, b, c)); // Sort the last two unknown elements. let c5 = is_less(&*unknown_right, &*unknown_left); - let lo = c5.select_unpredictable(unknown_right, unknown_left); - let hi = c5.select_unpredictable(unknown_left, unknown_right); + let lo = hint::select_unpredictable(c5, unknown_right, unknown_left); + let hi = hint::select_unpredictable(c5, unknown_left, unknown_right); ptr::copy_nonoverlapping(min, dst, 1); ptr::copy_nonoverlapping(lo, dst.add(1), 1); diff --git a/core/src/str/converts.rs b/core/src/str/converts.rs index 1276d9014f0ef..37854a4da64ce 100644 --- a/core/src/str/converts.rs +++ b/core/src/str/converts.rs @@ -126,7 +126,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_str_from_utf8", since = "1.87.0")] #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` diff --git a/core/src/str/mod.rs b/core/src/str/mod.rs index 5cc08f8a71afb..79b4953fcc11a 100644 --- a/core/src/str/mod.rs +++ b/core/src/str/mod.rs @@ -230,8 +230,8 @@ impl str { /// /// assert_eq!("💖", sparkle_heart); /// ``` - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { converts::from_utf8(v) @@ -263,8 +263,8 @@ impl str { /// ``` /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "const_str_from_utf8", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { converts::from_utf8_mut(v) @@ -295,8 +295,8 @@ impl str { /// ``` #[inline] #[must_use] - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: converts::from_utf8_unchecked has the same safety requirements as this function. @@ -320,8 +320,8 @@ impl str { /// ``` #[inline] #[must_use] - #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "inherent_str_constructors", since = "1.87.0")] + #[rustc_const_stable(feature = "inherent_str_constructors", since = "1.87.0")] #[rustc_diagnostic_item = "str_inherent_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: converts::from_utf8_unchecked_mut has the same safety requirements as this function. diff --git a/core/src/tuple.rs b/core/src/tuple.rs index d754bb9034300..02eb805ece121 100644 --- a/core/src/tuple.rs +++ b/core/src/tuple.rs @@ -2,7 +2,7 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; -use crate::ops::ControlFlow::{Break, Continue}; +use crate::ops::ControlFlow::{self, Break, Continue}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -95,6 +95,22 @@ macro_rules! tuple_impls { fn gt(&self, other: &($($T,)+)) -> bool { lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) } + #[inline] + fn __chaining_lt(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_le(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_gt(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } + #[inline] + fn __chaining_ge(&self, other: &($($T,)+)) -> ControlFlow { + lexical_chain!(__chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+) + } } } @@ -187,6 +203,17 @@ macro_rules! lexical_ord { }; } +// Same parameter interleaving as `lexical_ord` above +macro_rules! lexical_chain { + ($chain_rel: ident, $a:expr, $b:expr $(,$rest_a:expr, $rest_b:expr)*) => {{ + PartialOrd::$chain_rel(&$a, &$b)?; + lexical_chain!($chain_rel $(,$rest_a, $rest_b)*) + }}; + ($chain_rel: ident) => { + Continue(()) + }; +} + macro_rules! lexical_partial_cmp { ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { match ($a).partial_cmp(&$b) { diff --git a/coretests/tests/hint.rs b/coretests/tests/hint.rs new file mode 100644 index 0000000000000..032bbc1dcc80f --- /dev/null +++ b/coretests/tests/hint.rs @@ -0,0 +1,23 @@ +#[test] +fn select_unpredictable_drop() { + use core::cell::Cell; + struct X<'a>(&'a Cell); + impl Drop for X<'_> { + fn drop(&mut self) { + self.0.set(true); + } + } + + let a_dropped = Cell::new(false); + let b_dropped = Cell::new(false); + let a = X(&a_dropped); + let b = X(&b_dropped); + assert!(!a_dropped.get()); + assert!(!b_dropped.get()); + let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b); + assert!(!a_dropped.get()); + assert!(b_dropped.get()); + drop(selected); + assert!(a_dropped.get()); + assert!(b_dropped.get()); +} diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index 7ad154796f649..1c43bfe0ed4a9 100644 --- a/coretests/tests/lib.rs +++ b/coretests/tests/lib.rs @@ -68,6 +68,7 @@ #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] +#![feature(select_unpredictable)] #![feature(slice_from_ptr_range)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] @@ -147,6 +148,7 @@ mod ffi; mod fmt; mod future; mod hash; +mod hint; mod intrinsics; mod io; mod iter; diff --git a/coretests/tests/pin_macro.rs b/coretests/tests/pin_macro.rs index 3174c91a6498b..bfbfa8d280fa1 100644 --- a/coretests/tests/pin_macro.rs +++ b/coretests/tests/pin_macro.rs @@ -38,7 +38,6 @@ fn rust_2024_expr() { } #[test] -#[cfg(not(bootstrap))] fn temp_lifetime() { // Check that temporary lifetimes work as in Rust 2021. // Regression test for https://github.com/rust-lang/rust/issues/138596 diff --git a/coretests/tests/ptr.rs b/coretests/tests/ptr.rs index 6091926084a35..cc5f7946863a6 100644 --- a/coretests/tests/ptr.rs +++ b/coretests/tests/ptr.rs @@ -984,3 +984,39 @@ fn test_ptr_metadata_in_const() { assert_eq!(SLICE_META, 3); assert_eq!(DYN_META.size_of(), 42); } + +// See +const fn ptr_swap_nonoverlapping_is_untyped_inner() { + #[repr(C)] + struct HasPadding(usize, u8); + + let buf1: [usize; 2] = [1000, 2000]; + let buf2: [usize; 2] = [3000, 4000]; + + // HasPadding and [usize; 2] have the same size and alignment, + // so swap_nonoverlapping should treat them the same + assert!(size_of::() == size_of::<[usize; 2]>()); + assert!(align_of::() == align_of::<[usize; 2]>()); + + let mut b1 = buf1; + let mut b2 = buf2; + // Safety: b1 and b2 are distinct local variables, + // with the same size and alignment as HasPadding. + unsafe { + std::ptr::swap_nonoverlapping( + b1.as_mut_ptr().cast::(), + b2.as_mut_ptr().cast::(), + 1, + ); + } + assert!(b1[0] == buf2[0]); + assert!(b1[1] == buf2[1]); + assert!(b2[0] == buf1[0]); + assert!(b2[1] == buf1[1]); +} + +#[test] +fn test_ptr_swap_nonoverlapping_is_untyped() { + ptr_swap_nonoverlapping_is_untyped_inner(); + const { ptr_swap_nonoverlapping_is_untyped_inner() }; +} diff --git a/panic_unwind/src/lib.rs b/panic_unwind/src/lib.rs index e5c1d6bdb3b06..50bd933aca204 100644 --- a/panic_unwind/src/lib.rs +++ b/panic_unwind/src/lib.rs @@ -79,11 +79,11 @@ cfg_if::cfg_if! { unsafe extern "C" { /// Handler in std called when a panic object is dropped outside of /// `catch_unwind`. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_drop_panic() -> !; /// Handler in std called when a foreign exception is caught. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_foreign_exception() -> !; } diff --git a/proc_macro/src/bridge/client.rs b/proc_macro/src/bridge/client.rs index f6d4825c67b24..e7d547966a5d5 100644 --- a/proc_macro/src/bridge/client.rs +++ b/proc_macro/src/bridge/client.rs @@ -111,12 +111,6 @@ impl Clone for TokenStream { } } -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - impl Span { pub(crate) fn def_site() -> Span { Bridge::with(|bridge| bridge.globals.def_site) diff --git a/proc_macro/src/bridge/mod.rs b/proc_macro/src/bridge/mod.rs index 52cc8fba0438d..75d82d7465404 100644 --- a/proc_macro/src/bridge/mod.rs +++ b/proc_macro/src/bridge/mod.rs @@ -9,7 +9,6 @@ #![deny(unsafe_code)] // proc_macros anyway don't work on wasm hosts so while both sides of this bridge can // be built with different versions of rustc, the wasm ABI changes don't really matter. -#![cfg_attr(bootstrap, allow(unknown_lints))] #![allow(wasm_c_abi)] use std::hash::Hash; @@ -82,16 +81,8 @@ macro_rules! with_api { $self: $S::TokenStream ) -> Vec>; }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, Span { fn debug($self: $S::Span) -> String; - fn source_file($self: $S::Span) -> $S::SourceFile; fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; fn byte_range($self: $S::Span) -> Range; @@ -99,6 +90,8 @@ macro_rules! with_api { fn end($self: $S::Span) -> $S::Span; fn line($self: $S::Span) -> usize; fn column($self: $S::Span) -> usize; + fn file($self: $S::Span) -> String; + fn local_file($self: $S::Span) -> Option; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn subspan($self: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; @@ -121,7 +114,6 @@ macro_rules! with_api_handle_types { 'owned: FreeFunctions, TokenStream, - SourceFile, 'interned: Span, diff --git a/proc_macro/src/bridge/server.rs b/proc_macro/src/bridge/server.rs index 97e5a603c3ac9..5beda7c3c96e5 100644 --- a/proc_macro/src/bridge/server.rs +++ b/proc_macro/src/bridge/server.rs @@ -82,7 +82,6 @@ with_api_handle_types!(define_server_handles); pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; - type SourceFile: 'static + Clone; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } diff --git a/proc_macro/src/lib.rs b/proc_macro/src/lib.rs index f1cf0c5a2db7c..c46dcebedcab8 100644 --- a/proc_macro/src/lib.rs +++ b/proc_macro/src/lib.rs @@ -491,12 +491,6 @@ impl Span { Span(bridge::client::Span::mixed_site()) } - /// The original source file into which this span points. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - /// The `Span` for the tokens in the previous macro expansion from which /// `self` was generated from, if any. #[unstable(feature = "proc_macro_span", issue = "54725")] @@ -546,6 +540,25 @@ impl Span { self.0.column() } + /// The path to the source file in which this span occurs, for display purposes. + /// + /// This might not correspond to a valid file system path. + /// It might be remapped, or might be an artificial path such as `""`. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn file(&self) -> String { + self.0.file() + } + + /// The path to the source file in which this span occurs on disk. + /// + /// This is the actual path on disk. It is unaffected by path remapping. + /// + /// This path should not be embedded in the output of the macro; prefer `file()` instead. + #[unstable(feature = "proc_macro_span", issue = "54725")] + pub fn local_file(&self) -> Option { + self.0.local_file().map(|s| PathBuf::from(s)) + } + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. @@ -614,58 +627,6 @@ impl fmt::Debug for Span { } } -/// The source file of a given `Span`. -#[unstable(feature = "proc_macro_span", issue = "54725")] -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - #[unstable(feature = "proc_macro_span", issue = "54725")] - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -#[unstable(feature = "proc_macro_span", issue = "54725")] -impl Eq for SourceFile {} - /// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] diff --git a/profiler_builtins/build.rs b/profiler_builtins/build.rs index dd85239fa8cfd..fc1a9ecc1ec32 100644 --- a/profiler_builtins/build.rs +++ b/profiler_builtins/build.rs @@ -9,8 +9,14 @@ use std::path::PathBuf; fn main() { if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") { - println!("cargo::rustc-link-lib=static:+verbatim={rt}"); - return; + let rt = PathBuf::from(rt); + if let Some(lib) = rt.file_name() { + if let Some(dir) = rt.parent() { + println!("cargo::rustc-link-search=native={}", dir.display()); + } + println!("cargo::rustc-link-lib=static:+verbatim={}", lib.to_str().unwrap()); + return; + } } let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); diff --git a/std/Cargo.toml b/std/Cargo.toml index 176da603d58d7..917a470842ca9 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.152" } +compiler_builtins = { version = "=0.1.155" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', diff --git a/std/build.rs b/std/build.rs index d76d07a89f4e8..40a56d4930d35 100644 --- a/std/build.rs +++ b/std/build.rs @@ -12,11 +12,6 @@ fn main() { .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") .parse() .unwrap(); - let target_features: Vec<_> = env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(); let is_miri = env::var_os("CARGO_CFG_MIRI").is_some(); println!("cargo:rustc-check-cfg=cfg(netbsd10)"); @@ -108,8 +103,6 @@ fn main() { ("s390x", _) => false, // Unsupported ("arm64ec", _) => false, - // LLVM crash - ("aarch64", _) if !target_features.iter().any(|f| f == "neon") => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion diff --git a/std/src/alloc.rs b/std/src/alloc.rs index 5d2a304b41c5a..75971ac90e783 100644 --- a/std/src/alloc.rs +++ b/std/src/alloc.rs @@ -348,7 +348,7 @@ fn default_alloc_error_hook(layout: Layout) { unsafe extern "Rust" { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] static __rust_alloc_error_handler_should_panic: u8; } diff --git a/std/src/backtrace.rs b/std/src/backtrace.rs index 3e641ac5d9041..3683485640c2f 100644 --- a/std/src/backtrace.rs +++ b/std/src/backtrace.rs @@ -432,7 +432,7 @@ mod helper { use super::*; pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; - #[cfg_attr(not(bootstrap), define_opaque(LazyResolve))] + #[define_opaque(LazyResolve)] pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve { move || { // Use the global backtrace lock to synchronize this as it's a diff --git a/std/src/collections/hash/map.rs b/std/src/collections/hash/map.rs index 2487f5a2a503f..0eef2bd225c06 100644 --- a/std/src/collections/hash/map.rs +++ b/std/src/collections/hash/map.rs @@ -683,7 +683,7 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "hash_extract_if", since = "1.87.0")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -1677,7 +1677,7 @@ impl<'a, K, V> Drain<'a, K, V> { /// ]); /// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf<'a, K, V, F> where @@ -2294,7 +2294,7 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -2311,10 +2311,10 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> where F: FnMut(&K, &mut V) -> bool, diff --git a/std/src/collections/hash/set.rs b/std/src/collections/hash/set.rs index a547a9943c1a0..7be000594bc55 100644 --- a/std/src/collections/hash/set.rs +++ b/std/src/collections/hash/set.rs @@ -308,7 +308,7 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "hash_extract_if", since = "1.87.0")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, @@ -1390,7 +1390,7 @@ pub struct Drain<'a, K: 'a> { /// /// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] pub struct ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, @@ -1673,7 +1673,7 @@ impl fmt::Debug for Drain<'_, K> { } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, @@ -1690,10 +1690,10 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.87.0")] impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, diff --git a/std/src/f128.rs b/std/src/f128.rs index ede2196905118..217528fdf1c10 100644 --- a/std/src/f128.rs +++ b/std/src/f128.rs @@ -666,7 +666,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cbrt(self) -> f128 { - unsafe { cmath::cbrtf128(self) } + cmath::cbrtf128(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -703,7 +703,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn hypot(self, other: f128) -> f128 { - unsafe { cmath::hypotf128(self, other) } + cmath::hypotf128(self, other) } /// Computes the sine of a number (in radians). @@ -789,7 +789,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tan(self) -> f128 { - unsafe { cmath::tanf128(self) } + cmath::tanf128(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -824,7 +824,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn asin(self) -> f128 { - unsafe { cmath::asinf128(self) } + cmath::asinf128(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -859,7 +859,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn acos(self) -> f128 { - unsafe { cmath::acosf128(self) } + cmath::acosf128(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -893,7 +893,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan(self) -> f128 { - unsafe { cmath::atanf128(self) } + cmath::atanf128(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -939,7 +939,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan2(self, other: f128) -> f128 { - unsafe { cmath::atan2f128(self, other) } + cmath::atan2f128(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -1008,7 +1008,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp_m1(self) -> f128 { - unsafe { cmath::expm1f128(self) } + cmath::expm1f128(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -1055,7 +1055,7 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] pub fn ln_1p(self) -> f128 { - unsafe { cmath::log1pf128(self) } + cmath::log1pf128(self) } /// Hyperbolic sine function. @@ -1090,7 +1090,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sinh(self) -> f128 { - unsafe { cmath::sinhf128(self) } + cmath::sinhf128(self) } /// Hyperbolic cosine function. @@ -1125,7 +1125,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cosh(self) -> f128 { - unsafe { cmath::coshf128(self) } + cmath::coshf128(self) } /// Hyperbolic tangent function. @@ -1160,7 +1160,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tanh(self) -> f128 { - unsafe { cmath::tanhf128(self) } + cmath::tanhf128(self) } /// Inverse hyperbolic sine function. @@ -1289,7 +1289,7 @@ impl f128 { // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f128 { - unsafe { cmath::tgammaf128(self) } + cmath::tgammaf128(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1325,7 +1325,7 @@ impl f128 { #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f128, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) }; + let x = cmath::lgammaf128_r(self, &mut signgamp); (x, signgamp) } @@ -1365,7 +1365,7 @@ impl f128 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f128 { - unsafe { cmath::erff128(self) } + cmath::erff128(self) } /// Complementary error function. @@ -1398,6 +1398,6 @@ impl f128 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f128 { - unsafe { cmath::erfcf128(self) } + cmath::erfcf128(self) } } diff --git a/std/src/f16.rs b/std/src/f16.rs index 286993d736b9c..4dadcbb518556 100644 --- a/std/src/f16.rs +++ b/std/src/f16.rs @@ -665,7 +665,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cbrt(self) -> f16 { - (unsafe { cmath::cbrtf(self as f32) }) as f16 + cmath::cbrtf(self as f32) as f16 } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -701,7 +701,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn hypot(self, other: f16) -> f16 { - (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16 + cmath::hypotf(self as f32, other as f32) as f16 } /// Computes the sine of a number (in radians). @@ -787,7 +787,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tan(self) -> f16 { - (unsafe { cmath::tanf(self as f32) }) as f16 + cmath::tanf(self as f32) as f16 } /// Computes the arcsine of a number. Return value is in radians in @@ -822,7 +822,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn asin(self) -> f16 { - (unsafe { cmath::asinf(self as f32) }) as f16 + cmath::asinf(self as f32) as f16 } /// Computes the arccosine of a number. Return value is in radians in @@ -857,7 +857,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn acos(self) -> f16 { - (unsafe { cmath::acosf(self as f32) }) as f16 + cmath::acosf(self as f32) as f16 } /// Computes the arctangent of a number. Return value is in radians in the @@ -891,7 +891,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan(self) -> f16 { - (unsafe { cmath::atanf(self as f32) }) as f16 + cmath::atanf(self as f32) as f16 } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -937,7 +937,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn atan2(self, other: f16) -> f16 { - (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16 + cmath::atan2f(self as f32, other as f32) as f16 } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -1006,7 +1006,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp_m1(self) -> f16 { - (unsafe { cmath::expm1f(self as f32) }) as f16 + cmath::expm1f(self as f32) as f16 } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -1053,7 +1053,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_1p(self) -> f16 { - (unsafe { cmath::log1pf(self as f32) }) as f16 + cmath::log1pf(self as f32) as f16 } /// Hyperbolic sine function. @@ -1088,7 +1088,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sinh(self) -> f16 { - (unsafe { cmath::sinhf(self as f32) }) as f16 + cmath::sinhf(self as f32) as f16 } /// Hyperbolic cosine function. @@ -1123,7 +1123,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cosh(self) -> f16 { - (unsafe { cmath::coshf(self as f32) }) as f16 + cmath::coshf(self as f32) as f16 } /// Hyperbolic tangent function. @@ -1158,7 +1158,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn tanh(self) -> f16 { - (unsafe { cmath::tanhf(self as f32) }) as f16 + cmath::tanhf(self as f32) as f16 } /// Inverse hyperbolic sine function. @@ -1287,7 +1287,7 @@ impl f16 { // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f16 { - (unsafe { cmath::tgammaf(self as f32) }) as f16 + cmath::tgammaf(self as f32) as f16 } /// Natural logarithm of the absolute value of the gamma function @@ -1323,7 +1323,7 @@ impl f16 { #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f16, i32) { let mut signgamp: i32 = 0; - let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16; + let x = cmath::lgammaf_r(self as f32, &mut signgamp) as f16; (x, signgamp) } @@ -1363,7 +1363,7 @@ impl f16 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f16 { - (unsafe { cmath::erff(self as f32) }) as f16 + cmath::erff(self as f32) as f16 } /// Complementary error function. @@ -1396,6 +1396,6 @@ impl f16 { // #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f16 { - (unsafe { cmath::erfcf(self as f32) }) as f16 + cmath::erfcf(self as f32) as f16 } } diff --git a/std/src/f32.rs b/std/src/f32.rs index 980e7f7793af2..baf7002f3803c 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -599,7 +599,7 @@ impl f32 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f32) -> f32 { - unsafe { cmath::fdimf(self, other) } + cmath::fdimf(self, other) } /// Returns the cube root of a number. @@ -626,7 +626,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { - unsafe { cmath::cbrtf(self) } + cmath::cbrtf(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -657,7 +657,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn hypot(self, other: f32) -> f32 { - unsafe { cmath::hypotf(self, other) } + cmath::hypotf(self, other) } /// Computes the sine of a number (in radians). @@ -730,7 +730,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f32 { - unsafe { cmath::tanf(self) } + cmath::tanf(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -760,7 +760,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f32 { - unsafe { cmath::asinf(self) } + cmath::asinf(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -790,7 +790,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f32 { - unsafe { cmath::acosf(self) } + cmath::acosf(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -819,7 +819,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f32 { - unsafe { cmath::atanf(self) } + cmath::atanf(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -860,7 +860,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan2(self, other: f32) -> f32 { - unsafe { cmath::atan2f(self, other) } + cmath::atan2f(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -919,7 +919,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f32 { - unsafe { cmath::expm1f(self) } + cmath::expm1f(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -957,7 +957,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f32 { - unsafe { cmath::log1pf(self) } + cmath::log1pf(self) } /// Hyperbolic sine function. @@ -987,7 +987,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f32 { - unsafe { cmath::sinhf(self) } + cmath::sinhf(self) } /// Hyperbolic cosine function. @@ -1017,7 +1017,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f32 { - unsafe { cmath::coshf(self) } + cmath::coshf(self) } /// Hyperbolic tangent function. @@ -1047,7 +1047,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f32 { - unsafe { cmath::tanhf(self) } + cmath::tanhf(self) } /// Inverse hyperbolic sine function. @@ -1158,7 +1158,7 @@ impl f32 { #[unstable(feature = "float_gamma", issue = "99842")] #[inline] pub fn gamma(self) -> f32 { - unsafe { cmath::tgammaf(self) } + cmath::tgammaf(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1188,7 +1188,7 @@ impl f32 { #[inline] pub fn ln_gamma(self) -> (f32, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) }; + let x = cmath::lgammaf_r(self, &mut signgamp); (x, signgamp) } @@ -1224,7 +1224,7 @@ impl f32 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f32 { - unsafe { cmath::erff(self) } + cmath::erff(self) } /// Complementary error function. @@ -1253,6 +1253,6 @@ impl f32 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f32 { - unsafe { cmath::erfcf(self) } + cmath::erfcf(self) } } diff --git a/std/src/f64.rs b/std/src/f64.rs index 2aaab3ffc8352..84fd9bfb7b680 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -599,7 +599,7 @@ impl f64 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } + cmath::fdim(self, other) } /// Returns the cube root of a number. @@ -626,7 +626,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { - unsafe { cmath::cbrt(self) } + cmath::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -657,7 +657,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn hypot(self, other: f64) -> f64 { - unsafe { cmath::hypot(self, other) } + cmath::hypot(self, other) } /// Computes the sine of a number (in radians). @@ -730,7 +730,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f64 { - unsafe { cmath::tan(self) } + cmath::tan(self) } /// Computes the arcsine of a number. Return value is in radians in @@ -760,7 +760,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f64 { - unsafe { cmath::asin(self) } + cmath::asin(self) } /// Computes the arccosine of a number. Return value is in radians in @@ -790,7 +790,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f64 { - unsafe { cmath::acos(self) } + cmath::acos(self) } /// Computes the arctangent of a number. Return value is in radians in the @@ -819,7 +819,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f64 { - unsafe { cmath::atan(self) } + cmath::atan(self) } /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. @@ -860,7 +860,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan2(self, other: f64) -> f64 { - unsafe { cmath::atan2(self, other) } + cmath::atan2(self, other) } /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -919,7 +919,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f64 { - unsafe { cmath::expm1(self) } + cmath::expm1(self) } /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -957,7 +957,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f64 { - unsafe { cmath::log1p(self) } + cmath::log1p(self) } /// Hyperbolic sine function. @@ -987,7 +987,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f64 { - unsafe { cmath::sinh(self) } + cmath::sinh(self) } /// Hyperbolic cosine function. @@ -1017,7 +1017,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f64 { - unsafe { cmath::cosh(self) } + cmath::cosh(self) } /// Hyperbolic tangent function. @@ -1047,7 +1047,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f64 { - unsafe { cmath::tanh(self) } + cmath::tanh(self) } /// Inverse hyperbolic sine function. @@ -1158,7 +1158,7 @@ impl f64 { #[unstable(feature = "float_gamma", issue = "99842")] #[inline] pub fn gamma(self) -> f64 { - unsafe { cmath::tgamma(self) } + cmath::tgamma(self) } /// Natural logarithm of the absolute value of the gamma function @@ -1188,7 +1188,7 @@ impl f64 { #[inline] pub fn ln_gamma(self) -> (f64, i32) { let mut signgamp: i32 = 0; - let x = unsafe { cmath::lgamma_r(self, &mut signgamp) }; + let x = cmath::lgamma_r(self, &mut signgamp); (x, signgamp) } @@ -1224,7 +1224,7 @@ impl f64 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erf(self) -> f64 { - unsafe { cmath::erf(self) } + cmath::erf(self) } /// Complementary error function. @@ -1253,6 +1253,6 @@ impl f64 { #[unstable(feature = "float_erf", issue = "136321")] #[inline] pub fn erfc(self) -> f64 { - unsafe { cmath::erfc(self) } + cmath::erfc(self) } } diff --git a/std/src/ffi/mod.rs b/std/src/ffi/mod.rs index 860ec3a6be16e..d34e3ca00b9fe 100644 --- a/std/src/ffi/mod.rs +++ b/std/src/ffi/mod.rs @@ -201,5 +201,5 @@ pub use self::c_str::{CStr, CString}; #[doc(inline)] pub use self::os_str::{OsStr, OsString}; -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] pub mod os_str; diff --git a/std/src/ffi/os_str.rs b/std/src/ffi/os_str.rs index aa25ff5293c71..ce01175309a77 100644 --- a/std/src/ffi/os_str.rs +++ b/std/src/ffi/os_str.rs @@ -1255,7 +1255,7 @@ impl OsStr { /// let s = OsStr::new("Hello, world!"); /// println!("{}", s.display()); /// ``` - #[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_str_display", since = "1.87.0")] #[must_use = "this does not display the `OsStr`; \ it returns an object that can be displayed"] #[inline] @@ -1612,19 +1612,19 @@ impl fmt::Debug for OsStr { /// /// [`Display`]: fmt::Display /// [`format!`]: crate::format -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] pub struct Display<'a> { os_str: &'a OsStr, } -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] impl fmt::Debug for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.os_str, f) } } -#[stable(feature = "os_str_display", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "os_str_display", since = "1.87.0")] impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.os_str.inner, f) diff --git a/std/src/io/error.rs b/std/src/io/error.rs index 8472f90305007..cf3778bd29071 100644 --- a/std/src/io/error.rs +++ b/std/src/io/error.rs @@ -48,6 +48,7 @@ use crate::{error, fmt, result, sys}; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), doc(search_unbox))] pub type Result = result::Result; /// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and @@ -374,7 +375,7 @@ pub enum ErrorKind { /// A filename was invalid. /// /// This error can also occur if a length limit for a name was exceeded. - #[stable(feature = "io_error_invalid_filename", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_invalid_filename", since = "1.87.0")] InvalidFilename, /// Program argument list too long. /// diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs index 314cbb45d49e2..5242261cf93f6 100644 --- a/std/src/io/mod.rs +++ b/std/src/io/mod.rs @@ -310,7 +310,7 @@ pub use self::error::RawOsError; pub use self::error::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use self::error::const_error; -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; @@ -2658,6 +2658,10 @@ impl Chain { /// Gets references to the underlying readers in this `Chain`. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// /// # Examples /// /// ```no_run @@ -2915,6 +2919,10 @@ impl Take { /// Gets a reference to the underlying reader. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// /// # Examples /// /// ```no_run diff --git a/std/src/io/pipe.rs b/std/src/io/pipe.rs index cfed9b05cc0c6..c6b7b49a351e4 100644 --- a/std/src/io/pipe.rs +++ b/std/src/io/pipe.rs @@ -67,19 +67,19 @@ use crate::sys_common::{FromInner, IntoInner}; /// ``` /// [changes]: io#platform-specific-behavior /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[inline] pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) } /// Read end of an anonymous pipe. -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] pub struct PipeReader(pub(crate) AnonPipe); /// Write end of an anonymous pipe. -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] pub struct PipeWriter(pub(crate) AnonPipe); @@ -160,7 +160,7 @@ impl PipeReader { /// # Ok(()) /// # } /// ``` - #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) } @@ -199,13 +199,13 @@ impl PipeWriter { /// # Ok(()) /// # } /// ``` - #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "anonymous_pipe", since = "1.87.0")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Read for &PipeReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -225,7 +225,7 @@ impl io::Read for &PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Read for PipeReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -245,7 +245,7 @@ impl io::Read for PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Write for &PipeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -263,7 +263,7 @@ impl io::Write for &PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl io::Write for PipeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) diff --git a/std/src/lib.rs b/std/src/lib.rs index 5c381181218df..3a52b7790376c 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -312,7 +312,6 @@ #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(no_sanitize)] #![feature(optimize_attribute)] #![feature(prelude_import)] #![feature(rustc_attrs)] diff --git a/std/src/os/fd/owned.rs b/std/src/os/fd/owned.rs index be73e7dee9c7b..10e1e73a115bd 100644 --- a/std/src/os/fd/owned.rs +++ b/std/src/os/fd/owned.rs @@ -505,7 +505,7 @@ impl<'a> AsFd for io::StderrLock<'a> { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeReader { fn as_fd(&self) -> BorrowedFd<'_> { @@ -513,7 +513,7 @@ impl AsFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeReader) -> Self { @@ -521,7 +521,7 @@ impl From for OwnedFd { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeWriter { fn as_fd(&self) -> BorrowedFd<'_> { @@ -529,7 +529,7 @@ impl AsFd for io::PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeWriter) -> Self { @@ -537,7 +537,7 @@ impl From for OwnedFd { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for io::PipeReader { fn from(owned_fd: OwnedFd) -> Self { @@ -545,7 +545,7 @@ impl From for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for io::PipeWriter { fn from(owned_fd: OwnedFd) -> Self { diff --git a/std/src/os/fd/raw.rs b/std/src/os/fd/raw.rs index c800c1489ad27..34a6cf1a8b84d 100644 --- a/std/src/os/fd/raw.rs +++ b/std/src/os/fd/raw.rs @@ -285,7 +285,7 @@ impl AsRawFd for Box { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeReader { fn as_raw_fd(&self) -> RawFd { @@ -293,7 +293,7 @@ impl AsRawFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeReader { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { @@ -301,7 +301,7 @@ impl FromRawFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeReader { fn into_raw_fd(self) -> RawFd { @@ -309,7 +309,7 @@ impl IntoRawFd for io::PipeReader { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeWriter { fn as_raw_fd(&self) -> RawFd { @@ -317,7 +317,7 @@ impl AsRawFd for io::PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeWriter { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { @@ -325,7 +325,7 @@ impl FromRawFd for io::PipeWriter { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeWriter { fn into_raw_fd(self) -> RawFd { diff --git a/std/src/os/windows/io/handle.rs b/std/src/os/windows/io/handle.rs index 7f21929b85f99..4fc04b79315f9 100644 --- a/std/src/os/windows/io/handle.rs +++ b/std/src/os/windows/io/handle.rs @@ -661,42 +661,42 @@ impl From> for OwnedHandle { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeReader { fn as_handle(&self) -> BorrowedHandle<'_> { self.0.as_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { fn from(pipe: io::PipeReader) -> Self { pipe.into_inner().into_inner() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeWriter { fn as_handle(&self) -> BorrowedHandle<'_> { self.0.as_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { fn from(pipe: io::PipeWriter) -> Self { pipe.into_inner().into_inner() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeReader { fn from(owned_handle: OwnedHandle) -> Self { Self::from_inner(FromInner::from_inner(owned_handle)) } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeWriter { fn from(owned_handle: OwnedHandle) -> Self { Self::from_inner(FromInner::from_inner(owned_handle)) diff --git a/std/src/os/windows/io/raw.rs b/std/src/os/windows/io/raw.rs index bc3e55c862962..a3ec7440338d2 100644 --- a/std/src/os/windows/io/raw.rs +++ b/std/src/os/windows/io/raw.rs @@ -311,42 +311,42 @@ impl IntoRawSocket for net::UdpSocket { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeReader { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeReader { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeReader { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeWriter { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeWriter { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeWriter { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() diff --git a/std/src/panicking.rs b/std/src/panicking.rs index b35549c92ada7..a3950980b5e31 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -55,14 +55,14 @@ pub static EMPTY_PANIC: fn(&'static str) -> ! = // hook up these functions, but it is not this day! #[allow(improper_ctypes)] unsafe extern "C" { - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); } unsafe extern "Rust" { /// `PanicPayload` lazily performs allocation only when needed (this avoids /// allocations when using the "abort" panic runtime). - #[cfg_attr(not(bootstrap), rustc_std_internal_symbol)] + #[rustc_std_internal_symbol] fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32; } diff --git a/std/src/prelude/v1.rs b/std/src/prelude/v1.rs index 4217f65864072..c15d8c40085a5 100644 --- a/std/src/prelude/v1.rs +++ b/std/src/prelude/v1.rs @@ -109,7 +109,6 @@ pub use core::prelude::v1::deref; issue = "63063", reason = "`type_alias_impl_trait` has open design concerns" )] -#[cfg(not(bootstrap))] pub use core::prelude::v1::define_opaque; // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated diff --git a/std/src/process.rs b/std/src/process.rs index 3b765a9537bc9..76ce7bce81b15 100644 --- a/std/src/process.rs +++ b/std/src/process.rs @@ -1286,6 +1286,40 @@ pub struct Output { pub stderr: Vec, } +impl Output { + /// Returns an error if a nonzero exit status was received. + /// + /// If the [`Command`] exited successfully, + /// `self` is returned. + /// + /// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok) + /// on [`Output.status`](Output::status). + /// + /// Note that this will throw away the [`Output::stderr`] field in the error case. + /// If the child process outputs useful informantion to stderr, you can: + /// * Use `cmd.stderr(Stdio::inherit())` to forward the + /// stderr child process to the parent's stderr, + /// usually printing it to console where the user can see it. + /// This is usually correct for command-line applications. + /// * Capture `stderr` using a custom error type. + /// This is usually correct for libraries. + /// + /// # Examples + /// + /// ``` + /// #![feature(exit_status_error)] + /// # #[cfg(unix)] { + /// use std::process::Command; + /// assert!(Command::new("false").output().unwrap().exit_ok().is_err()); + /// # } + /// ``` + #[unstable(feature = "exit_status_error", issue = "84908")] + pub fn exit_ok(self) -> Result { + self.status.exit_ok()?; + Ok(self) + } +} + // If either stderr or stdout are valid utf8 strings it prints the valid // strings, otherwise it prints the byte sequence instead #[stable(feature = "process_output_debug", since = "1.7.0")] @@ -1659,14 +1693,14 @@ impl From for Stdio { } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for Stdio { fn from(pipe: io::PipeWriter) -> Self { Stdio::from_inner(pipe.into_inner().into()) } } -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for Stdio { fn from(pipe: io::PipeReader) -> Self { Stdio::from_inner(pipe.into_inner().into()) diff --git a/std/src/sync/mpmc/list.rs b/std/src/sync/mpmc/list.rs index d88914f529142..1c6acb29e375f 100644 --- a/std/src/sync/mpmc/list.rs +++ b/std/src/sync/mpmc/list.rs @@ -213,6 +213,11 @@ impl Channel { .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed) .is_ok() { + // This yield point leaves the channel in a half-initialized state where the + // tail.block pointer is set but the head.block is not. This is used to + // facilitate the test in src/tools/miri/tests/pass/issues/issue-139553.rs + #[cfg(miri)] + crate::thread::yield_now(); self.head.block.store(new, Ordering::Release); block = new; } else { @@ -564,9 +569,15 @@ impl Channel { // In that case, just wait until it gets initialized. while block.is_null() { backoff.spin_heavy(); - block = self.head.block.load(Ordering::Acquire); + block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel); } } + // After this point `head.block` is not modified again and it will be deallocated if it's + // non-null. The `Drop` code of the channel, which runs after this function, also attempts + // to deallocate `head.block` if it's non-null. Therefore this function must maintain the + // invariant that if a deallocation of head.block is attemped then it must also be set to + // NULL. Failing to do so will lead to the Drop code attempting a double free. For this + // reason both reads above do an atomic swap instead of a simple atomic load. unsafe { // Drop all messages between head and tail and deallocate the heap-allocated blocks. diff --git a/std/src/sync/poison/mutex.rs b/std/src/sync/poison/mutex.rs index 9362c764173a8..adb74bb6f3de7 100644 --- a/std/src/sync/poison/mutex.rs +++ b/std/src/sync/poison/mutex.rs @@ -582,7 +582,9 @@ impl Mutex { /// Returns a mutable reference to the underlying data. /// /// Since this call borrows the `Mutex` mutably, no actual locking needs to - /// take place -- the mutable borrow statically guarantees no locks exist. + /// take place -- the mutable borrow statically guarantees no new locks can be acquired + /// while this reference exists. Note that this method does not clear any previous abandoned locks + /// (e.g., via [`forget()`] on a [`MutexGuard`]). /// /// # Errors /// @@ -599,6 +601,8 @@ impl Mutex { /// *mutex.get_mut().unwrap() = 10; /// assert_eq!(*mutex.lock().unwrap(), 10); /// ``` + /// + /// [`forget()`]: mem::forget #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { let data = self.data.get_mut(); diff --git a/std/src/sync/poison/rwlock.rs b/std/src/sync/poison/rwlock.rs index f9d9321f5f2d8..a2abd4f692ec2 100644 --- a/std/src/sync/poison/rwlock.rs +++ b/std/src/sync/poison/rwlock.rs @@ -608,7 +608,9 @@ impl RwLock { /// Returns a mutable reference to the underlying data. /// /// Since this call borrows the `RwLock` mutably, no actual locking needs to - /// take place -- the mutable borrow statically guarantees no locks exist. + /// take place -- the mutable borrow statically guarantees no new locks can be acquired + /// while this reference exists. Note that this method does not clear any previously abandoned locks + /// (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). /// /// # Errors /// diff --git a/std/src/sys/args/common.rs b/std/src/sys/args/common.rs new file mode 100644 index 0000000000000..43ac5e9592348 --- /dev/null +++ b/std/src/sys/args/common.rs @@ -0,0 +1,43 @@ +use crate::ffi::OsString; +use crate::{fmt, vec}; + +pub struct Args { + iter: vec::IntoIter, +} + +impl !Send for Args {} +impl !Sync for Args {} + +impl Args { + pub(super) fn new(args: Vec) -> Self { + Args { iter: args.into_iter() } + } +} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.iter.as_slice().fmt(f) + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/std/src/sys/pal/hermit/args.rs b/std/src/sys/args/hermit.rs similarity index 59% rename from std/src/sys/pal/hermit/args.rs rename to std/src/sys/args/hermit.rs index 4402426027730..ddd644a554044 100644 --- a/std/src/sys/pal/hermit/args.rs +++ b/std/src/sys/args/hermit.rs @@ -1,8 +1,12 @@ use crate::ffi::{CStr, OsString, c_char}; use crate::os::hermit::ffi::OsStringExt; +use crate::ptr; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicIsize, AtomicPtr}; -use crate::{fmt, ptr, vec}; + +#[path = "common.rs"] +mod common; +pub use common::Args; static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); @@ -27,40 +31,5 @@ pub fn args() -> Args { }) .collect(); - Args { iter: args.into_iter() } -} - -pub struct Args { - iter: vec::IntoIter, -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl !Send for Args {} -impl !Sync for Args {} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } + Args::new(args) } diff --git a/std/src/sys/args/mod.rs b/std/src/sys/args/mod.rs new file mode 100644 index 0000000000000..f24d6eb123e03 --- /dev/null +++ b/std/src/sys/args/mod.rs @@ -0,0 +1,34 @@ +//! Platform-dependent command line arguments abstraction. + +#![forbid(unsafe_op_in_unsafe_fn)] + +cfg_if::cfg_if! { + if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] { + mod unix; + pub use unix::*; + } else if #[cfg(target_family = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/std/src/sys/pal/sgx/args.rs b/std/src/sys/args/sgx.rs similarity index 89% rename from std/src/sys/pal/sgx/args.rs rename to std/src/sys/args/sgx.rs index e62bf383954eb..efc4b79185227 100644 --- a/std/src/sys/pal/sgx/args.rs +++ b/std/src/sys/args/sgx.rs @@ -1,8 +1,10 @@ -use super::abi::usercalls::alloc; -use super::abi::usercalls::raw::ByteBuffer; +#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers + use crate::ffi::OsString; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::os_str::Buf; +use crate::sys::pal::abi::usercalls::alloc; +use crate::sys::pal::abi::usercalls::raw::ByteBuffer; use crate::sys_common::FromInner; use crate::{fmt, slice}; diff --git a/std/src/sys/pal/uefi/args.rs b/std/src/sys/args/uefi.rs similarity index 79% rename from std/src/sys/pal/uefi/args.rs rename to std/src/sys/args/uefi.rs index 0c29caf2db676..84406c7f69df2 100644 --- a/std/src/sys/pal/uefi/args.rs +++ b/std/src/sys/args/uefi.rs @@ -1,14 +1,13 @@ use r_efi::protocols::loaded_image; -use super::helpers; use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; -use crate::{fmt, vec}; +use crate::sys::pal::helpers; -pub struct Args { - parsed_args_list: vec::IntoIter, -} +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); @@ -22,51 +21,17 @@ pub fn args() -> Args { let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize; // Break if we are sure that it cannot be UTF-16 if lp_size < size_of::() || lp_size % size_of::() != 0 { - return Args { parsed_args_list: lazy_current_exe().into_iter() }; + return Args::new(lazy_current_exe()); } let lp_size = lp_size / size_of::(); let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 }; if !lp_cmd_line.is_aligned() { - return Args { parsed_args_list: lazy_current_exe().into_iter() }; + return Args::new(lazy_current_exe()); } let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) }; - Args { - parsed_args_list: parse_lp_cmd_line(lp_cmd_line) - .unwrap_or_else(lazy_current_exe) - .into_iter(), - } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } + Args::new(parse_lp_cmd_line(lp_cmd_line).unwrap_or_else(lazy_current_exe)) } /// Implements the UEFI command-line argument parsing algorithm. diff --git a/std/src/sys/pal/unix/args.rs b/std/src/sys/args/unix.rs similarity index 85% rename from std/src/sys/pal/unix/args.rs rename to std/src/sys/args/unix.rs index 0bb7b64007aba..7d7815c6dff23 100644 --- a/std/src/sys/pal/unix/args.rs +++ b/std/src/sys/args/unix.rs @@ -5,13 +5,16 @@ #![allow(dead_code)] // runtime init functions not used during testing -use crate::ffi::{CStr, OsString}; +use crate::ffi::CStr; use crate::os::unix::ffi::OsStringExt; -use crate::{fmt, vec}; + +#[path = "common.rs"] +mod common; +pub use common::Args; /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { - imp::init(argc, argv) + unsafe { imp::init(argc, argv) } } /// Returns the command line arguments @@ -55,42 +58,7 @@ pub fn args() -> Args { vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec())); } - Args { iter: vec.into_iter() } -} - -pub struct Args { - iter: vec::IntoIter, -} - -impl !Send for Args {} -impl !Sync for Args {} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } + Args::new(vec) } #[cfg(any( @@ -141,7 +109,7 @@ mod imp { pub unsafe fn init(argc: isize, argv: *const *const u8) { // on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work" // BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc. - really_init(argc, argv); + unsafe { really_init(argc, argv) }; } /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. @@ -159,9 +127,7 @@ mod imp { argv: *const *const u8, _envp: *const *const u8, ) { - unsafe { - really_init(argc as isize, argv); - } + unsafe { really_init(argc as isize, argv) }; } init_wrapper }; @@ -228,16 +194,3 @@ mod imp { (argc as isize, argv.cast()) } } - -#[cfg(any(target_os = "espidf", target_os = "vita"))] -mod imp { - use crate::ffi::c_char; - use crate::ptr; - - #[inline(always)] - pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - - pub fn argc_argv() -> (isize, *const *const c_char) { - (0, ptr::null()) - } -} diff --git a/std/src/sys/pal/unsupported/args.rs b/std/src/sys/args/unsupported.rs similarity index 100% rename from std/src/sys/pal/unsupported/args.rs rename to std/src/sys/args/unsupported.rs diff --git a/std/src/sys/args/wasi.rs b/std/src/sys/args/wasi.rs new file mode 100644 index 0000000000000..4795789e4c717 --- /dev/null +++ b/std/src/sys/args/wasi.rs @@ -0,0 +1,29 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +use crate::ffi::{CStr, OsStr, OsString}; +use crate::os::wasi::ffi::OsStrExt; + +#[path = "common.rs"] +mod common; +pub use common::Args; + +/// Returns the command line arguments +pub fn args() -> Args { + Args::new(maybe_args().unwrap_or(Vec::new())) +} + +fn maybe_args() -> Option> { + unsafe { + let (argc, buf_size) = wasi::args_sizes_get().ok()?; + let mut argv = Vec::with_capacity(argc); + let mut buf = Vec::with_capacity(buf_size); + wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?; + argv.set_len(argc); + let mut ret = Vec::with_capacity(argc); + for ptr in argv { + let s = CStr::from_ptr(ptr.cast()); + ret.push(OsStr::from_bytes(s.to_bytes()).to_owned()); + } + Some(ret) + } +} diff --git a/std/src/sys/pal/windows/args.rs b/std/src/sys/args/windows.rs similarity index 94% rename from std/src/sys/pal/windows/args.rs rename to std/src/sys/args/windows.rs index d973743639ab0..47f0e5f2d05f8 100644 --- a/std/src/sys/pal/windows/args.rs +++ b/std/src/sys/args/windows.rs @@ -6,17 +6,21 @@ #[cfg(test)] mod tests; -use super::ensure_no_nuls; -use super::os::current_exe; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; +use crate::sys::pal::os::current_exe; +use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::path::get_long_path; use crate::sys::{c, to_u16s}; use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; -use crate::{fmt, io, iter, vec}; +use crate::{io, iter, ptr}; + +#[path = "common.rs"] +mod common; +pub use common::Args; pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 @@ -27,7 +31,7 @@ pub fn args() -> Args { current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()) }); - Args { parsed_args_list: parsed_args_list.into_iter() } + Args::new(parsed_args_list) } } @@ -153,38 +157,6 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( ret_val } -pub struct Args { - parsed_args_list: vec::IntoIter, -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} - #[derive(Debug)] pub(crate) enum Arg { /// Add quotes (if needed) @@ -384,9 +356,6 @@ pub(crate) fn to_user_path(path: &Path) -> io::Result> { from_wide_to_user_path(to_u16s(path)?) } pub(crate) fn from_wide_to_user_path(mut path: Vec) -> io::Result> { - use super::fill_utf16_buf; - use crate::ptr; - // UTF-16 encoded code points, used in parsing and building UTF-16 paths. // All of these are in the ASCII range so they can be cast directly to `u16`. const SEP: u16 = b'\\' as _; diff --git a/std/src/sys/pal/windows/args/tests.rs b/std/src/sys/args/windows/tests.rs similarity index 100% rename from std/src/sys/pal/windows/args/tests.rs rename to std/src/sys/args/windows/tests.rs diff --git a/std/src/sys/args/xous.rs b/std/src/sys/args/xous.rs new file mode 100644 index 0000000000000..09a47283d6573 --- /dev/null +++ b/std/src/sys/args/xous.rs @@ -0,0 +1,23 @@ +use crate::sys::pal::os::get_application_parameters; +use crate::sys::pal::os::params::ArgumentList; + +#[path = "common.rs"] +mod common; +pub use common::Args; + +pub fn args() -> Args { + let Some(params) = get_application_parameters() else { + return Args::new(vec![]); + }; + + for param in params { + if let Ok(args) = ArgumentList::try_from(¶m) { + let mut parsed_args = vec![]; + for arg in args { + parsed_args.push(arg.into()); + } + return Args::new(parsed_args); + } + } + Args::new(vec![]) +} diff --git a/std/src/sys/pal/zkvm/args.rs b/std/src/sys/args/zkvm.rs similarity index 98% rename from std/src/sys/pal/zkvm/args.rs rename to std/src/sys/args/zkvm.rs index 47857f6c448bc..194ba7159d459 100644 --- a/std/src/sys/pal/zkvm/args.rs +++ b/std/src/sys/args/zkvm.rs @@ -1,7 +1,7 @@ -use super::{WORD_SIZE, abi}; use crate::ffi::OsString; use crate::fmt; use crate::sys::os_str; +use crate::sys::pal::{WORD_SIZE, abi}; use crate::sys_common::FromInner; pub struct Args { diff --git a/std/src/sys/cmath.rs b/std/src/sys/cmath.rs index c9969b4e376ea..668fd92853400 100644 --- a/std/src/sys/cmath.rs +++ b/std/src/sys/cmath.rs @@ -3,70 +3,70 @@ // These symbols are all defined by `libm`, // or by `compiler-builtins` on unsupported platforms. unsafe extern "C" { - pub fn acos(n: f64) -> f64; - pub fn asin(n: f64) -> f64; - pub fn atan(n: f64) -> f64; - pub fn atan2(a: f64, b: f64) -> f64; - pub fn cbrt(n: f64) -> f64; - pub fn cbrtf(n: f32) -> f32; - pub fn cosh(n: f64) -> f64; - pub fn expm1(n: f64) -> f64; - pub fn expm1f(n: f32) -> f32; - pub fn fdim(a: f64, b: f64) -> f64; - pub fn fdimf(a: f32, b: f32) -> f32; + pub safe fn acos(n: f64) -> f64; + pub safe fn asin(n: f64) -> f64; + pub safe fn atan(n: f64) -> f64; + pub safe fn atan2(a: f64, b: f64) -> f64; + pub safe fn cbrt(n: f64) -> f64; + pub safe fn cbrtf(n: f32) -> f32; + pub safe fn cosh(n: f64) -> f64; + pub safe fn expm1(n: f64) -> f64; + pub safe fn expm1f(n: f32) -> f32; + pub safe fn fdim(a: f64, b: f64) -> f64; + pub safe fn fdimf(a: f32, b: f32) -> f32; #[cfg_attr(target_env = "msvc", link_name = "_hypot")] - pub fn hypot(x: f64, y: f64) -> f64; + pub safe fn hypot(x: f64, y: f64) -> f64; #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] - pub fn hypotf(x: f32, y: f32) -> f32; - pub fn log1p(n: f64) -> f64; - pub fn log1pf(n: f32) -> f32; - pub fn sinh(n: f64) -> f64; - pub fn tan(n: f64) -> f64; - pub fn tanh(n: f64) -> f64; - pub fn tgamma(n: f64) -> f64; - pub fn tgammaf(n: f32) -> f32; - pub fn lgamma_r(n: f64, s: &mut i32) -> f64; + pub safe fn hypotf(x: f32, y: f32) -> f32; + pub safe fn log1p(n: f64) -> f64; + pub safe fn log1pf(n: f32) -> f32; + pub safe fn sinh(n: f64) -> f64; + pub safe fn tan(n: f64) -> f64; + pub safe fn tanh(n: f64) -> f64; + pub safe fn tgamma(n: f64) -> f64; + pub safe fn tgammaf(n: f32) -> f32; + pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64; #[cfg(not(target_os = "aix"))] - pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; - pub fn erf(n: f64) -> f64; - pub fn erff(n: f32) -> f32; - pub fn erfc(n: f64) -> f64; - pub fn erfcf(n: f32) -> f32; + pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32; + pub safe fn erf(n: f64) -> f64; + pub safe fn erff(n: f32) -> f32; + pub safe fn erfc(n: f64) -> f64; + pub safe fn erfcf(n: f32) -> f32; - pub fn acosf128(n: f128) -> f128; - pub fn asinf128(n: f128) -> f128; - pub fn atanf128(n: f128) -> f128; - pub fn atan2f128(a: f128, b: f128) -> f128; - pub fn cbrtf128(n: f128) -> f128; - pub fn coshf128(n: f128) -> f128; - pub fn expm1f128(n: f128) -> f128; - pub fn hypotf128(x: f128, y: f128) -> f128; - pub fn log1pf128(n: f128) -> f128; - pub fn sinhf128(n: f128) -> f128; - pub fn tanf128(n: f128) -> f128; - pub fn tanhf128(n: f128) -> f128; - pub fn tgammaf128(n: f128) -> f128; - pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128; - pub fn erff128(n: f128) -> f128; - pub fn erfcf128(n: f128) -> f128; + pub safe fn acosf128(n: f128) -> f128; + pub safe fn asinf128(n: f128) -> f128; + pub safe fn atanf128(n: f128) -> f128; + pub safe fn atan2f128(a: f128, b: f128) -> f128; + pub safe fn cbrtf128(n: f128) -> f128; + pub safe fn coshf128(n: f128) -> f128; + pub safe fn expm1f128(n: f128) -> f128; + pub safe fn hypotf128(x: f128, y: f128) -> f128; + pub safe fn log1pf128(n: f128) -> f128; + pub safe fn sinhf128(n: f128) -> f128; + pub safe fn tanf128(n: f128) -> f128; + pub safe fn tanhf128(n: f128) -> f128; + pub safe fn tgammaf128(n: f128) -> f128; + pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128; + pub safe fn erff128(n: f128) -> f128; + pub safe fn erfcf128(n: f128) -> f128; cfg_if::cfg_if! { if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] { - pub fn acosf(n: f32) -> f32; - pub fn asinf(n: f32) -> f32; - pub fn atan2f(a: f32, b: f32) -> f32; - pub fn atanf(n: f32) -> f32; - pub fn coshf(n: f32) -> f32; - pub fn sinhf(n: f32) -> f32; - pub fn tanf(n: f32) -> f32; - pub fn tanhf(n: f32) -> f32; + pub safe fn acosf(n: f32) -> f32; + pub safe fn asinf(n: f32) -> f32; + pub safe fn atan2f(a: f32, b: f32) -> f32; + pub safe fn atanf(n: f32) -> f32; + pub safe fn coshf(n: f32) -> f32; + pub safe fn sinhf(n: f32) -> f32; + pub safe fn tanf(n: f32) -> f32; + pub safe fn tanhf(n: f32) -> f32; }} } // On AIX, we don't have lgammaf_r only the f64 version, so we can // use the f64 version lgamma_r #[cfg(target_os = "aix")] -pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { +pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 { lgamma_r(n.into(), s) as f32 } @@ -76,42 +76,42 @@ pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 { cfg_if::cfg_if! { if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] { #[inline] - pub unsafe fn acosf(n: f32) -> f32 { + pub fn acosf(n: f32) -> f32 { f64::acos(n as f64) as f32 } #[inline] - pub unsafe fn asinf(n: f32) -> f32 { + pub fn asinf(n: f32) -> f32 { f64::asin(n as f64) as f32 } #[inline] - pub unsafe fn atan2f(n: f32, b: f32) -> f32 { + pub fn atan2f(n: f32, b: f32) -> f32 { f64::atan2(n as f64, b as f64) as f32 } #[inline] - pub unsafe fn atanf(n: f32) -> f32 { + pub fn atanf(n: f32) -> f32 { f64::atan(n as f64) as f32 } #[inline] - pub unsafe fn coshf(n: f32) -> f32 { + pub fn coshf(n: f32) -> f32 { f64::cosh(n as f64) as f32 } #[inline] - pub unsafe fn sinhf(n: f32) -> f32 { + pub fn sinhf(n: f32) -> f32 { f64::sinh(n as f64) as f32 } #[inline] - pub unsafe fn tanf(n: f32) -> f32 { + pub fn tanf(n: f32) -> f32 { f64::tan(n as f64) as f32 } #[inline] - pub unsafe fn tanhf(n: f32) -> f32 { + pub fn tanhf(n: f32) -> f32 { f64::tanh(n as f64) as f32 } }} diff --git a/std/src/sys/fd/unix.rs b/std/src/sys/fd/unix.rs index 2042ea2c73d00..cdca73cdca11e 100644 --- a/std/src/sys/fd/unix.rs +++ b/std/src/sys/fd/unix.rs @@ -71,9 +71,11 @@ const fn max_iov() -> usize { target_os = "android", target_os = "dragonfly", target_os = "emscripten", + target_os = "espidf", target_os = "freebsd", target_os = "linux", target_os = "netbsd", + target_os = "nuttx", target_os = "nto", target_os = "openbsd", target_os = "horizon", @@ -257,9 +259,6 @@ impl FileDesc { } #[cfg(all(target_os = "android", target_pointer_width = "32"))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { weak!( fn preadv64( diff --git a/std/src/sys/fs/mod.rs b/std/src/sys/fs/mod.rs index 3b176d0d16c44..4c5e36ce67a3b 100644 --- a/std/src/sys/fs/mod.rs +++ b/std/src/sys/fs/mod.rs @@ -20,6 +20,7 @@ cfg_if::cfg_if! { mod windows; use windows as imp; pub use windows::{symlink_inner, junction_point}; + use crate::sys::path::with_native_path; } else if #[cfg(target_os = "hermit")] { mod hermit; use hermit as imp; @@ -39,7 +40,7 @@ cfg_if::cfg_if! { } // FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(target_family = "unix"))] +#[cfg(not(any(target_family = "unix", target_os = "windows")))] #[inline] pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { f(path) @@ -51,7 +52,7 @@ pub use imp::{ }; pub fn read_dir(path: &Path) -> io::Result { - // FIXME: use with_native_path + // FIXME: use with_native_path on all platforms imp::readdir(path) } @@ -68,8 +69,11 @@ pub fn remove_dir(path: &Path) -> io::Result<()> { } pub fn remove_dir_all(path: &Path) -> io::Result<()> { - // FIXME: use with_native_path - imp::remove_dir_all(path) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::remove_dir_all(path); + #[cfg(windows)] + with_native_path(path, &imp::remove_dir_all) } pub fn read_link(path: &Path) -> io::Result { @@ -77,6 +81,10 @@ pub fn read_link(path: &Path) -> io::Result { } pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + // FIXME: use with_native_path on all platforms + #[cfg(windows)] + return imp::symlink(original, link); + #[cfg(not(windows))] with_native_path(original, &|original| { with_native_path(link, &|link| imp::symlink(original, link)) }) @@ -105,11 +113,17 @@ pub fn canonicalize(path: &Path) -> io::Result { } pub fn copy(from: &Path, to: &Path) -> io::Result { - // FIXME: use with_native_path - imp::copy(from, to) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::copy(from, to); + #[cfg(windows)] + with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to))) } pub fn exists(path: &Path) -> io::Result { - // FIXME: use with_native_path - imp::exists(path) + // FIXME: use with_native_path on all platforms + #[cfg(not(windows))] + return imp::exists(path); + #[cfg(windows)] + with_native_path(path, &imp::exists) } diff --git a/std/src/sys/fs/unix.rs b/std/src/sys/fs/unix.rs index 87865be0387d5..687fc322e598d 100644 --- a/std/src/sys/fs/unix.rs +++ b/std/src/sys/fs/unix.rs @@ -1463,20 +1463,6 @@ impl File { Ok(()) } - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr( - any( - target_os = "android", - all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ) - ), - no_sanitize(cfi) - )] pub fn set_times(&self, times: FileTimes) -> io::Result<()> { #[cfg(not(any( target_os = "redox", diff --git a/std/src/sys/fs/windows.rs b/std/src/sys/fs/windows.rs index 15727c996837b..9215f93756710 100644 --- a/std/src/sys/fs/windows.rs +++ b/std/src/sys/fs/windows.rs @@ -12,7 +12,7 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::pal::api::{self, WinError, set_file_information_by_handle}; use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul}; -use crate::sys::path::maybe_verbatim; +use crate::sys::path::{WCStr, maybe_verbatim}; use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -298,10 +298,12 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = maybe_verbatim(path)?; + // SAFETY: maybe_verbatim returns null-terminated strings + let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) }; Self::open_native(&path, opts) } - fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result { + fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result { let creation = opts.get_creation_mode()?; let handle = unsafe { c::CreateFileW( @@ -1212,9 +1214,8 @@ pub fn readdir(p: &Path) -> io::Result { } } -pub fn unlink(p: &Path) -> io::Result<()> { - let p_u16s = maybe_verbatim(p)?; - if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 { +pub fn unlink(path: &WCStr) -> io::Result<()> { + if unsafe { c::DeleteFileW(path.as_ptr()) } == 0 { let err = api::get_last_error(); // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove // the file while ignoring the readonly attribute. @@ -1223,7 +1224,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { let mut opts = OpenOptions::new(); opts.access_mode(c::DELETE); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); - if let Ok(f) = File::open_native(&p_u16s, &opts) { + if let Ok(f) = File::open_native(&path, &opts) { if f.posix_delete().is_ok() { return Ok(()); } @@ -1236,10 +1237,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { } } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = maybe_verbatim(old)?; - let new = maybe_verbatim(new)?; - +pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> { if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { let err = api::get_last_error(); // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move @@ -1253,7 +1251,8 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. - let Ok(new_len_without_nul_in_bytes): Result = ((new.len() - 1) * 2).try_into() + let Ok(new_len_without_nul_in_bytes): Result = + ((new.count_bytes() - 1) * 2).try_into() else { return Err(err).io_result(); }; @@ -1282,7 +1281,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { new.as_ptr().copy_to_nonoverlapping( (&raw mut (*file_rename_info).FileName).cast::(), - new.len(), + new.count_bytes(), ); } @@ -1309,20 +1308,19 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { Ok(()) } -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = maybe_verbatim(p)?; +pub fn rmdir(p: &WCStr) -> io::Result<()> { cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { +pub fn remove_dir_all(path: &WCStr) -> io::Result<()> { // Open a file or directory without following symlinks. let mut opts = OpenOptions::new(); opts.access_mode(c::FILE_LIST_DIRECTORY); // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; + let file = File::open_native(path, &opts)?; // Test if the file is not a directory or a symlink to a directory. if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { @@ -1333,14 +1331,14 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { remove_dir_all_iterative(file).io_result() } -pub fn readlink(path: &Path) -> io::Result { +pub fn readlink(path: &WCStr) -> io::Result { // Open the link with no access mode, instead of generic read. // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so // this is needed for a common case. let mut opts = OpenOptions::new(); opts.access_mode(0); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; + let file = File::open_native(&path, &opts)?; file.readlink() } @@ -1378,19 +1376,17 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> } #[cfg(not(target_vendor = "uwp"))] -pub fn link(original: &Path, link: &Path) -> io::Result<()> { - let original = maybe_verbatim(original)?; - let link = maybe_verbatim(link)?; +pub fn link(original: &WCStr, link: &WCStr) -> io::Result<()> { cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?; Ok(()) } #[cfg(target_vendor = "uwp")] -pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn link(_original: &WCStr, _link: &WCStr) -> io::Result<()> { return Err(io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP")); } -pub fn stat(path: &Path) -> io::Result { +pub fn stat(path: &WCStr) -> io::Result { match metadata(path, ReparsePoint::Follow) { Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => { if let Ok(attrs) = lstat(path) { @@ -1404,7 +1400,7 @@ pub fn stat(path: &Path) -> io::Result { } } -pub fn lstat(path: &Path) -> io::Result { +pub fn lstat(path: &WCStr) -> io::Result { metadata(path, ReparsePoint::Open) } @@ -1420,7 +1416,7 @@ impl ReparsePoint { } } -fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { +fn metadata(path: &WCStr, reparse: ReparsePoint) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); @@ -1429,7 +1425,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { // Attempt to open the file normally. // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`. // If the fallback fails for any reason we return the original error. - match File::open(path, &opts) { + match File::open_native(&path, &opts) { Ok(file) => file.file_attr(), Err(e) if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)] @@ -1442,8 +1438,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { // However, there are special system files, such as // `C:\hiberfil.sys`, that are locked in a way that denies even that. unsafe { - let path = maybe_verbatim(path)?; - // `FindFirstFileExW` accepts wildcard file names. // Fortunately wildcards are not valid file names and // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) @@ -1482,8 +1476,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { } } -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = maybe_verbatim(p)?; +pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> { unsafe { cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; Ok(()) @@ -1499,17 +1492,17 @@ fn get_path(f: &File) -> io::Result { ) } -pub fn canonicalize(p: &Path) -> io::Result { +pub fn canonicalize(p: &WCStr) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); // This flag is so we can open directories too opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(p, &opts)?; + let f = File::open_native(p, &opts)?; get_path(&f) } -pub fn copy(from: &Path, to: &Path) -> io::Result { +pub fn copy(from: &WCStr, to: &WCStr) -> io::Result { unsafe extern "system" fn callback( _TotalFileSize: i64, _TotalBytesTransferred: i64, @@ -1528,13 +1521,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { c::PROGRESS_CONTINUE } } - let pfrom = maybe_verbatim(from)?; - let pto = maybe_verbatim(to)?; let mut size = 0i64; cvt(unsafe { c::CopyFileExW( - pfrom.as_ptr(), - pto.as_ptr(), + from.as_ptr(), + to.as_ptr(), Some(callback), (&raw mut size) as *mut _, ptr::null_mut(), @@ -1624,14 +1615,14 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } // Try to see if a file exists but, unlike `exists`, report I/O errors. -pub fn exists(path: &Path) -> io::Result { +pub fn exists(path: &WCStr) -> io::Result { // Open the file to ensure any symlinks are followed to their target. let mut opts = OpenOptions::new(); // No read, write, etc access rights are needed. opts.access_mode(0); // Backup semantics enables opening directories as well as files. opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - match File::open(path, &opts) { + match File::open_native(path, &opts) { Err(e) => match e.kind() { // The file definitely does not exist io::ErrorKind::NotFound => Ok(false), diff --git a/std/src/sys/fs/windows/remove_dir_all.rs b/std/src/sys/fs/windows/remove_dir_all.rs index f51eced84164f..b213c49bcb001 100644 --- a/std/src/sys/fs/windows/remove_dir_all.rs +++ b/std/src/sys/fs/windows/remove_dir_all.rs @@ -95,7 +95,7 @@ fn open_link_no_reparse( ObjectName: &mut path_str, RootDirectory: parent.as_raw_handle(), Attributes: ATTRIBUTES.load(Ordering::Relaxed), - ..c::OBJECT_ATTRIBUTES::default() + ..c::OBJECT_ATTRIBUTES::with_length() }; let share = c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE; let options = c::FILE_OPEN_REPARSE_POINT | options; diff --git a/std/src/sys/mod.rs b/std/src/sys/mod.rs index f8f220fafd1d1..bc4bf11cb7405 100644 --- a/std/src/sys/mod.rs +++ b/std/src/sys/mod.rs @@ -9,6 +9,7 @@ mod alloc; mod personality; pub mod anonymous_pipe; +pub mod args; pub mod backtrace; pub mod cmath; pub mod exit_guard; diff --git a/std/src/sys/net/connection/socket/unix.rs b/std/src/sys/net/connection/socket/unix.rs index bbe1e038dccf5..b35d5d2aa8418 100644 --- a/std/src/sys/net/connection/socket/unix.rs +++ b/std/src/sys/net/connection/socket/unix.rs @@ -1,5 +1,6 @@ use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t}; +#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] use crate::ffi::CStr; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Shutdown, SocketAddr}; diff --git a/std/src/sys/pal/hermit/mod.rs b/std/src/sys/pal/hermit/mod.rs index 26211bcb15202..821836824e2bc 100644 --- a/std/src/sys/pal/hermit/mod.rs +++ b/std/src/sys/pal/hermit/mod.rs @@ -18,7 +18,6 @@ use crate::os::raw::c_char; -pub mod args; pub mod env; pub mod futex; pub mod os; @@ -58,7 +57,7 @@ pub extern "C" fn __rust_abort() { // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { - args::init(argc, argv); + crate::sys::args::init(argc, argv); } } diff --git a/std/src/sys/pal/sgx/mod.rs b/std/src/sys/pal/sgx/mod.rs index 52684e18ac276..8a87e7a7ae13d 100644 --- a/std/src/sys/pal/sgx/mod.rs +++ b/std/src/sys/pal/sgx/mod.rs @@ -9,7 +9,6 @@ use crate::io::ErrorKind; use crate::sync::atomic::{AtomicBool, Ordering}; pub mod abi; -pub mod args; pub mod env; mod libunwind_integration; pub mod os; @@ -24,7 +23,7 @@ pub mod waitqueue; // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { unsafe { - args::init(argc, argv); + crate::sys::args::init(argc, argv); } } diff --git a/std/src/sys/pal/solid/mod.rs b/std/src/sys/pal/solid/mod.rs index 22052a168fd15..c41dc848a1b4a 100644 --- a/std/src/sys/pal/solid/mod.rs +++ b/std/src/sys/pal/solid/mod.rs @@ -16,8 +16,6 @@ pub mod itron { use super::unsupported; } -#[path = "../unsupported/args.rs"] -pub mod args; pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` diff --git a/std/src/sys/pal/teeos/mod.rs b/std/src/sys/pal/teeos/mod.rs index c1921a2f40df5..b8095cec3e978 100644 --- a/std/src/sys/pal/teeos/mod.rs +++ b/std/src/sys/pal/teeos/mod.rs @@ -6,8 +6,6 @@ #![allow(unused_variables)] #![allow(dead_code)] -#[path = "../unsupported/args.rs"] -pub mod args; #[path = "../unsupported/env.rs"] pub mod env; //pub mod fd; diff --git a/std/src/sys/pal/trusty/mod.rs b/std/src/sys/pal/trusty/mod.rs index 5295d3fdc9145..04e6b4c818687 100644 --- a/std/src/sys/pal/trusty/mod.rs +++ b/std/src/sys/pal/trusty/mod.rs @@ -1,7 +1,5 @@ //! System bindings for the Trusty OS. -#[path = "../unsupported/args.rs"] -pub mod args; #[path = "../unsupported/common.rs"] #[deny(unsafe_op_in_unsafe_fn)] mod common; diff --git a/std/src/sys/pal/uefi/mod.rs b/std/src/sys/pal/uefi/mod.rs index 9760a23084aad..cd901f48b76f8 100644 --- a/std/src/sys/pal/uefi/mod.rs +++ b/std/src/sys/pal/uefi/mod.rs @@ -13,7 +13,6 @@ //! [`OsString`]: crate::ffi::OsString #![forbid(unsafe_op_in_unsafe_fn)] -pub mod args; pub mod env; pub mod helpers; pub mod os; diff --git a/std/src/sys/pal/unix/mod.rs b/std/src/sys/pal/unix/mod.rs index d7106c339747b..3a790d9c868c9 100644 --- a/std/src/sys/pal/unix/mod.rs +++ b/std/src/sys/pal/unix/mod.rs @@ -6,7 +6,6 @@ use crate::io::ErrorKind; #[macro_use] pub mod weak; -pub mod args; pub mod env; #[cfg(target_os = "fuchsia")] pub mod fuchsia; @@ -27,6 +26,7 @@ pub mod time; pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] +#[cfg_attr(target_os = "vita", allow(unused_variables))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. // See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. @@ -47,7 +47,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { reset_sigpipe(sigpipe); stack_overflow::init(); - args::init(argc, argv); + #[cfg(not(target_os = "vita"))] + crate::sys::args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread // already exists, we have to call it ourselves. We only do this on Apple targets @@ -273,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ETXTBSY => ExecutableFileBusy, libc::EXDEV => CrossesDevices, libc::EINPROGRESS => InProgress, + libc::EOPNOTSUPP => Unsupported, libc::EACCES | libc::EPERM => PermissionDenied, diff --git a/std/src/sys/pal/unix/thread.rs b/std/src/sys/pal/unix/thread.rs index 9078dd1c23166..4cdc2eaf0e535 100644 --- a/std/src/sys/pal/unix/thread.rs +++ b/std/src/sys/pal/unix/thread.rs @@ -8,14 +8,19 @@ use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; use crate::time::Duration; use crate::{cmp, io, ptr}; -#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))] +#[cfg(not(any( + target_os = "l4re", + target_os = "vxworks", + target_os = "espidf", + target_os = "nuttx" +)))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; #[cfg(target_os = "vxworks")] pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; -#[cfg(target_os = "espidf")] -pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used +#[cfg(any(target_os = "espidf", target_os = "nuttx"))] +pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used #[cfg(target_os = "fuchsia")] mod zircon { @@ -52,10 +57,10 @@ impl Thread { let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); - #[cfg(target_os = "espidf")] + #[cfg(any(target_os = "espidf", target_os = "nuttx"))] if stack > 0 { // Only set the stack if a non-zero value is passed - // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used + // 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used assert_eq!( libc::pthread_attr_setstacksize( attr.as_mut_ptr(), @@ -65,7 +70,7 @@ impl Thread { ); } - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] { let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr())); @@ -189,9 +194,6 @@ impl Thread { } #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { weak!( fn pthread_setname_np( diff --git a/std/src/sys/pal/unix/time.rs b/std/src/sys/pal/unix/time.rs index b8469b1681f03..0074d7674741b 100644 --- a/std/src/sys/pal/unix/time.rs +++ b/std/src/sys/pal/unix/time.rs @@ -96,17 +96,6 @@ impl Timespec { } } - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr( - all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ), - no_sanitize(cfi) - )] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/std/src/sys/pal/unix/weak.rs b/std/src/sys/pal/unix/weak.rs index e4c814fba8cef..a034995e6525d 100644 --- a/std/src/sys/pal/unix/weak.rs +++ b/std/src/sys/pal/unix/weak.rs @@ -155,9 +155,6 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[no_sanitize(cfi)] unsafe fn $name($($param: $t),*) -> $ret { weak!(fn $name($($param: $t),*) -> $ret;); diff --git a/std/src/sys/pal/unsupported/mod.rs b/std/src/sys/pal/unsupported/mod.rs index 38838b915b5c1..dea42a95dcc6f 100644 --- a/std/src/sys/pal/unsupported/mod.rs +++ b/std/src/sys/pal/unsupported/mod.rs @@ -1,6 +1,5 @@ #![deny(unsafe_op_in_unsafe_fn)] -pub mod args; pub mod env; pub mod os; pub mod pipe; diff --git a/std/src/sys/pal/wasi/args.rs b/std/src/sys/pal/wasi/args.rs deleted file mode 100644 index 52cfa202af825..0000000000000 --- a/std/src/sys/pal/wasi/args.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::ffi::{CStr, OsStr, OsString}; -use crate::os::wasi::ffi::OsStrExt; -use crate::{fmt, vec}; - -pub struct Args { - iter: vec::IntoIter, -} - -impl !Send for Args {} -impl !Sync for Args {} - -/// Returns the command line arguments -pub fn args() -> Args { - Args { iter: maybe_args().unwrap_or(Vec::new()).into_iter() } -} - -fn maybe_args() -> Option> { - unsafe { - let (argc, buf_size) = wasi::args_sizes_get().ok()?; - let mut argv = Vec::with_capacity(argc); - let mut buf = Vec::with_capacity(buf_size); - wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?; - argv.set_len(argc); - let mut ret = Vec::with_capacity(argc); - for ptr in argv { - let s = CStr::from_ptr(ptr.cast()); - ret.push(OsStr::from_bytes(s.to_bytes()).to_owned()); - } - Some(ret) - } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} diff --git a/std/src/sys/pal/wasi/mod.rs b/std/src/sys/pal/wasi/mod.rs index 80853e7b5a26f..4ea42b1082b1d 100644 --- a/std/src/sys/pal/wasi/mod.rs +++ b/std/src/sys/pal/wasi/mod.rs @@ -13,7 +13,6 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -pub mod args; pub mod env; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] diff --git a/std/src/sys/pal/wasip2/mod.rs b/std/src/sys/pal/wasip2/mod.rs index 504b947d09e2c..6445bf2cc0d2c 100644 --- a/std/src/sys/pal/wasip2/mod.rs +++ b/std/src/sys/pal/wasip2/mod.rs @@ -6,8 +6,6 @@ //! To begin with, this target mirrors the wasi target 1 to 1, but over //! time this will change significantly. -#[path = "../wasi/args.rs"] -pub mod args; #[path = "../wasi/env.rs"] pub mod env; #[allow(unused)] diff --git a/std/src/sys/pal/wasm/mod.rs b/std/src/sys/pal/wasm/mod.rs index 8d39b70d0397a..af370020d96ab 100644 --- a/std/src/sys/pal/wasm/mod.rs +++ b/std/src/sys/pal/wasm/mod.rs @@ -16,8 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -#[path = "../unsupported/args.rs"] -pub mod args; pub mod env; #[path = "../unsupported/os.rs"] pub mod os; diff --git a/std/src/sys/pal/windows/c.rs b/std/src/sys/pal/windows/c.rs index 004cbee52f62a..ac1c5e9932e1c 100644 --- a/std/src/sys/pal/windows/c.rs +++ b/std/src/sys/pal/windows/c.rs @@ -44,8 +44,8 @@ impl UNICODE_STRING { } } -impl Default for OBJECT_ATTRIBUTES { - fn default() -> Self { +impl OBJECT_ATTRIBUTES { + pub fn with_length() -> Self { Self { Length: size_of::() as _, RootDirectory: ptr::null_mut(), diff --git a/std/src/sys/pal/windows/c/bindings.txt b/std/src/sys/pal/windows/c/bindings.txt index e2c2163327968..d5fbb453c6f96 100644 --- a/std/src/sys/pal/windows/c/bindings.txt +++ b/std/src/sys/pal/windows/c/bindings.txt @@ -1,7 +1,8 @@ --out windows_sys.rs --flat --sys ---no-core +--no-deps +--link windows_targets --filter !INVALID_HANDLE_VALUE ABOVE_NORMAL_PRIORITY_CLASS @@ -19,7 +20,6 @@ ALL_PROCESSOR_GROUPS ARM64_NT_NEON128 BELOW_NORMAL_PRIORITY_CLASS bind -BOOL BY_HANDLE_FILE_INFORMATION CALLBACK_CHUNK_FINISHED CALLBACK_STREAM_SWITCH diff --git a/std/src/sys/pal/windows/c/windows_sys.rs b/std/src/sys/pal/windows/c/windows_sys.rs index 1d0e89f5d0f0e..eb2914b864473 100644 --- a/std/src/sys/pal/windows/c/windows_sys.rs +++ b/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,4 +1,4 @@ -// Bindings generated by `windows-bindgen` 0.59.0 +// Bindings generated by `windows-bindgen` 0.61.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] @@ -141,7 +141,7 @@ windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32); pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ACL { pub AclRevision: u8, pub Sbz1: u8, @@ -162,6 +162,11 @@ pub struct ADDRINFOA { pub ai_addr: *mut SOCKADDR, pub ai_next: *mut ADDRINFOA, } +impl Default for ADDRINFOA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const AF_INET: ADDRESS_FAMILY = 2u16; pub const AF_INET6: ADDRESS_FAMILY = 23u16; pub const AF_UNIX: u16 = 1u16; @@ -176,8 +181,13 @@ pub union ARM64_NT_NEON128 { pub H: [u16; 8], pub B: [u8; 16], } +impl Default for ARM64_NT_NEON128 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ARM64_NT_NEON128_0 { pub Low: u64, pub High: i64, @@ -185,7 +195,7 @@ pub struct ARM64_NT_NEON128_0 { pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32; pub type BOOL = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct BY_HANDLE_FILE_INFORMATION { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -206,9 +216,14 @@ pub type COMPARESTRING_RESULT = i32; pub struct CONDITION_VARIABLE { pub Ptr: *mut core::ffi::c_void, } +impl Default for CONDITION_VARIABLE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type CONSOLE_MODE = u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct CONSOLE_READCONSOLE_CONTROL { pub nLength: u32, pub nInitialChars: u32, @@ -245,6 +260,12 @@ pub struct CONTEXT { pub SegSs: u32, pub ExtendedRegisters: [u8; 512], } +#[cfg(target_arch = "x86")] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -296,6 +317,12 @@ pub struct CONTEXT { pub LastExceptionToRip: u64, pub LastExceptionFromRip: u64, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -303,6 +330,12 @@ pub union CONTEXT_0 { pub FltSave: XSAVE_FORMAT, pub Anonymous: CONTEXT_0_0, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -326,6 +359,12 @@ pub struct CONTEXT_0_0 { pub Xmm14: M128A, pub Xmm15: M128A, } +#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for CONTEXT_0_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] #[derive(Clone, Copy)] @@ -343,6 +382,12 @@ pub struct CONTEXT { pub Wcr: [u32; 2], pub Wvr: [u64; 2], } +#[cfg(target_arch = "aarch64")] +impl Default for CONTEXT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] #[derive(Clone, Copy)] @@ -350,9 +395,15 @@ pub union CONTEXT_0 { pub Anonymous: CONTEXT_0_0, pub X: [u64; 31], } +#[cfg(target_arch = "aarch64")] +impl Default for CONTEXT_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "aarch64")] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct CONTEXT_0_0 { pub X0: u64, pub X1: u64, @@ -2305,6 +2356,11 @@ pub struct EXCEPTION_POINTERS { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ContextRecord: *mut CONTEXT, } +impl Default for EXCEPTION_POINTERS { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct EXCEPTION_RECORD { @@ -2315,6 +2371,11 @@ pub struct EXCEPTION_RECORD { pub NumberParameters: u32, pub ExceptionInformation: [usize; 15], } +impl Default for EXCEPTION_RECORD { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _; pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32; pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _; @@ -2333,8 +2394,13 @@ pub struct FD_SET { pub fd_count: u32, pub fd_array: [SOCKET; 64], } +impl Default for FD_SET { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, @@ -2343,7 +2409,7 @@ pub type FILE_ACCESS_RIGHTS = u32; pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32; pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_ALLOCATION_INFO { pub AllocationSize: i64, } @@ -2369,7 +2435,7 @@ pub const FILE_ATTRIBUTE_REPARSE_POINT: FILE_FLAGS_AND_ATTRIBUTES = 1024u32; pub const FILE_ATTRIBUTE_SPARSE_FILE: FILE_FLAGS_AND_ATTRIBUTES = 512u32; pub const FILE_ATTRIBUTE_SYSTEM: FILE_FLAGS_AND_ATTRIBUTES = 4u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_ATTRIBUTE_TAG_INFO { pub FileAttributes: u32, pub ReparseTag: u32, @@ -2378,7 +2444,7 @@ pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32; pub const FILE_ATTRIBUTE_UNPINNED: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32; pub const FILE_ATTRIBUTE_VIRTUAL: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_BASIC_INFO { pub CreationTime: i64, pub LastAccessTime: i64, @@ -2405,19 +2471,19 @@ pub const FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE: FILE_DISPOSITION_INFO pub const FILE_DISPOSITION_FLAG_ON_CLOSE: FILE_DISPOSITION_INFO_EX_FLAGS = 8u32; pub const FILE_DISPOSITION_FLAG_POSIX_SEMANTICS: FILE_DISPOSITION_INFO_EX_FLAGS = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: bool, } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_DISPOSITION_INFO_EX { pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS, } pub type FILE_DISPOSITION_INFO_EX_FLAGS = u32; pub const FILE_END: SET_FILE_POINTER_MOVE_METHOD = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: i64, } @@ -2457,9 +2523,14 @@ pub struct FILE_ID_BOTH_DIR_INFO { pub FileId: i64, pub FileName: [u16; 1], } +impl Default for FILE_ID_BOTH_DIR_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } @@ -2494,12 +2565,22 @@ pub struct FILE_RENAME_INFO { pub FileNameLength: u32, pub FileName: [u16; 1], } +impl Default for FILE_RENAME_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union FILE_RENAME_INFO_0 { pub ReplaceIfExists: bool, pub Flags: u32, } +impl Default for FILE_RENAME_INFO_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FILE_RESERVE_OPFILTER: NTCREATEFILE_CREATE_OPTIONS = 1048576u32; pub const FILE_SEQUENTIAL_ONLY: NTCREATEFILE_CREATE_OPTIONS = 4u32; pub const FILE_SESSION_AWARE: NTCREATEFILE_CREATE_OPTIONS = 262144u32; @@ -2509,7 +2590,7 @@ pub const FILE_SHARE_NONE: FILE_SHARE_MODE = 0u32; pub const FILE_SHARE_READ: FILE_SHARE_MODE = 1u32; pub const FILE_SHARE_WRITE: FILE_SHARE_MODE = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct FILE_STANDARD_INFO { pub AllocationSize: i64, pub EndOfFile: i64, @@ -2549,6 +2630,12 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Spare0: u32, } +#[cfg(target_arch = "x86")] +impl Default for FLOATING_SAVE_AREA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -2563,6 +2650,12 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Cr0NpxState: u32, } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for FLOATING_SAVE_AREA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32; pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: FORMAT_MESSAGE_OPTIONS = 8192u32; pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32; @@ -2639,12 +2732,22 @@ pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32; pub struct IN6_ADDR { pub u: IN6_ADDR_0, } +impl Default for IN6_ADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IN6_ADDR_0 { pub Byte: [u8; 16], pub Word: [u16; 8], } +impl Default for IN6_ADDR_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const INFINITE: u32 = 4294967295u32; pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32; pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; @@ -2653,6 +2756,11 @@ pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; pub union INIT_ONCE { pub Ptr: *mut core::ffi::c_void, } +impl Default for INIT_ONCE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const INIT_ONCE_INIT_FAILED: u32 = 4u32; pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32; pub const INVALID_SOCKET: SOCKET = -1i32 as _; @@ -2661,6 +2769,11 @@ pub const INVALID_SOCKET: SOCKET = -1i32 as _; pub struct IN_ADDR { pub S_un: IN_ADDR_0, } +impl Default for IN_ADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IN_ADDR_0 { @@ -2668,8 +2781,13 @@ pub union IN_ADDR_0 { pub S_un_w: IN_ADDR_0_1, pub S_addr: u32, } +impl Default for IN_ADDR_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct IN_ADDR_0_0 { pub s_b1: u8, pub s_b2: u8, @@ -2677,7 +2795,7 @@ pub struct IN_ADDR_0_0 { pub s_b4: u8, } #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct IN_ADDR_0_1 { pub s_w1: u16, pub s_w2: u16, @@ -2690,12 +2808,22 @@ pub struct IO_STATUS_BLOCK { pub Anonymous: IO_STATUS_BLOCK_0, pub Information: usize, } +impl Default for IO_STATUS_BLOCK { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union IO_STATUS_BLOCK_0 { pub Status: NTSTATUS, pub Pointer: *mut core::ffi::c_void, } +impl Default for IO_STATUS_BLOCK_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type IPPROTO = i32; pub const IPPROTO_AH: IPPROTO = 51i32; pub const IPPROTO_CBT: IPPROTO = 7i32; @@ -2742,6 +2870,11 @@ pub struct IPV6_MREQ { pub ipv6mr_multiaddr: IN6_ADDR, pub ipv6mr_interface: u32, } +impl Default for IPV6_MREQ { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const IPV6_MULTICAST_LOOP: i32 = 11i32; pub const IPV6_V6ONLY: i32 = 27i32; pub const IP_ADD_MEMBERSHIP: i32 = 12i32; @@ -2752,11 +2885,16 @@ pub struct IP_MREQ { pub imr_multiaddr: IN_ADDR, pub imr_interface: IN_ADDR, } +impl Default for IP_MREQ { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const IP_MULTICAST_LOOP: i32 = 11i32; pub const IP_MULTICAST_TTL: i32 = 10i32; pub const IP_TTL: i32 = 4i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, @@ -2797,7 +2935,7 @@ pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = Option< ), >; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct M128A { pub Low: u64, pub High: i64, @@ -2838,6 +2976,11 @@ pub struct OBJECT_ATTRIBUTES { pub SecurityDescriptor: *const SECURITY_DESCRIPTOR, pub SecurityQualityOfService: *const SECURITY_QUALITY_OF_SERVICE, } +impl Default for OBJECT_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type OBJECT_ATTRIBUTE_FLAGS = u32; pub const OBJ_DONT_REPARSE: OBJECT_ATTRIBUTE_FLAGS = 4096u32; pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32; @@ -2850,14 +2993,24 @@ pub struct OVERLAPPED { pub Anonymous: OVERLAPPED_0, pub hEvent: HANDLE, } +impl Default for OVERLAPPED { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union OVERLAPPED_0 { pub Anonymous: OVERLAPPED_0_0, pub Pointer: *mut core::ffi::c_void, } +impl Default for OVERLAPPED_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct OVERLAPPED_0_0 { pub Offset: u32, pub OffsetHigh: u32, @@ -2895,6 +3048,11 @@ pub struct PROCESS_INFORMATION { pub dwProcessId: u32, pub dwThreadId: u32, } +impl Default for PROCESS_INFORMATION { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const PROCESS_MODE_BACKGROUND_BEGIN: PROCESS_CREATION_FLAGS = 1048576u32; pub const PROCESS_MODE_BACKGROUND_END: PROCESS_CREATION_FLAGS = 2097152u32; pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32; @@ -2926,6 +3084,11 @@ pub struct SECURITY_ATTRIBUTES { pub lpSecurityDescriptor: *mut core::ffi::c_void, pub bInheritHandle: BOOL, } +impl Default for SECURITY_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const SECURITY_CONTEXT_TRACKING: FILE_FLAGS_AND_ATTRIBUTES = 262144u32; pub const SECURITY_DELEGATION: FILE_FLAGS_AND_ATTRIBUTES = 196608u32; #[repr(C)] @@ -2939,13 +3102,18 @@ pub struct SECURITY_DESCRIPTOR { pub Sacl: *mut ACL, pub Dacl: *mut ACL, } +impl Default for SECURITY_DESCRIPTOR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SECURITY_DESCRIPTOR_CONTROL = u16; pub const SECURITY_EFFECTIVE_ONLY: FILE_FLAGS_AND_ATTRIBUTES = 524288u32; pub const SECURITY_IDENTIFICATION: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; pub const SECURITY_IMPERSONATION: FILE_FLAGS_AND_ATTRIBUTES = 131072u32; pub type SECURITY_IMPERSONATION_LEVEL = i32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SECURITY_QUALITY_OF_SERVICE { pub Length: u32, pub ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, @@ -2962,6 +3130,11 @@ pub struct SOCKADDR { pub sa_family: ADDRESS_FAMILY, pub sa_data: [i8; 14], } +impl Default for SOCKADDR { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct SOCKADDR_STORAGE { @@ -2970,12 +3143,22 @@ pub struct SOCKADDR_STORAGE { pub __ss_align: i64, pub __ss_pad2: [i8; 112], } +impl Default for SOCKADDR_STORAGE { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], } +impl Default for SOCKADDR_UN { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type SOCKET = usize; pub const SOCKET_ERROR: i32 = -1i32; pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32; @@ -2995,6 +3178,11 @@ pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32; pub struct SRWLOCK { pub Ptr: *mut core::ffi::c_void, } +impl Default for SRWLOCK { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32; pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32; pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32; @@ -3021,6 +3209,11 @@ pub struct STARTUPINFOEXW { pub StartupInfo: STARTUPINFOW, pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, } +impl Default for STARTUPINFOEXW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct STARTUPINFOW { @@ -3043,6 +3236,11 @@ pub struct STARTUPINFOW { pub hStdOutput: HANDLE, pub hStdError: HANDLE, } +impl Default for STARTUPINFOW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _; pub const STATUS_DIRECTORY_NOT_EMPTY: NTSTATUS = 0xC0000101_u32 as _; @@ -3078,14 +3276,24 @@ pub struct SYSTEM_INFO { pub wProcessorLevel: u16, pub wProcessorRevision: u16, } +impl Default for SYSTEM_INFO { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub union SYSTEM_INFO_0 { pub dwOemId: u32, pub Anonymous: SYSTEM_INFO_0_0, } +impl Default for SYSTEM_INFO_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SYSTEM_INFO_0_0 { pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE, pub wReserved: u16, @@ -3097,7 +3305,7 @@ pub type THREAD_CREATION_FLAGS = u32; pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32; pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32; #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct TIMEVAL { pub tv_sec: i32, pub tv_usec: i32, @@ -3134,6 +3342,11 @@ pub struct UNICODE_STRING { pub MaximumLength: u16, pub Buffer: PWSTR, } +impl Default for UNICODE_STRING { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32; pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32; @@ -3160,6 +3373,11 @@ pub struct WIN32_FIND_DATAW { pub cFileName: [u16; 260], pub cAlternateFileName: [u16; 14], } +impl Default for WIN32_FIND_DATAW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub type WINSOCK_SHUTDOWN_HOW = i32; pub type WINSOCK_SOCKET_TYPE = i32; pub const WRITE_DAC: FILE_ACCESS_RIGHTS = 262144u32; @@ -3171,6 +3389,11 @@ pub struct WSABUF { pub len: u32, pub buf: PSTR, } +impl Default for WSABUF { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(target_arch = "x86")] #[derive(Clone, Copy)] @@ -3183,6 +3406,12 @@ pub struct WSADATA { pub iMaxUdpDg: u16, pub lpVendorInfo: PSTR, } +#[cfg(target_arch = "x86")] +impl Default for WSADATA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -3195,6 +3424,12 @@ pub struct WSADATA { pub szDescription: [i8; 257], pub szSystemStatus: [i8; 129], } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for WSADATA { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const WSAEACCES: WSA_ERROR = 10013i32; pub const WSAEADDRINUSE: WSA_ERROR = 10048i32; pub const WSAEADDRNOTAVAIL: WSA_ERROR = 10049i32; @@ -3255,6 +3490,11 @@ pub struct WSAPROTOCOLCHAIN { pub ChainLen: i32, pub ChainEntries: [u32; 7], } +impl Default for WSAPROTOCOLCHAIN { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[derive(Clone, Copy)] pub struct WSAPROTOCOL_INFOW { @@ -3279,6 +3519,11 @@ pub struct WSAPROTOCOL_INFOW { pub dwProviderReserved: u32, pub szProtocol: [u16; 256], } +impl Default for WSAPROTOCOL_INFOW { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} pub const WSASERVICE_NOT_FOUND: WSA_ERROR = 10108i32; pub const WSASYSCALLFAILURE: WSA_ERROR = 10107i32; pub const WSASYSNOTREADY: WSA_ERROR = 10091i32; @@ -3348,6 +3593,12 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } +#[cfg(target_arch = "x86")] +impl Default for XSAVE_FORMAT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] #[derive(Clone, Copy)] @@ -3369,6 +3620,12 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 16], pub Reserved4: [u8; 96], } +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +impl Default for XSAVE_FORMAT { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} #[cfg(target_arch = "arm")] #[repr(C)] diff --git a/std/src/sys/pal/windows/mod.rs b/std/src/sys/pal/windows/mod.rs index bdf0cc2c59cf1..3c0a5c2de2636 100644 --- a/std/src/sys/pal/windows/mod.rs +++ b/std/src/sys/pal/windows/mod.rs @@ -14,7 +14,6 @@ pub mod compat; pub mod api; -pub mod args; pub mod c; pub mod env; #[cfg(not(target_vendor = "win7"))] diff --git a/std/src/sys/pal/xous/args.rs b/std/src/sys/pal/xous/args.rs deleted file mode 100644 index 00c44ca220a9e..0000000000000 --- a/std/src/sys/pal/xous/args.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::ffi::OsString; -use crate::sys::pal::xous::os::get_application_parameters; -use crate::sys::pal::xous::os::params::ArgumentList; -use crate::{fmt, vec}; - -pub struct Args { - parsed_args_list: vec::IntoIter, -} - -pub fn args() -> Args { - let Some(params) = get_application_parameters() else { - return Args { parsed_args_list: vec![].into_iter() }; - }; - - for param in params { - if let Ok(args) = ArgumentList::try_from(¶m) { - let mut parsed_args = vec![]; - for arg in args { - parsed_args.push(arg.into()); - } - return Args { parsed_args_list: parsed_args.into_iter() }; - } - } - Args { parsed_args_list: vec![].into_iter() } -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.parsed_args_list.as_slice().fmt(f) - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.parsed_args_list.next() - } - fn size_hint(&self) -> (usize, Option) { - self.parsed_args_list.size_hint() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.parsed_args_list.next_back() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.parsed_args_list.len() - } -} diff --git a/std/src/sys/pal/xous/mod.rs b/std/src/sys/pal/xous/mod.rs index 58926e2beb1d0..4f652d3f130de 100644 --- a/std/src/sys/pal/xous/mod.rs +++ b/std/src/sys/pal/xous/mod.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -pub mod args; #[path = "../unsupported/env.rs"] pub mod env; pub mod os; diff --git a/std/src/sys/pal/zkvm/mod.rs b/std/src/sys/pal/zkvm/mod.rs index 4659dad16e85a..ebd7b03677988 100644 --- a/std/src/sys/pal/zkvm/mod.rs +++ b/std/src/sys/pal/zkvm/mod.rs @@ -8,11 +8,9 @@ //! will likely change over time. #![forbid(unsafe_op_in_unsafe_fn)] -const WORD_SIZE: usize = size_of::(); +pub const WORD_SIZE: usize = size_of::(); pub mod abi; -#[path = "../zkvm/args.rs"] -pub mod args; pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/std/src/sys/path/windows.rs b/std/src/sys/path/windows.rs index 1c53472191699..e0e003f6a8192 100644 --- a/std/src/sys/path/windows.rs +++ b/std/src/sys/path/windows.rs @@ -10,6 +10,40 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; +/// A null terminated wide string. +#[repr(transparent)] +pub struct WCStr([u16]); + +impl WCStr { + /// Convert a slice to a WCStr without checks. + /// + /// Though it is memory safe, the slice should also not contain interior nulls + /// as this may lead to unwanted truncation. + /// + /// # Safety + /// + /// The slice must end in a null. + pub unsafe fn from_wchars_with_null_unchecked(s: &[u16]) -> &Self { + unsafe { &*(s as *const [u16] as *const Self) } + } + + pub fn as_ptr(&self) -> *const u16 { + self.0.as_ptr() + } + + pub fn count_bytes(&self) -> usize { + self.0.len() + } +} + +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&WCStr) -> io::Result) -> io::Result { + let path = maybe_verbatim(path)?; + // SAFETY: maybe_verbatim returns null-terminated strings + let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) }; + f(path) +} + #[inline] pub fn is_sep_byte(b: u8) -> bool { b == b'/' || b == b'\\' @@ -350,3 +384,46 @@ pub(crate) fn absolute(path: &Path) -> io::Result { pub(crate) fn is_absolute(path: &Path) -> bool { path.has_root() && path.prefix().is_some() } + +/// Test that the path is absolute, fully qualified and unchanged when processed by the Windows API. +/// +/// For example: +/// +/// - `C:\path\to\file` will return true. +/// - `C:\path\to\nul` returns false because the Windows API will convert it to \\.\NUL +/// - `C:\path\to\..\file` returns false because it will be resolved to `C:\path\file`. +/// +/// This is a useful property because it means the path can be converted from and to and verbatim +/// path just by changing the prefix. +pub(crate) fn is_absolute_exact(path: &[u16]) -> bool { + // This is implemented by checking that passing the path through + // GetFullPathNameW does not change the path in any way. + + // Windows paths are limited to i16::MAX length + // though the API here accepts a u32 for the length. + if path.is_empty() || path.len() > u32::MAX as usize || path.last() != Some(&0) { + return false; + } + // The path returned by `GetFullPathNameW` must be the same length as the + // given path, otherwise they're not equal. + let buffer_len = path.len(); + let mut new_path = Vec::with_capacity(buffer_len); + let result = unsafe { + c::GetFullPathNameW( + path.as_ptr(), + new_path.capacity() as u32, + new_path.as_mut_ptr(), + crate::ptr::null_mut(), + ) + }; + // Note: if non-zero, the returned result is the length of the buffer without the null termination + if result == 0 || result as usize != buffer_len - 1 { + false + } else { + // SAFETY: `GetFullPathNameW` initialized `result` bytes and does not exceed `nBufferLength - 1` (capacity). + unsafe { + new_path.set_len((result as usize) + 1); + } + path == &new_path + } +} diff --git a/std/src/sys/path/windows/tests.rs b/std/src/sys/path/windows/tests.rs index f2a60e30bc610..9eb79203dcac7 100644 --- a/std/src/sys/path/windows/tests.rs +++ b/std/src/sys/path/windows/tests.rs @@ -135,3 +135,15 @@ fn broken_unc_path() { assert_eq!(components.next(), Some(Component::Normal("foo".as_ref()))); assert_eq!(components.next(), Some(Component::Normal("bar".as_ref()))); } + +#[test] +fn test_is_absolute_exact() { + use crate::sys::pal::api::wide_str; + // These paths can be made verbatim by only changing their prefix. + assert!(is_absolute_exact(wide_str!(r"C:\path\to\file"))); + assert!(is_absolute_exact(wide_str!(r"\\server\share\path\to\file"))); + // These paths change more substantially + assert!(!is_absolute_exact(wide_str!(r"C:\path\to\..\file"))); + assert!(!is_absolute_exact(wide_str!(r"\\server\share\path\to\..\file"))); + assert!(!is_absolute_exact(wide_str!(r"C:\path\to\NUL"))); // Converts to \\.\NUL +} diff --git a/std/src/sys/process/uefi.rs b/std/src/sys/process/uefi.rs index b46418ae9bb67..5f922292d0542 100644 --- a/std/src/sys/process/uefi.rs +++ b/std/src/sys/process/uefi.rs @@ -1,4 +1,4 @@ -use r_efi::protocols::simple_text_output; +use r_efi::protocols::{simple_text_input, simple_text_output}; use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; @@ -23,6 +23,7 @@ pub struct Command { args: Vec, stdout: Option, stderr: Option, + stdin: Option, env: CommandEnv, } @@ -48,6 +49,7 @@ impl Command { args: Vec::new(), stdout: None, stderr: None, + stdin: None, env: Default::default(), } } @@ -64,8 +66,8 @@ impl Command { panic!("unsupported") } - pub fn stdin(&mut self, _stdin: Stdio) { - panic!("unsupported") + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); } pub fn stdout(&mut self, stdout: Stdio) { @@ -122,6 +124,22 @@ impl Command { } } + fn create_stdin( + s: Stdio, + ) -> io::Result>> { + match s { + Stdio::Null => unsafe { + helpers::OwnedProtocol::create( + uefi_command_internal::InputProtocol::null(), + simple_text_input::PROTOCOL_GUID, + ) + } + .map(Some), + Stdio::Inherit => Ok(None), + Stdio::MakePipe => unsupported(), + } + } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; @@ -149,6 +167,15 @@ impl Command { cmd.stderr_inherit() }; + // Setup Stdin + let stdin = self.stdin.unwrap_or(Stdio::Null); + let stdin = Self::create_stdin(stdin)?; + if let Some(con) = stdin { + cmd.stdin_init(con) + } else { + cmd.stdin_inherit() + }; + let env = env_changes(&self.env); // Set any new vars @@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> { #[allow(dead_code)] mod uefi_command_internal { - use r_efi::protocols::{loaded_image, simple_text_output}; + use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; @@ -350,6 +377,7 @@ mod uefi_command_internal { handle: NonNull, stdout: Option>, stderr: Option>, + stdin: Option>, st: OwnedTable, args: Option<(*mut u16, usize)>, } @@ -384,7 +412,14 @@ mod uefi_command_internal { helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap(); let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table }); - Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None }) + Ok(Self { + handle: child_handle, + stdout: None, + stderr: None, + stdin: None, + st, + args: None, + }) } } @@ -445,6 +480,17 @@ mod uefi_command_internal { } } + fn set_stdin( + &mut self, + handle: r_efi::efi::Handle, + protocol: *mut simple_text_input::Protocol, + ) { + unsafe { + (*self.st.as_mut_ptr()).console_in_handle = handle; + (*self.st.as_mut_ptr()).con_in = protocol; + } + } + pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol) { self.set_stdout( protocol.handle().as_ptr(), @@ -471,6 +517,19 @@ mod uefi_command_internal { unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) } } + pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol) { + self.set_stdin( + protocol.handle().as_ptr(), + protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol, + ); + self.stdin = Some(protocol); + } + + pub(crate) fn stdin_inherit(&mut self) { + let st: NonNull = system_table().cast(); + unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) } + } + pub fn stderr(&self) -> io::Result> { match &self.stderr { Some(stderr) => stderr.as_ref().utf8(), @@ -722,6 +781,56 @@ mod uefi_command_internal { } } + #[repr(C)] + pub(crate) struct InputProtocol { + reset: simple_text_input::ProtocolReset, + read_key_stroke: simple_text_input::ProtocolReadKeyStroke, + wait_for_key: r_efi::efi::Event, + } + + impl InputProtocol { + pub(crate) fn null() -> Self { + let evt = helpers::OwnedEvent::new( + r_efi::efi::EVT_NOTIFY_WAIT, + r_efi::efi::TPL_CALLBACK, + Some(Self::empty_notify), + None, + ) + .unwrap(); + + Self { + reset: Self::null_reset, + read_key_stroke: Self::null_read_key, + wait_for_key: evt.into_raw(), + } + } + + extern "efiapi" fn null_reset( + _: *mut simple_text_input::Protocol, + _: r_efi::efi::Boolean, + ) -> r_efi::efi::Status { + r_efi::efi::Status::SUCCESS + } + + extern "efiapi" fn null_read_key( + _: *mut simple_text_input::Protocol, + _: *mut simple_text_input::InputKey, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {} + } + + impl Drop for InputProtocol { + fn drop(&mut self) { + // Close wait_for_key + unsafe { + let _ = helpers::OwnedEvent::from_raw(self.wait_for_key); + } + } + } + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { const QUOTE: u16 = 0x0022; const SPACE: u16 = 0x0020; diff --git a/std/src/sys/process/unix/unix.rs b/std/src/sys/process/unix/unix.rs index 191a09c8da913..3b04ec50db30e 100644 --- a/std/src/sys/process/unix/unix.rs +++ b/std/src/sys/process/unix/unix.rs @@ -434,9 +434,6 @@ impl Command { target_os = "nto", target_vendor = "apple", ))] - // FIXME(#115199): Rust currently omits weak function definitions - // and its metadata from LLVM IR. - #[cfg_attr(target_os = "linux", no_sanitize(cfi))] fn posix_spawn( &mut self, stdio: &ChildPipes, diff --git a/std/src/sys/process/windows.rs b/std/src/sys/process/windows.rs index 06c15e08f3fb1..4cfdf908c58de 100644 --- a/std/src/sys/process/windows.rs +++ b/std/src/sys/process/windows.rs @@ -19,7 +19,7 @@ use crate::sys::args::{self, Arg}; use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; -use crate::sys::pal::api::{self, WinError}; +use crate::sys::pal::api::{self, WinError, utf16}; use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; @@ -880,9 +880,33 @@ fn make_envp(maybe_env: Option>) -> io::Result<(*mut fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { match d { Some(dir) => { - let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().collect(); - dir_str.push(0); - Ok((dir_str.as_ptr(), dir_str)) + let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().chain([0]).collect(); + // Try to remove the `\\?\` prefix, if any. + // This is necessary because the current directory does not support verbatim paths. + // However. this can only be done if it doesn't change how the path will be resolved. + let ptr = if dir_str.starts_with(utf16!(r"\\?\UNC")) { + // Turn the `C` in `UNC` into a `\` so we can then use `\\rest\of\path`. + let start = r"\\?\UN".len(); + dir_str[start] = b'\\' as u16; + if path::is_absolute_exact(&dir_str[start..]) { + dir_str[start..].as_ptr() + } else { + // Revert the above change. + dir_str[start] = b'C' as u16; + dir_str.as_ptr() + } + } else if dir_str.starts_with(utf16!(r"\\?\")) { + // Strip the leading `\\?\` + let start = r"\\?\".len(); + if path::is_absolute_exact(&dir_str[start..]) { + dir_str[start..].as_ptr() + } else { + dir_str.as_ptr() + } + } else { + dir_str.as_ptr() + }; + Ok((ptr, dir_str)) } None => Ok((ptr::null(), Vec::new())), } diff --git a/std/src/sys/stdio/uefi.rs b/std/src/sys/stdio/uefi.rs index 257e321dd03d7..ccd6bf658b0ff 100644 --- a/std/src/sys/stdio/uefi.rs +++ b/std/src/sys/stdio/uefi.rs @@ -142,8 +142,12 @@ impl io::Write for Stderr { // UTF-16 character should occupy 4 bytes at most in UTF-8 pub const STDIN_BUF_SIZE: usize = 4; -pub fn is_ebadf(_err: &io::Error) -> bool { - false +pub fn is_ebadf(err: &io::Error) -> bool { + if let Some(x) = err.raw_os_error() { + r_efi::efi::Status::UNSUPPORTED.as_usize() == x + } else { + false + } } pub fn panic_output() -> Option { diff --git a/std/src/sys/thread_local/destructors/linux_like.rs b/std/src/sys/thread_local/destructors/linux_like.rs index 817941229eefe..d7cbaeb89f42e 100644 --- a/std/src/sys/thread_local/destructors/linux_like.rs +++ b/std/src/sys/thread_local/destructors/linux_like.rs @@ -12,9 +12,6 @@ use crate::mem::transmute; -// FIXME: The Rust compiler currently omits weakly function definitions (i.e., -// __cxa_thread_atexit_impl) and its metadata from LLVM IR. -#[no_sanitize(cfi, kcfi)] pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { /// This is necessary because the __cxa_thread_atexit_impl implementation /// std links to by default may be a C or C++ implementation that was not diff --git a/std/src/thread/mod.rs b/std/src/thread/mod.rs index 3f3ba02361cc8..2097f1e304cea 100644 --- a/std/src/thread/mod.rs +++ b/std/src/thread/mod.rs @@ -1676,6 +1676,7 @@ impl fmt::Debug for Thread { /// [`Result`]: crate::result::Result /// [`std::panic::resume_unwind`]: crate::panic::resume_unwind #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), doc(search_unbox))] pub type Result = crate::result::Result>; // This packet is used to communicate the return value between the spawned diff --git a/std/tests/sync/mpmc.rs b/std/tests/sync/mpmc.rs index 81b92297f76a3..78abcb3bcbe1d 100644 --- a/std/tests/sync/mpmc.rs +++ b/std/tests/sync/mpmc.rs @@ -63,6 +63,24 @@ fn smoke_port_gone() { assert!(tx.send(1).is_err()); } +#[test] +fn smoke_receiver_clone() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + drop(rx); + tx.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 1); +} + +#[test] +fn smoke_receiver_clone_port_gone() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + drop(rx); + drop(rx2); + assert!(tx.send(1).is_err()); +} + #[test] fn smoke_shared_port_gone() { let (tx, rx) = channel::(); @@ -124,6 +142,18 @@ fn chan_gone_concurrent() { while rx.recv().is_ok() {} } +#[test] +fn receiver_cloning() { + let (tx, rx) = channel::(); + let rx2 = rx.clone(); + + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + assert_eq!(rx2.recv(), Ok(1)); + assert_eq!(rx.recv(), Ok(2)); +} + #[test] fn stress() { let count = if cfg!(miri) { 100 } else { 10000 }; diff --git a/stdarch b/stdarch index 9426bb56586c6..4666c7376f25a 160000 --- a/stdarch +++ b/stdarch @@ -1 +1 @@ -Subproject commit 9426bb56586c6ae4095a2dcbd66c570253e6fb32 +Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1 diff --git a/test/src/lib.rs b/test/src/lib.rs index 7ada3f269a002..acaf026c679bf 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -666,10 +666,11 @@ fn run_test_in_process( io::set_output_capture(None); - let test_result = match result { - Ok(()) => calc_result(&desc, Ok(()), time_opts.as_ref(), exec_time.as_ref()), - Err(e) => calc_result(&desc, Err(e.as_ref()), time_opts.as_ref(), exec_time.as_ref()), - }; + // Determine whether the test passed or failed, by comparing its panic + // payload (if any) with its `ShouldPanic` value, and by checking for + // fatal timeout. + let test_result = + calc_result(&desc, result.err().as_deref(), time_opts.as_ref(), exec_time.as_ref()); let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec(); let message = CompletedTest::new(id, desc, test_result, exec_time, stdout); monitor_ch.send(message).unwrap(); @@ -741,10 +742,7 @@ fn spawn_test_subprocess( fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! { let builtin_panic_hook = panic::take_hook(); let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| { - let test_result = match panic_info { - Some(info) => calc_result(&desc, Err(info.payload()), None, None), - None => calc_result(&desc, Ok(()), None, None), - }; + let test_result = calc_result(&desc, panic_info.map(|info| info.payload()), None, None); // We don't support serializing TrFailedMsg, so just // print the message out to stderr. diff --git a/test/src/test_result.rs b/test/src/test_result.rs index 73dcc2e2a0cca..a312894c25c47 100644 --- a/test/src/test_result.rs +++ b/test/src/test_result.rs @@ -39,15 +39,18 @@ pub enum TestResult { /// Creates a `TestResult` depending on the raw result of test execution /// and associated data. -pub(crate) fn calc_result<'a>( +pub(crate) fn calc_result( desc: &TestDesc, - task_result: Result<(), &'a (dyn Any + 'static + Send)>, + panic_payload: Option<&(dyn Any + Send)>, time_opts: Option<&time::TestTimeOptions>, exec_time: Option<&time::TestExecTime>, ) -> TestResult { - let result = match (&desc.should_panic, task_result) { - (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, - (&ShouldPanic::YesWithMessage(msg), Err(err)) => { + let result = match (desc.should_panic, panic_payload) { + // The test did or didn't panic, as expected. + (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestResult::TrOk, + + // Check the actual panic message against the expected message. + (ShouldPanic::YesWithMessage(msg), Some(err)) => { let maybe_panic_str = err .downcast_ref::() .map(|e| &**e) @@ -71,10 +74,19 @@ pub(crate) fn calc_result<'a>( )) } } - (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => { - TestResult::TrFailedMsg("test did not panic as expected".to_string()) + + // The test should have panicked, but didn't panic. + (ShouldPanic::Yes, None) | (ShouldPanic::YesWithMessage(_), None) => { + let fn_location = if !desc.source_file.is_empty() { + &format!(" at {}:{}:{}", desc.source_file, desc.start_line, desc.start_col) + } else { + "" + }; + TestResult::TrFailedMsg(format!("test did not panic as expected{}", fn_location)) } - _ => TestResult::TrFailed, + + // The test should not have panicked, but did panic. + (ShouldPanic::No, Some(_)) => TestResult::TrFailed, }; // If test is already failed (or allowed to fail), do not change the result.