diff --git a/.github/workflows/flux.yml b/.github/workflows/flux.yml index ad1370c04f807..c1bbd32844fb9 100644 --- a/.github/workflows/flux.yml +++ b/.github/workflows/flux.yml @@ -9,7 +9,7 @@ on: env: FIXPOINT_VERSION: "556104ba5508891c357b0bdf819ce706e93d9349" - FLUX_VERSION: "f6bdf90c54ad6eed51b25c125f251cac01cfe170" + FLUX_VERSION: "ebafb8d0ca32d8c0fcd2a0cfef6b1b4bd4dc4a6f" jobs: check-flux-on-core: diff --git a/library/Cargo.lock b/library/Cargo.lock index c681c5935df5f..8b5275e5065e6 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 21425b9846e42..1cce36606d2c0 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -5,7 +5,7 @@ use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; #[cfg(not(no_global_oom_handling))] -use core::intrinsics::const_allocate; +use core::intrinsics::{const_allocate, const_make_global}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; @@ -340,9 +340,10 @@ impl WithHeader { alloc.add(metadata_offset).cast(); // SAFETY: `*metadata_ptr` is within the allocation. metadata_ptr.write(ptr::metadata::(ptr::dangling::() as *const Dyn)); - + // SAFETY: valid heap allocation + const_make_global(alloc); // SAFETY: we have just written the metadata. - &*(metadata_ptr) + &*metadata_ptr } }; diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 30f42050ac8ac..d0ba9c398864f 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -348,13 +348,13 @@ //! format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}' //! argument := integer | identifier //! -//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision]type +//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type] //! fill := character //! align := '<' | '^' | '>' //! sign := '+' | '-' //! width := count //! precision := count | '*' -//! type := '' | '?' | 'x?' | 'X?' | identifier +//! type := '?' | 'x?' | 'X?' | identifier //! count := parameter | integer //! parameter := argument '$' //! ``` diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 9bf8fcae64e91..4bb82fb519cd0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -156,6 +156,7 @@ #![feature(try_trait_v2)] #![feature(try_with_capacity)] #![feature(tuple_trait)] +#![feature(ub_checks)] #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 58baa07bc1741..a189c00a6b61d 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2611,7 +2611,7 @@ impl_eq! { Cow<'a, str>, &'b str } impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for String { /// Creates an empty `String`. #[inline] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 51071eb974c38..d69b31da8c27f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use core::{fmt, intrinsics}; +use core::{fmt, intrinsics, ub_checks}; #[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; @@ -1058,6 +1058,11 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_raw_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } @@ -1174,6 +1179,11 @@ impl Vec { #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")] // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub unsafe fn from_parts_in(ptr: NonNull, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } @@ -1950,7 +1960,11 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn set_len(&mut self, new_len: usize) { - debug_assert!(new_len <= self.capacity()); + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::set_len requires that new_len <= capacity()", + (new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity + ); self.len = new_len; } @@ -3695,7 +3709,7 @@ impl Vec { /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, - /// * or `replace_with` yields fewer or equal elements than `range`’s length + /// * or `replace_with` yields fewer or equal elements than `range`'s length /// * or the lower bound of its `size_hint()` is exact. /// /// Otherwise, a temporary vector is allocated and the tail is moved twice. @@ -3895,7 +3909,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for Vec { /// Creates an empty `Vec`. /// diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 39cdf6efda07a..38393379a78a7 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -783,7 +783,7 @@ impl TypeId { // This is a provenance-stripping memcpy. for (i, chunk) in self.data.iter().copied().enumerate() { - let chunk = chunk.expose_provenance().to_ne_bytes(); + let chunk = chunk.addr().to_ne_bytes(); let start = i * chunk.len(); bytes[start..(start + chunk.len())].copy_from_slice(&chunk); } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 16356f749c92b..62203e132b70c 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] { } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl Index for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const Index for [T; N] where - [T]: Index, + [T]: ~const Index, { type Output = <[T] as Index>::Output; @@ -387,9 +388,10 @@ where } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl IndexMut for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const IndexMut for [T; N] where - [T]: IndexMut, + [T]: ~const IndexMut, { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index 069c50c2531b0..c21c08320bef6 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -28,15 +28,15 @@ pub trait AsyncIterator { /// async iterator state: /// /// - `Poll::Pending` means that this async iterator's next value is not ready - /// yet. Implementations will ensure that the current task will be notified - /// when the next value may be ready. + /// yet. Implementations will ensure that the current task will be notified + /// when the next value may be ready. /// /// - `Poll::Ready(Some(val))` means that the async iterator has successfully - /// produced a value, `val`, and may produce further values on subsequent - /// `poll_next` calls. + /// produced a value, `val`, and may produce further values on subsequent + /// `poll_next` calls. /// /// - `Poll::Ready(None)` means that the async iterator has terminated, and - /// `poll_next` should not be invoked again. + /// `poll_next` should not be invoked again. /// /// # Panics /// diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c53a2b2beb4cc..d6d1bf2effae2 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -333,7 +333,7 @@ impl Clone for Cell { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for Cell { /// Creates a `Cell`, with the `Default` value for T. #[inline] @@ -1324,7 +1324,7 @@ impl Clone for RefCell { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for RefCell { /// Creates a `RefCell`, with the `Default` value for T. #[inline] @@ -2332,7 +2332,7 @@ impl UnsafeCell { } #[stable(feature = "unsafe_cell_default", since = "1.10.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for UnsafeCell { /// Creates an `UnsafeCell`, with the `Default` value for T. fn default() -> UnsafeCell { @@ -2437,7 +2437,7 @@ impl SyncUnsafeCell { } #[unstable(feature = "sync_unsafe_cell", issue = "95439")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for SyncUnsafeCell { /// Creates an `SyncUnsafeCell`, with the `Default` value for T. fn default() -> SyncUnsafeCell { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 03b120fbf0c34..1b9af10a6fda5 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -381,7 +381,8 @@ pub struct AssertParamIsEq { /// /// assert_eq!(2.cmp(&1), Ordering::Greater); /// ``` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive_const(PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] // This is a lang item only so that `BinOp::Cmp` in MIR can return it. // It has no special behavior, but does require that the three variants @@ -1481,13 +1482,14 @@ pub trait PartialOrd: PartialEq + PointeeSized { } } -fn default_chaining_impl( +fn default_chaining_impl( lhs: &T, rhs: &U, p: impl FnOnce(Ordering) -> bool, ) -> ControlFlow where - T: PartialOrd, + T: PartialOrd + PointeeSized, + U: PointeeSized, { // It's important that this only call `partial_cmp` once, not call `eq` then // one of the relational operators. We don't want to `bcmp`-then-`memcp` a diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs index a06a5227fe285..7d61c9345ecf8 100644 --- a/library/core/src/cmp/bytewise.rs +++ b/library/core/src/cmp/bytewise.rs @@ -17,11 +17,15 @@ use crate::num::NonZero; /// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct. /// - `>::{eq,ne}` are equivalent to comparing the bytes. #[rustc_specialization_trait] -pub(crate) unsafe trait BytewiseEq: PartialEq + Sized {} +#[const_trait] +pub(crate) unsafe trait BytewiseEq: + ~const PartialEq + Sized +{ +} macro_rules! is_bytewise_comparable { ($($t:ty),+ $(,)?) => {$( - unsafe impl BytewiseEq for $t {} + unsafe impl const BytewiseEq for $t {} )+}; } diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 4d108b0c18ed3..897267968aacc 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -104,7 +104,7 @@ use crate::ascii::Char as AsciiChar; #[rustc_diagnostic_item = "Default"] #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] pub trait Default: Sized { /// Returns the "default value" for a type. /// @@ -151,7 +151,7 @@ pub macro Default($item:item) { macro_rules! default_impl { ($t:ty, $v:expr, $doc:tt) => { #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_default", issue = "67792")] + #[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for $t { #[inline(always)] #[doc = $doc] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 777bee6ea3ba2..756237c6f4182 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -142,16 +142,20 @@ pub enum FromBytesWithNulError { } #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl Error for FromBytesWithNulError { - #[allow(deprecated)] - fn description(&self) -> &str { +impl fmt::Display for FromBytesWithNulError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::InteriorNul { .. } => "data provided contains an interior nul byte", - Self::NotNulTerminated => "data provided is not nul terminated", + Self::InteriorNul { position } => { + write!(f, "data provided contains an interior nul byte at byte position {position}") + } + Self::NotNulTerminated => write!(f, "data provided is not nul terminated"), } } } +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for FromBytesWithNulError {} + /// An error indicating that no nul byte was present. /// /// A slice used to create a [`CStr`] must contain a nul byte somewhere @@ -188,18 +192,6 @@ impl Default for &CStr { } } -#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl fmt::Display for FromBytesWithNulError { - #[allow(deprecated, deprecated_in_future)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.description())?; - if let Self::InteriorNul { position } = self { - write!(f, " at byte pos {position}")?; - } - Ok(()) - } -} - #[unstable(feature = "ub_checks", issue = "none")] impl Invariant for &CStr { /** diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 228a331e1da4d..8ac29e5b07638 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -854,7 +854,6 @@ impl Display for Arguments<'_> { /// }"; /// assert_eq!(format!("The origin is: {origin:#?}"), expected); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index e1381ace44151..7d41ae45093ea 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -358,7 +358,7 @@ macro_rules! impl_Display { } #[cfg(feature = "optimize_for_size")] { - offset = _inner_slow_integer_to_str(self.unsigned_abs().$conv_fn(), &mut buf.buf); + offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf); } // Only difference between signed and unsigned are these 4 lines. if self < 0 { @@ -401,7 +401,7 @@ macro_rules! impl_Display { } #[cfg(feature = "optimize_for_size")] { - offset = _inner_slow_integer_to_str(self.$conv_fn(), &mut buf.buf); + offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf); } // SAFETY: Starting from `offset`, all elements of the slice have been set. unsafe { slice_buffer_to_str(&buf.buf, offset) } @@ -412,7 +412,7 @@ macro_rules! impl_Display { )* #[cfg(feature = "optimize_for_size")] - fn _inner_slow_integer_to_str(mut n: $u, buf: &mut [MaybeUninit::]) -> usize { + fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::]) -> usize { let mut curr = buf.len(); // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning @@ -437,7 +437,7 @@ macro_rules! impl_Display { const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1; let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; - let offset = _inner_slow_integer_to_str(n, &mut buf); + let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf); // SAFETY: Starting from `offset`, all elements of the slice have been set. let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) }; f.pad_integral(is_nonnegative, "", buf_slice) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 15295a3cdf738..e099c28646015 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -916,7 +916,7 @@ pub const unsafe fn arith_offset(dst: *const T, offset: isize) -> *const T; /// # Safety /// /// - `index < PtrMetadata(slice_ptr)`, so the indexing is in-bounds for the slice -/// - the resulting offsetting is in-bounds of the allocated object, which is +/// - the resulting offsetting is in-bounds of the allocation, which is /// always the case for references, but needs to be upheld manually for pointers #[rustc_nounwind] #[rustc_intrinsic] @@ -1385,6 +1385,7 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::floor`](../../std/primitive.f16.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf16(x: f16) -> f16; @@ -1392,6 +1393,7 @@ pub const unsafe fn floorf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::floor`](../../std/primitive.f32.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf32(x: f32) -> f32; @@ -1399,6 +1401,7 @@ pub const unsafe fn floorf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::floor`](../../std/primitive.f64.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf64(x: f64) -> f64; @@ -1406,6 +1409,7 @@ pub const unsafe fn floorf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::floor`](../../std/primitive.f128.html#method.floor) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn floorf128(x: f128) -> f128; @@ -1414,6 +1418,7 @@ pub const unsafe fn floorf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf16(x: f16) -> f16; @@ -1421,6 +1426,7 @@ pub const unsafe fn ceilf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf32(x: f32) -> f32; @@ -1428,6 +1434,7 @@ pub const unsafe fn ceilf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf64(x: f64) -> f64; @@ -1435,6 +1442,7 @@ pub const unsafe fn ceilf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn ceilf128(x: f128) -> f128; @@ -1443,6 +1451,7 @@ pub const unsafe fn ceilf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf16(x: f16) -> f16; @@ -1450,6 +1459,7 @@ pub const unsafe fn truncf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf32(x: f32) -> f32; @@ -1457,6 +1467,7 @@ pub const unsafe fn truncf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf64(x: f64) -> f64; @@ -1464,6 +1475,7 @@ pub const unsafe fn truncf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn truncf128(x: f128) -> f128; @@ -1473,6 +1485,7 @@ pub const unsafe fn truncf128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f16(x: f16) -> f16; @@ -1482,6 +1495,7 @@ pub const fn round_ties_even_f16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f32(x: f32) -> f32; @@ -1491,6 +1505,7 @@ pub const fn round_ties_even_f32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f64(x: f64) -> f64; @@ -1500,6 +1515,7 @@ pub const fn round_ties_even_f64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const fn round_ties_even_f128(x: f128) -> f128; @@ -1508,6 +1524,7 @@ pub const fn round_ties_even_f128(x: f128) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::round`](../../std/primitive.f16.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf16(x: f16) -> f16; @@ -1515,6 +1532,7 @@ pub const unsafe fn roundf16(x: f16) -> f16; /// /// The stabilized version of this intrinsic is /// [`f32::round`](../../std/primitive.f32.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf32(x: f32) -> f32; @@ -1522,6 +1540,7 @@ pub const unsafe fn roundf32(x: f32) -> f32; /// /// The stabilized version of this intrinsic is /// [`f64::round`](../../std/primitive.f64.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf64(x: f64) -> f64; @@ -1529,6 +1548,7 @@ pub const unsafe fn roundf64(x: f64) -> f64; /// /// The stabilized version of this intrinsic is /// [`f128::round`](../../std/primitive.f128.html#method.round) +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] pub const unsafe fn roundf128(x: f128) -> f128; @@ -2214,6 +2234,7 @@ pub const unsafe fn raw_eq(a: &T, b: &T) -> bool; /// [valid]: crate::ptr#safety #[rustc_nounwind] #[rustc_intrinsic] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub const unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; /// See documentation of [`std::hint::black_box`] for details. @@ -2546,6 +2567,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 { + // const eval overrides this function; at runtime, it is a NOP. + ptr +} + /// Returns whether we should perform contract-checking at runtime. /// /// This is meant to be similar to the ub_checks intrinsic, in terms diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 854e03cf18279..088dea7812945 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -69,6 +69,23 @@ impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { } } +/// Creates a new `BorrowedBuf` from a cursor. +/// +/// Use `BorrowedCursor::with_unfilled_buf` instead for a safer alternative. +impl<'data> From> for BorrowedBuf<'data> { + #[inline] + fn from(mut buf: BorrowedCursor<'data>) -> BorrowedBuf<'data> { + let init = buf.init_mut().len(); + BorrowedBuf { + // SAFETY: no initialized byte is ever uninitialized as per + // `BorrowedBuf`'s invariant + buf: unsafe { buf.buf.buf.get_unchecked_mut(buf.buf.filled..) }, + filled: 0, + init, + } + } +} + impl<'data> BorrowedBuf<'data> { /// Returns the total capacity of the buffer. #[inline] @@ -132,7 +149,6 @@ impl<'data> BorrowedBuf<'data> { #[inline] pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { BorrowedCursor { - start: self.filled, // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its // lifetime covariantly is safe. buf: unsafe { @@ -188,9 +204,6 @@ pub struct BorrowedCursor<'a> { // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into // it, so don't do that! buf: &'a mut BorrowedBuf<'a>, - /// The length of the filled portion of the underlying buffer at the time of the cursor's - /// creation. - start: usize, } impl<'a> BorrowedCursor<'a> { @@ -208,7 +221,6 @@ impl<'a> BorrowedCursor<'a> { self.buf, ) }, - start: self.start, } } @@ -218,23 +230,12 @@ impl<'a> BorrowedCursor<'a> { self.buf.capacity() - self.buf.filled } - /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`. + /// Returns the number of bytes written to the `BorrowedBuf` this cursor was created from. /// - /// Note that if this cursor is a reborrowed clone of another, then the count returned is the - /// count written via either cursor, not the count since the cursor was reborrowed. + /// In particular, the count returned is shared by all reborrows of the cursor. #[inline] pub fn written(&self) -> usize { - self.buf.filled - self.start - } - - /// Returns a shared reference to the initialized portion of the cursor. - #[inline] - pub fn init_ref(&self) -> &[u8] { - // SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { - let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init); - buf.assume_init_ref() - } + self.buf.filled } /// Returns a mutable reference to the initialized portion of the cursor. @@ -247,15 +248,6 @@ impl<'a> BorrowedCursor<'a> { } } - /// Returns a mutable reference to the uninitialized part of the cursor. - /// - /// It is safe to uninitialize any of these bytes. - #[inline] - pub fn uninit_mut(&mut self) -> &mut [MaybeUninit] { - // SAFETY: always in bounds - unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) } - } - /// Returns a mutable reference to the whole cursor. /// /// # Safety @@ -308,7 +300,9 @@ impl<'a> BorrowedCursor<'a> { /// Initializes all bytes in the cursor. #[inline] pub fn ensure_init(&mut self) -> &mut Self { - let uninit = self.uninit_mut(); + // SAFETY: always in bounds and we never uninitialize these bytes. + let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }; + // SAFETY: 0 is a valid value for MaybeUninit and the length matches the allocation // since it is comes from a slice reference. unsafe { @@ -353,4 +347,38 @@ impl<'a> BorrowedCursor<'a> { } self.buf.filled += buf.len(); } + + /// Runs the given closure with a `BorrowedBuf` containing the unfilled part + /// of the cursor. + /// + /// This enables inspecting what was written to the cursor. + /// + /// # Panics + /// + /// Panics if the `BorrowedBuf` given to the closure is replaced by another + /// one. + pub fn with_unfilled_buf(&mut self, f: impl FnOnce(&mut BorrowedBuf<'_>) -> T) -> T { + let mut buf = BorrowedBuf::from(self.reborrow()); + let prev_ptr = buf.buf as *const _; + let res = f(&mut buf); + + // Check that the caller didn't replace the `BorrowedBuf`. + // This is necessary for the safety of the code below: if the check wasn't + // there, one could mark some bytes as initialized even though there aren't. + assert!(core::ptr::addr_eq(prev_ptr, buf.buf)); + + let filled = buf.filled; + let init = buf.init; + + // Update `init` and `filled` fields with what was written to the buffer. + // `self.buf.filled` was the starting length of the `BorrowedBuf`. + // + // SAFETY: These amounts of bytes were initialized/filled in the `BorrowedBuf`, + // and therefore they are initialized/filled in the cursor too, because the + // buffer wasn't replaced. + self.buf.init = self.buf.filled + init; + self.buf.filled += filled; + + res + } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 8090c98e7edb7..c5e199c30821d 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -18,7 +18,6 @@ pub struct Zip { // index, len and a_len are only used by the specialized version of zip index: usize, len: usize, - a_len: usize, } impl Zip { pub(in crate::iter) fn new(a: A, b: B) -> Zip { @@ -158,7 +157,6 @@ macro_rules! zip_impl_general_defaults { b, index: 0, // unused len: 0, // unused - a_len: 0, // unused } } @@ -299,9 +297,8 @@ where B: TrustedRandomAccess + Iterator, { fn new(a: A, b: B) -> Self { - let a_len = a.size(); - let len = cmp::min(a_len, b.size()); - Zip { a, b, index: 0, len, a_len } + let len = cmp::min(a.size(), b.size()); + Zip { a, b, index: 0, len } } #[inline] @@ -315,17 +312,6 @@ where unsafe { Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i))) } - } else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len { - let i = self.index; - // as above, increment before executing code that may panic - self.index += 1; - self.len += 1; - // match the base implementation's potential side effects - // SAFETY: we just checked that `i` < `self.a.len()` - unsafe { - self.a.__iterator_get_unchecked(i); - } - None } else { None } @@ -371,36 +357,42 @@ where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator, { - if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT { - let sz_a = self.a.size(); - let sz_b = self.b.size(); - // Adjust a, b to equal length, make sure that only the first call - // of `next_back` does this, otherwise we will break the restriction - // on calls to `self.next_back()` after calling `get_unchecked()`. - if sz_a != sz_b { + // No effects when the iterator is exhausted, to reduce the number of + // cases the unsafe code has to handle. + // See #137255 for a case where where too many epicycles lead to unsoundness. + if self.index < self.len { + let old_len = self.len; + + // since get_unchecked and the side-effecting code can execute user code + // which can panic we decrement the counter beforehand + // so that the same index won't be accessed twice, as required by TrustedRandomAccess. + // Additionally this will ensure that the side-effects code won't run a second time. + self.len -= 1; + + // Adjust a, b to equal length if we're iterating backwards. + if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT { + // note if some forward-iteration already happened then these aren't the real + // remaining lengths of the inner iterators, so we have to relate them to + // Zip's internal length-tracking. let sz_a = self.a.size(); - if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len { - for _ in 0..sz_a - self.len { - // since next_back() may panic we increment the counters beforehand - // to keep Zip's state in sync with the underlying iterator source - self.a_len -= 1; - self.a.next_back(); - } - debug_assert_eq!(self.a_len, self.len); - } let sz_b = self.b.size(); - if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len { - for _ in 0..sz_b - self.len { - self.b.next_back(); + // This condition can and must only be true on the first `next_back` call, + // otherwise we will break the restriction on calls to `self.next_back()` + // after calling `get_unchecked()`. + if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) { + if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len { + for _ in 0..sz_a - old_len { + self.a.next_back(); + } } + if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len { + for _ in 0..sz_b - old_len { + self.b.next_back(); + } + } + debug_assert_eq!(self.a.size(), self.b.size()); } } - } - if self.index < self.len { - // since get_unchecked executes code which can panic we increment the counters beforehand - // so that the same index won't be accessed twice, as required by TrustedRandomAccess - self.len -= 1; - self.a_len -= 1; let i = self.len; // SAFETY: `i` is smaller than the previous value of `self.len`, // which is also smaller than or equal to `self.a.len()` and `self.b.len()` diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs index 309962ab70ce1..1844c76e5df7e 100644 --- a/library/core/src/iter/sources/empty.rs +++ b/library/core/src/iter/sources/empty.rs @@ -81,7 +81,7 @@ impl Clone for Empty { // not #[derive] because that adds a Default bound on T, // which isn't necessary. #[stable(feature = "iter_empty", since = "1.2.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for Empty { fn default() -> Empty { Empty(marker::PhantomData) diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 3bc9cff8072bf..ab27650067980 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -436,7 +436,6 @@ pub trait Extend { /// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is, /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words, /// callers may assume that if they `extend_reserve`ed enough space they can call this method. - // This method is for internal usage only. It is only on the trait because of specialization's limitations. #[unstable(feature = "extend_one_unchecked", issue = "none")] #[doc(hidden)] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f296792b1dcb2..10f9d464f7d7f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3414,10 +3414,10 @@ pub trait Iterator { /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] #[rustc_diagnostic_item = "iter_copied"] - fn copied<'a, T: 'a>(self) -> Copied + fn copied<'a, T>(self) -> Copied where + T: Copy + 'a, Self: Sized + Iterator, - T: Copy, { Copied::new(self) } @@ -3462,10 +3462,10 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "iter_cloned"] - fn cloned<'a, T: 'a>(self) -> Cloned + fn cloned<'a, T>(self) -> Cloned where + T: Clone + 'a, Self: Sized + Iterator, - T: Clone, { Cloned::new(self) } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 66bfb757daff9..ef8b499773b03 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -39,9 +39,9 @@ //! return. You should mark your implementation using `#[panic_handler]`. //! //! * `rust_eh_personality` - is used by the failure mechanisms of the -//! compiler. This is often mapped to GCC's personality function, but crates -//! which do not trigger a panic can be assured that this function is never -//! called. The `lang` attribute is called `eh_personality`. +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. #![stable(feature = "core", since = "1.6.0")] #![doc( @@ -103,6 +103,7 @@ #![feature(cfg_select)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(const_carrying_mul_add)] +#![feature(const_cmp)] #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -146,6 +147,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] @@ -160,6 +162,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] #![feature(marker_trait_attr)] #![feature(min_specialization)] #![feature(multiple_supertrait_upcastable)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6b9cbb0643586..8ac6ce2242d4e 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -196,16 +196,14 @@ pub macro assert_matches { }, } -/// A macro for defining `#[cfg]` match-like statements. +/// Selects code at compile-time based on `cfg` predicates. /// -/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of -/// `#[cfg]` cases, emitting the implementation which matches first. +/// This macro evaluates, at compile-time, a series of `cfg` predicates, +/// selects the first that is true, and emits the code guarded by that +/// predicate. The code guarded by other predicates is not emitted. /// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -/// -/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when -/// all previous declarations do not evaluate to true. +/// An optional trailing `_` wildcard can be used to specify a fallback. If +/// none of the predicates are true, a [`compile_error`] is emitted. /// /// # Example /// @@ -225,7 +223,7 @@ pub macro assert_matches { /// } /// ``` /// -/// If desired, it is possible to return expressions through the use of surrounding braces: +/// The `cfg_select!` macro can also be used in expression position: /// /// ``` /// #![feature(cfg_select)] @@ -1617,7 +1615,7 @@ pub(crate) mod builtin { /// See [the reference] for more info. /// /// [the reference]: ../../../reference/attributes/derive.html - #[unstable(feature = "derive_const", issue = "none")] + #[unstable(feature = "derive_const", issue = "118304")] #[rustc_builtin_macro] pub macro derive_const($item:item) { /* compiler built-in */ diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 6531d3ec766a9..45277a1c82d3a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -863,7 +863,7 @@ impl Clone for PhantomData { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for PhantomData { fn default() -> Self { Self diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index fc35e54bb0dcc..34d8370da7ecb 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1005,28 +1005,6 @@ impl MaybeUninit { } } - /// Deprecated version of [`slice::assume_init_ref`]. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[deprecated( - note = "replaced by inherent assume_init_ref method; will eventually be removed", - since = "1.83.0" - )] - pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { - // SAFETY: Same for both methods. - unsafe { slice.assume_init_ref() } - } - - /// Deprecated version of [`slice::assume_init_mut`]. - #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[deprecated( - note = "replaced by inherent assume_init_mut method; will eventually be removed", - since = "1.83.0" - )] - pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { - // SAFETY: Same for both methods. - unsafe { slice.assume_init_mut() } - } - /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] @@ -1040,94 +1018,6 @@ impl MaybeUninit { pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } - - /// Deprecated version of [`slice::write_copy_of_slice`]. - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[deprecated( - note = "replaced by inherent write_copy_of_slice method; will eventually be removed", - since = "1.83.0" - )] - pub fn copy_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Copy, - { - this.write_copy_of_slice(src) - } - - /// Deprecated version of [`slice::write_clone_of_slice`]. - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[deprecated( - note = "replaced by inherent write_clone_of_slice method; will eventually be removed", - since = "1.83.0" - )] - pub fn clone_from_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Clone, - { - this.write_clone_of_slice(src) - } - - /// Deprecated version of [`slice::write_filled`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_filled method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] - where - T: Clone, - { - this.write_filled(value) - } - - /// Deprecated version of [`slice::write_with`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_with method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] - where - F: FnMut() -> T, - { - this.write_with(|_| f()) - } - - /// Deprecated version of [`slice::write_iter`]. - #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - #[deprecated( - note = "replaced by inherent write_iter method; will eventually be removed", - since = "1.83.0" - )] - pub fn fill_from<'a, I>( - this: &'a mut [MaybeUninit], - it: I, - ) -> (&'a mut [T], &'a mut [MaybeUninit]) - where - I: IntoIterator, - { - this.write_iter(it) - } - - /// Deprecated version of [`slice::as_bytes`]. - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - #[deprecated( - note = "replaced by inherent as_bytes method; will eventually be removed", - since = "1.83.0" - )] - pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { - this.as_bytes() - } - - /// Deprecated version of [`slice::as_bytes_mut`]. - #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - #[deprecated( - note = "replaced by inherent as_bytes_mut method; will eventually be removed", - since = "1.83.0" - )] - pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { - this.as_bytes_mut() - } } impl [MaybeUninit] { @@ -1304,7 +1194,7 @@ impl [MaybeUninit] { /// Fills a slice with elements returned by calling a closure for each index. /// /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use - /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can + /// [slice::write_filled]. If you want to use the `Default` trait to generate values, you can /// pass [`|_| Default::default()`][Default::default] as the argument. /// /// # Panics @@ -1463,7 +1353,7 @@ impl [MaybeUninit] { /// use std::mem::MaybeUninit; /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; - /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit); + /// let uninit_bytes = uninit.as_bytes_mut(); /// uninit_bytes.write_copy_of_slice(&[0x12, 0x34, 0x56, 0x78]); /// let vals = unsafe { uninit.assume_init_ref() }; /// if cfg!(target_endian = "little") { diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 8fb1010fd2014..12113c227131c 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -38,7 +38,7 @@ pub use crate::intrinsics::transmute; /// * If you want to leak memory, see [`Box::leak`]. /// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`]. /// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`]. +/// [`mem::drop`]. /// /// # Safety /// diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index aaa68e8d7d1ad..49a7ae5de5c8f 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -787,7 +787,6 @@ impl Ipv4Addr { /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// [unspecified address]: Ipv4Addr::UNSPECIFIED /// [broadcast address]: Ipv4Addr::BROADCAST - /// /// # Examples /// diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index e4c846ec65a25..8b1e19f6a048d 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1456,7 +1456,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1486,7 +1485,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1522,7 +1520,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1556,7 +1553,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(self) -> f128 { intrinsics::round_ties_even_f128(self) @@ -1588,7 +1584,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f128 { // SAFETY: intrinsic with no preconditions @@ -1619,7 +1614,6 @@ impl f128 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(self) -> f128 { self - self.trunc() diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 022aa659534c5..cbae92205c2ba 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1431,7 +1431,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1461,7 +1460,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1497,7 +1495,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1531,7 +1528,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(self) -> f16 { intrinsics::round_ties_even_f16(self) @@ -1563,7 +1559,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f16 { // SAFETY: intrinsic with no preconditions @@ -1594,7 +1589,6 @@ impl f16 { #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] - // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(self) -> f16 { self - self.trunc() diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index b06ac75104fb7..7a6a0b3d5ce43 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1599,7 +1599,6 @@ pub mod math { /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions @@ -1630,7 +1629,6 @@ pub mod math { #[doc(alias = "ceiling")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn ceil(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf32(x) } @@ -1665,7 +1663,6 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn round(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf32(x) } @@ -1699,7 +1696,6 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn round_ties_even(x: f32) -> f32 { intrinsics::round_ties_even_f32(x) } @@ -1730,7 +1726,6 @@ pub mod math { #[doc(alias = "truncate")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] pub const fn trunc(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf32(x) } @@ -1760,7 +1755,6 @@ pub mod math { /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(x: f32) -> f32 { x - trunc(x) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 0a8a767858717..5c3e62262af6c 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1597,7 +1597,6 @@ pub mod math { /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1627,7 +1626,6 @@ pub mod math { #[inline] #[doc(alias = "ceiling")] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1662,7 +1660,6 @@ pub mod math { /// [`f64::round`]: ../../../std/primitive.f64.html#method.round #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1696,7 +1693,6 @@ pub mod math { /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round_ties_even(x: f64) -> f64 { intrinsics::round_ties_even_f64(x) @@ -1727,7 +1723,6 @@ pub mod math { #[inline] #[doc(alias = "truncate")] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions @@ -1758,7 +1753,6 @@ pub mod math { /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn fract(x: f64) -> f64 { x - trunc(x) diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs index 28a3f5d880ad7..649a736b6e7b5 100644 --- a/library/core/src/num/int_log10.rs +++ b/library/core/src/num/int_log10.rs @@ -1,5 +1,5 @@ -/// These functions compute the integer logarithm of their type, assuming -/// that someone has already checked that the value is strictly positive. +//! These functions compute the integer logarithm of their type, assuming +//! that someone has already checked that the value is strictly positive. // 0 < val <= u8::MAX #[inline] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index f26aeaef249a6..56a4ac621b6ea 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -204,9 +204,10 @@ impl UseCloned for NonZero where T: ZeroablePrimitive {} impl Copy for NonZero where T: ZeroablePrimitive {} #[stable(feature = "nonzero", since = "1.28.0")] -impl PartialEq for NonZero +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for NonZero where - T: ZeroablePrimitive + PartialEq, + T: ZeroablePrimitive + ~const PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index eb3de36512198..2d4c1067703a7 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -556,7 +556,7 @@ macro_rules! uint_impl { pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); if b { overflow_panic::add() } else { a } - } + } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow /// cannot occur. @@ -654,7 +654,7 @@ macro_rules! uint_impl { pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); if b { overflow_panic::add() } else { a } - } + } /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. @@ -714,7 +714,7 @@ macro_rules! uint_impl { pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); if b { overflow_panic::sub() } else { a } - } + } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow /// cannot occur. @@ -807,6 +807,43 @@ macro_rules! uint_impl { } } + /// Strict subtraction with a signed integer. Computes `self - rhs`, + /// panicking if overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_overflow_ops)] + #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".strict_sub_signed(2), 1);")] + /// ``` + /// + /// The following panic because of overflow: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_sub_signed(2);")] + /// ``` + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX).strict_sub_signed(-1);")] + /// ``` + #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + pub const fn strict_sub_signed(self, rhs: $SignedT) -> Self { + let (a, b) = self.overflowing_sub_signed(rhs); + if b { overflow_panic::sub() } else { a } + } + #[doc = concat!( "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`", stringify!($SignedT), "`], returning `None` if overflow occurred." @@ -915,7 +952,7 @@ macro_rules! uint_impl { pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); if b { overflow_panic::mul() } else { a } - } + } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow /// cannot occur. diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 491845f6ef8f4..d696cc9095249 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -104,9 +104,9 @@ macro_rules! sh_impl_signed { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(-other as u32)) } else { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } } @@ -129,9 +129,9 @@ macro_rules! sh_impl_signed { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(-other as u32)) } else { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } } @@ -157,7 +157,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, @@ -178,7 +178,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, @@ -1062,39 +1062,3 @@ macro_rules! wrapping_int_impl_unsigned { } wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } - -mod shift_max { - #![allow(non_upper_case_globals)] - - #[cfg(target_pointer_width = "16")] - mod platform { - pub(crate) const usize: u32 = super::u16; - pub(crate) const isize: u32 = super::i16; - } - - #[cfg(target_pointer_width = "32")] - mod platform { - pub(crate) const usize: u32 = super::u32; - pub(crate) const isize: u32 = super::i32; - } - - #[cfg(target_pointer_width = "64")] - mod platform { - pub(crate) const usize: u32 = super::u64; - pub(crate) const isize: u32 = super::i64; - } - - pub(super) const i8: u32 = (1 << 3) - 1; - pub(super) const i16: u32 = (1 << 4) - 1; - pub(super) const i32: u32 = (1 << 5) - 1; - pub(super) const i64: u32 = (1 << 6) - 1; - pub(super) const i128: u32 = (1 << 7) - 1; - pub(super) use self::platform::isize; - - pub(super) const u8: u32 = i8; - pub(super) const u16: u32 = i16; - pub(super) const u32: u32 = i32; - pub(super) const u64: u32 = i64; - pub(super) const u128: u32 = i128; - pub(super) use self::platform::usize; -} diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 763b60d88e510..efc751a094d12 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -73,7 +73,7 @@ use crate::marker::Tuple; #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[const_trait] -#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] pub trait Fn: FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -161,7 +161,7 @@ pub trait Fn: FnMut { #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[const_trait] -#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] pub trait FnMut: FnOnce { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -241,7 +241,7 @@ pub trait FnMut: FnOnce { #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[const_trait] -#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] pub trait FnOnce { /// The returned type after the call operator is used. #[lang = "fn_once_output"] @@ -257,7 +257,7 @@ mod impls { use crate::marker::Tuple; #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] impl const Fn for &F where F: ~const Fn, @@ -268,7 +268,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] impl const FnMut for &F where F: ~const Fn, @@ -279,7 +279,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] impl const FnOnce for &F where F: ~const Fn, @@ -292,7 +292,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] impl const FnMut for &mut F where F: ~const FnMut, @@ -303,7 +303,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] impl const FnOnce for &mut F where F: ~const FnMut, diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 8092fa9eb2fc5..d8489e9a94913 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -55,6 +55,8 @@ #[doc(alias = "]")] #[doc(alias = "[")] #[doc(alias = "[]")] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -165,7 +167,9 @@ see chapter in The Book : Index { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[const_trait] +pub trait IndexMut: ~const Index { /// Performs the mutable indexing (`container[index]`) operation. /// /// # Panics diff --git a/library/core/src/option.rs b/library/core/src/option.rs index cbb1c7c7d8f00..d2365749f6129 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -577,6 +577,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{self, FusedIterator, TrustedLen}; +use crate::marker::Destruct; use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::panicking::{panic, panic_display}; use crate::pin::Pin; @@ -649,7 +650,8 @@ impl Option { #[must_use] #[inline] #[stable(feature = "is_some_and", since = "1.70.0")] - pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn is_some_and(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool { match self { None => false, Some(x) => f(x), @@ -697,7 +699,8 @@ impl Option { #[must_use] #[inline] #[stable(feature = "is_none_or", since = "1.82.0")] - pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn is_none_or(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool { match self { None => true, Some(x) => f(x), @@ -1023,7 +1026,12 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, default: T) -> T { + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn unwrap_or(self, default: T) -> T + where + T: ~const Destruct, + { match self { Some(x) => x, None => default, @@ -1042,9 +1050,10 @@ impl Option { #[inline] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_else(self, f: F) -> T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn unwrap_or_else(self, f: F) -> T where - F: FnOnce() -> T, + F: ~const FnOnce() -> T + ~const Destruct, { match self { Some(x) => x, @@ -1073,9 +1082,10 @@ impl Option { /// [`FromStr`]: crate::str::FromStr #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or_default(self) -> T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn unwrap_or_default(self) -> T where - T: Default, + T: ~const Default, { match self { Some(x) => x, @@ -1139,9 +1149,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map(self, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map(self, f: F) -> Option where - F: FnOnce(T) -> U, + F: ~const FnOnce(T) -> U + ~const Destruct, { match self { Some(x) => Some(f(x)), @@ -1169,7 +1180,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "result_option_inspect", since = "1.76.0")] - pub fn inspect(self, f: F) -> Self { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn inspect(self, f: F) -> Self + where + F: ~const FnOnce(&T) + ~const Destruct, + { if let Some(ref x) = self { f(x); } @@ -1198,9 +1213,11 @@ impl Option { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the returned value, use `if let` instead"] - pub fn map_or(self, default: U, f: F) -> U + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map_or(self, default: U, f: F) -> U where - F: FnOnce(T) -> U, + F: ~const FnOnce(T) -> U + ~const Destruct, + U: ~const Destruct, { match self { Some(t) => f(t), @@ -1243,10 +1260,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn map_or_else(self, default: D, f: F) -> U + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map_or_else(self, default: D, f: F) -> U where - D: FnOnce() -> U, - F: FnOnce(T) -> U, + D: ~const FnOnce() -> U + ~const Destruct, + F: ~const FnOnce(T) -> U + ~const Destruct, { match self { Some(t) => f(t), @@ -1273,10 +1291,11 @@ impl Option { /// [default value]: Default::default #[inline] #[unstable(feature = "result_option_map_or_default", issue = "138099")] - pub fn map_or_default(self, f: F) -> U + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn map_or_default(self, f: F) -> U where - U: Default, - F: FnOnce(T) -> U, + U: ~const Default, + F: ~const FnOnce(T) -> U + ~const Destruct, { match self { Some(t) => f(t), @@ -1307,7 +1326,8 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn ok_or(self, err: E) -> Result { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn ok_or(self, err: E) -> Result { match self { Some(v) => Ok(v), None => Err(err), @@ -1332,9 +1352,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn ok_or_else(self, err: F) -> Result + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn ok_or_else(self, err: F) -> Result where - F: FnOnce() -> E, + F: ~const FnOnce() -> E + ~const Destruct, { match self { Some(v) => Ok(v), @@ -1463,7 +1484,12 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn and(self, optb: Option) -> Option { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn and(self, optb: Option) -> Option + where + T: ~const Destruct, + U: ~const Destruct, + { match self { Some(_) => optb, None => None, @@ -1502,9 +1528,10 @@ impl Option { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("flat_map", "flatmap")] - pub fn and_then(self, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn and_then(self, f: F) -> Option where - F: FnOnce(T) -> Option, + F: ~const FnOnce(T) -> Option + ~const Destruct, { match self { Some(x) => f(x), @@ -1538,9 +1565,11 @@ impl Option { /// [`Some(t)`]: Some #[inline] #[stable(feature = "option_filter", since = "1.27.0")] - pub fn filter

(self, predicate: P) -> Self + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn filter

(self, predicate: P) -> Self where - P: FnOnce(&T) -> bool, + P: ~const FnOnce(&T) -> bool + ~const Destruct, + T: ~const Destruct, { if let Some(x) = self { if predicate(&x) { @@ -1579,7 +1608,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, optb: Option) -> Option { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn or(self, optb: Option) -> Option + where + T: ~const Destruct, + { match self { x @ Some(_) => x, None => optb, @@ -1601,9 +1634,13 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_else(self, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn or_else(self, f: F) -> Option where - F: FnOnce() -> Option, + F: ~const FnOnce() -> Option + ~const Destruct, + //FIXME(const_hack): this `T: ~const Destruct` is unnecessary, but even precise live drops can't tell + // no value of type `T` gets dropped here + T: ~const Destruct, { match self { x @ Some(_) => x, @@ -1634,7 +1671,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_xor", since = "1.37.0")] - pub fn xor(self, optb: Option) -> Option { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn xor(self, optb: Option) -> Option + where + T: ~const Destruct, + { match (self, optb) { (a @ Some(_), None) => a, (None, b @ Some(_)) => b, @@ -1668,7 +1709,11 @@ impl Option { #[must_use = "if you intended to set a value, consider assignment instead"] #[inline] #[stable(feature = "option_insert", since = "1.53.0")] - pub fn insert(&mut self, value: T) -> &mut T { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn insert(&mut self, value: T) -> &mut T + where + T: ~const Destruct, + { *self = Some(value); // SAFETY: the code above just filled the option @@ -1720,9 +1765,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_get_or_insert_default", since = "1.83.0")] - pub fn get_or_insert_default(&mut self) -> &mut T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn get_or_insert_default(&mut self) -> &mut T where - T: Default, + T: ~const Default + ~const Destruct, { self.get_or_insert_with(T::default) } @@ -1746,9 +1792,11 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_entry", since = "1.20.0")] - pub fn get_or_insert_with(&mut self, f: F) -> &mut T + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn get_or_insert_with(&mut self, f: F) -> &mut T where - F: FnOnce() -> T, + F: ~const FnOnce() -> T + ~const Destruct, + T: ~const Destruct, { if let None = self { *self = Some(f()); @@ -1812,9 +1860,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "option_take_if", since = "1.80.0")] - pub fn take_if

(&mut self, predicate: P) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn take_if

(&mut self, predicate: P) -> Option where - P: FnOnce(&mut T) -> bool, + P: ~const FnOnce(&mut T) -> bool + ~const Destruct, { if self.as_mut().map_or(false, predicate) { self.take() } else { None } } @@ -1859,7 +1908,12 @@ impl Option { /// assert_eq!(x.zip(z), None); /// ``` #[stable(feature = "option_zip_option", since = "1.46.0")] - pub fn zip(self, other: Option) -> Option<(T, U)> { + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn zip(self, other: Option) -> Option<(T, U)> + where + T: ~const Destruct, + U: ~const Destruct, + { match (self, other) { (Some(a), Some(b)) => Some((a, b)), _ => None, @@ -1895,9 +1949,12 @@ impl Option { /// assert_eq!(x.zip_with(None, Point::new), None); /// ``` #[unstable(feature = "option_zip", issue = "70086")] - pub fn zip_with(self, other: Option, f: F) -> Option + #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")] + pub const fn zip_with(self, other: Option, f: F) -> Option where - F: FnOnce(T, U) -> R, + F: ~const FnOnce(T, U) -> R + ~const Destruct, + T: ~const Destruct, + U: ~const Destruct, { match (self, other) { (Some(a), Some(b)) => Some(f(a, b)), @@ -2112,7 +2169,7 @@ where impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for Option { /// Returns [`None`][Option::None]. /// @@ -2243,7 +2300,8 @@ impl<'a, T> From<&'a mut Option> for Option<&'a mut T> { #[stable(feature = "rust1", since = "1.0.0")] impl crate::marker::StructuralPartialEq for Option {} #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Option { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for Option { #[inline] fn eq(&self, other: &Self) -> bool { // Spelling out the cases explicitly optimizes better than diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 7b9e04920d51d..a4be66b90cab3 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -80,7 +80,7 @@ pub use crate::macros::builtin::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; -#[unstable(feature = "derive_const", issue = "none")] +#[unstable(feature = "derive_const", issue = "118304")] pub use crate::macros::builtin::derive_const; #[unstable( diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 2c77c55745b46..9a1ba7d1728cb 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1081,13 +1081,11 @@ mod prim_str {} /// * [`Debug`] /// * [`Default`] /// * [`Hash`] -/// * [`Random`] /// * [`From<[T; N]>`][from] /// /// [from]: convert::From /// [`Debug`]: fmt::Debug /// [`Hash`]: hash::Hash -/// [`Random`]: random::Random /// /// The following traits are implemented for tuples of any length. These traits have /// implementations that are automatically generated by the compiler, so are not limited by @@ -1365,7 +1363,6 @@ mod prim_f16 {} /// x = a + b + c + d; // As written /// x = (a + c) + (b + d); // Reordered to shorten critical path and enable vectorization /// ``` - #[stable(feature = "rust1", since = "1.0.0")] mod prim_f32 {} diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 9e811666fa462..b658bbb24eddd 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -255,7 +255,7 @@ impl hash::Hash for Alignment { /// Returns [`Alignment::MIN`], which is valid for any type. #[unstable(feature = "ptr_alignment_type", issue = "102070")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for Alignment { fn default() -> Alignment { Alignment::MIN diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 61e88e7a00583..e389943d499fe 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1635,10 +1635,11 @@ impl *const [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + pub const unsafe fn get_unchecked(self, index: I) -> *const I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked(self) } diff --git a/library/core/src/ptr/docs/add.md b/library/core/src/ptr/docs/add.md index ae7c7785684c9..6e2e87f5f811b 100644 --- a/library/core/src/ptr/docs/add.md +++ b/library/core/src/ptr/docs/add.md @@ -19,7 +19,7 @@ If any of the following conditions are violated, the result is Undefined Behavio bounds of that allocation. In particular, this range must not "wrap around" the edge of the address space. -Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset +Allocations can never be larger than `isize::MAX` bytes, so if the computed offset stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always safe. diff --git a/library/core/src/ptr/docs/as_uninit_slice.md b/library/core/src/ptr/docs/as_uninit_slice.md index c80c04058838f..1113f4748c2df 100644 --- a/library/core/src/ptr/docs/as_uninit_slice.md +++ b/library/core/src/ptr/docs/as_uninit_slice.md @@ -10,24 +10,24 @@ When calling this method, you have to ensure that *either* the pointer is null * all of the following is true: * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, -and it must be properly aligned. This means in particular: + and it must be properly aligned. This means in particular: * The entire memory range of this slice must be contained within a single [allocation]! -Slices can never span across multiple allocations. + Slices can never span across multiple allocations. * The pointer must be aligned even for zero-length slices. One -reason for this is that enum layout optimizations may rely on references -(including slices of any length) being aligned and non-null to distinguish -them from other data. You can obtain a pointer that is usable as `data` -for zero-length slices using [`NonNull::dangling()`]. + reason for this is that enum layout optimizations may rely on references + (including slices of any length) being aligned and non-null to distinguish + them from other data. You can obtain a pointer that is usable as `data` + for zero-length slices using [`NonNull::dangling()`]. * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. -See the safety documentation of [`pointer::offset`]. + See the safety documentation of [`pointer::offset`]. * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is -arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. -In particular, while this reference exists, the memory the pointer points to must -not get mutated (except inside `UnsafeCell`). + arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. + In particular, while this reference exists, the memory the pointer points to must + not get mutated (except inside `UnsafeCell`). This applies even if the result of this method is unused! diff --git a/library/core/src/ptr/docs/offset.md b/library/core/src/ptr/docs/offset.md index f2e335a79a5c2..f04f5606ab297 100644 --- a/library/core/src/ptr/docs/offset.md +++ b/library/core/src/ptr/docs/offset.md @@ -16,7 +16,7 @@ bounds of that allocation. In particular, this range must not "wrap around" the of the address space. Note that "range" here refers to a half-open range as usual in Rust, i.e., `self..result` for non-negative offsets and `result..self` for negative offsets. -Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset +Allocations can never be larger than `isize::MAX` bytes, so if the computed offset stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always safe. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 0a77caa98eda1..6e537d6c15079 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -28,7 +28,8 @@ //! undefined behavior to perform two concurrent accesses to the same location from different //! threads unless both accesses only read from memory. Notice that this explicitly //! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot -//! be used for inter-thread synchronization. +//! be used for inter-thread synchronization, regardless of whether they are acting on +//! Rust memory or not. //! * The result of casting a reference to a pointer is valid for as long as the //! underlying allocation is live and no reference (just raw pointers) is used to //! access the same memory. That is, reference and pointer accesses cannot be @@ -114,6 +115,10 @@ //! fully contiguous (i.e., has no "holes"), there is no guarantee that this //! will not change in the future. //! +//! Allocations must behave like "normal" memory: in particular, reads must not have +//! side-effects, and writes must become visible to other threads using the usual synchronization +//! primitives. +//! //! For any allocation with `base` address, `size`, and a set of //! `addresses`, the following are guaranteed: //! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base + @@ -2023,54 +2028,61 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { } } -/// Performs a volatile read of the value from `src` without moving it. This -/// leaves the memory in `src` unchanged. -/// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. -/// -/// # Notes -/// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. -/// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// Performs a volatile read of the value from `src` without moving it. +/// +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally +/// observable events (just like syscalls, but less opaque), and are guaranteed to not be elided or +/// reordered by the compiler across other externally observable events. With this in mind, there +/// are two cases of usage that need to be distinguished: +/// +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like +/// [`read`], except for the additional guarantee that it won't be elided or reordered (see +/// above). This implies that the operation will actually access memory and not e.g. be lowered to +/// reusing data from a previous read. Other than that, all the usual rules for memory accesses +/// apply (including provenance). In particular, just like in C, whether an operation is volatile +/// has no bearing whatsoever on questions involving concurrent accesses from multiple threads. +/// Volatile accesses behave exactly like non-atomic accesses in that regard. +/// +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust +/// allocation. In this use-case, the pointer does *not* have to be [valid] for reads. This is +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special +/// semantics associated to their manipulation, and cannot be used as general purpose memory. +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics +/// of such a read are well-defined by the target hardware. The provenance of the pointer is +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This +/// access is still not considered [atomic], and as such it cannot be used for inter-thread +/// synchronization. +/// +/// Note that volatile memory operations where T is a zero-sized type are noops and may be ignored. +/// +/// [allocation]: crate::ptr#allocated-object +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses /// /// # Safety /// +/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of whether `T` is +/// [`Copy`]. If `T` is not [`Copy`], using both the returned value and the value at `*src` can +/// [violate memory safety][read-ownership]. However, storing non-[`Copy`] types in volatile memory +/// is almost certainly incorrect. +/// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid] for reads. +/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust +/// allocations and reading from that memory must: +/// - not trap, and +/// - not cause any memory inside a Rust allocation to be modified. /// /// * `src` must be properly aligned. /// -/// * `src` must point to a properly initialized value of type `T`. -/// -/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned -/// value and the value at `*src` can [violate memory safety][read-ownership]. -/// However, storing non-[`Copy`] types in volatile memory is almost certainly -/// incorrect. +/// * Reading from `src` must produce a properly initialized value of type `T`. /// /// Note that even if `T` has size `0`, the pointer must be properly aligned. /// /// [valid]: self#safety /// [read-ownership]: read#ownership-of-the-returned-value /// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `read_volatile` and any write operation to the same location -/// is undefined behavior. -/// /// # Examples /// /// Basic usage: @@ -2093,50 +2105,63 @@ pub unsafe fn read_volatile(src: *const T) -> T { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::read_volatile requires that the pointer argument is aligned and non-null", + "ptr::read_volatile requires that the pointer argument is aligned", ( addr: *const () = src as *const (), align: usize = align_of::(), - is_zst: bool = T::IS_ZST, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned(addr, align) ); intrinsics::volatile_load(src) } } -/// Performs a volatile write of a memory location with the given value without -/// reading or dropping the old value. -/// -/// Volatile operations are intended to act on I/O memory, and are guaranteed -/// to not be elided or reordered by the compiler across other volatile -/// operations. -/// -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care should be taken not to overwrite -/// an object that should be dropped. -/// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. -/// -/// # Notes -/// -/// Rust does not currently have a rigorously and formally defined memory model, -/// so the precise semantics of what "volatile" means here is subject to change -/// over time. That being said, the semantics will almost always end up pretty -/// similar to [C11's definition of volatile][c11]. -/// -/// The compiler shouldn't change the relative order or number of volatile -/// memory operations. However, volatile memory operations on zero-sized types -/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops -/// and may be ignored. -/// -/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +/// Performs a volatile write of a memory location with the given value without reading or dropping +/// the old value. +/// +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally +/// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the +/// compiler across other externally observable events. With this in mind, there are two cases of +/// usage that need to be distinguished: +/// +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like +/// [`write`][write()], except for the additional guarantee that it won't be elided or reordered +/// (see above). This implies that the operation will actually access memory and not e.g. be +/// lowered to a register access. Other than that, all the usual rules for memory accesses apply +/// (including provenance). In particular, just like in C, whether an operation is volatile has no +/// bearing whatsoever on questions involving concurrent access from multiple threads. Volatile +/// accesses behave exactly like non-atomic accesses in that regard. +/// +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust +/// allocation. In this use-case, the pointer does *not* have to be [valid] for writes. This is +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special +/// semantics associated to their manipulation, and cannot be used as general purpose memory. +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics +/// of such a write are well-defined by the target hardware. The provenance of the pointer is +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This +/// access is still not considered [atomic], and as such it cannot be used for inter-thread +/// synchronization. +/// +/// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed +/// to `write_volatile`) are noops and may be ignored. +/// +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care should be taken not to overwrite an object that should be +/// dropped when operating on Rust memory. Additionally, it does not drop `src`. Semantically, `src` +/// is moved into the location pointed to by `dst`. +/// +/// [allocation]: crate::ptr#allocated-object +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses /// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid] for writes. +/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust +/// allocations and writing to that memory must: +/// - not trap, and +/// - not cause any memory inside a Rust allocation to be modified. /// /// * `dst` must be properly aligned. /// @@ -2144,12 +2169,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// [valid]: self#safety /// -/// Just like in C, whether an operation is volatile has no bearing whatsoever -/// on questions involving concurrent access from multiple threads. Volatile -/// accesses behave exactly like non-atomic accesses in that regard. In particular, -/// a race between a `write_volatile` and any other operation (reading or writing) -/// on the same location is undefined behavior. -/// /// # Examples /// /// Basic usage: @@ -2174,12 +2193,11 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::write_volatile requires that the pointer argument is aligned and non-null", + "ptr::write_volatile requires that the pointer argument is aligned", ( addr: *mut () = dst as *mut (), align: usize = align_of::(), - is_zst: bool = T::IS_ZST, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned(addr, align) ); intrinsics::volatile_store(dst, src); } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index c1bd14c8b630c..4d7e0b96b3532 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -2000,10 +2000,11 @@ impl *mut [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + pub const unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked_mut(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 53ee523693a7b..f932de4c05250 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1796,11 +1796,12 @@ impl NonNull<[T]> { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] #[requires(ub_checks::can_dereference(self.as_ptr()))] // Ensure self can be dereferenced - pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + pub const unsafe fn get_unchecked_mut(self, index: I) -> NonNull where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. // As a consequence, the resulting pointer cannot be null. diff --git a/library/core/src/random.rs b/library/core/src/random.rs index 051fe26086389..8a51fb289d8f3 100644 --- a/library/core/src/random.rs +++ b/library/core/src/random.rs @@ -1,48 +1,46 @@ //! Random value generation. -//! -//! The [`Random`] trait allows generating a random value for a type using a -//! given [`RandomSource`]. + +use crate::range::RangeFull; /// A source of randomness. #[unstable(feature = "random", issue = "130703")] pub trait RandomSource { /// Fills `bytes` with random bytes. + /// + /// Note that calling `fill_bytes` multiple times is not equivalent to calling `fill_bytes` once + /// with a larger buffer. A `RandomSource` is allowed to return different bytes for those two + /// cases. For instance, this allows a `RandomSource` to generate a word at a time and throw + /// part of it away if not needed. fn fill_bytes(&mut self, bytes: &mut [u8]); } -/// A trait for getting a random value for a type. -/// -/// **Warning:** Be careful when manipulating random values! The -/// [`random`](Random::random) method on integers samples them with a uniform -/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using -/// modulo operations, some of the resulting values can become more likely than -/// others. Use audited crates when in doubt. +/// A trait representing a distribution of random values for a type. #[unstable(feature = "random", issue = "130703")] -pub trait Random: Sized { - /// Generates a random value. - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self; +pub trait Distribution { + /// Samples a random value from the distribution, using the specified random source. + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> T; +} + +impl> Distribution for &DT { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> T { + (*self).sample(source) + } } -impl Random for bool { - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { - u8::random(source) & 1 == 1 +impl Distribution for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> bool { + let byte: u8 = RangeFull.sample(source); + byte & 1 == 1 } } macro_rules! impl_primitive { ($t:ty) => { - impl Random for $t { - /// Generates a random value. - /// - /// **Warning:** Be careful when manipulating the resulting value! This - /// method samples according to a uniform distribution, so a value of 1 is - /// just as likely as [`MAX`](Self::MAX). By using modulo operations, some - /// values can become more likely than others. Use audited crates when in - /// doubt. - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { - let mut bytes = (0 as Self).to_ne_bytes(); + impl Distribution<$t> for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> $t { + let mut bytes = (0 as $t).to_ne_bytes(); source.fill_bytes(&mut bytes); - Self::from_ne_bytes(bytes) + <$t>::from_ne_bytes(bytes) } } }; diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2276112a27bb3..5cd7956291ca2 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -186,14 +186,17 @@ impl IntoBounds for Range { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::Range { #[inline] fn from(value: Range) -> Self { Self { start: value.start, end: value.end } } } + #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for Range { #[inline] fn from(value: legacy::Range) -> Self { Self { start: value.start, end: value.end } @@ -362,7 +365,8 @@ impl IntoBounds for RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeInclusive { #[inline] fn from(value: RangeInclusive) -> Self { Self::new(value.start, value.end) @@ -506,14 +510,16 @@ impl IntoBounds for RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeFrom { #[inline] fn from(value: RangeFrom) -> Self { Self { start: value.start } } } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for RangeFrom { #[inline] fn from(value: legacy::RangeFrom) -> Self { Self { start: value.start } diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 5ce72b46eee36..1eda8bc1bec40 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -8,9 +8,10 @@ use crate::num::NonZero; use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[U]> for [T] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq<[U]> for [T] where - T: PartialEq, + T: ~const PartialEq, { fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) @@ -94,6 +95,8 @@ impl PartialOrd for [T] { #[doc(hidden)] // intermediate trait for specialization of slice's PartialEq +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; @@ -103,9 +106,10 @@ trait SlicePartialEq { } // Generic slice equality -impl SlicePartialEq for [A] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialEq for [A] where - A: PartialEq, + A: ~const PartialEq, { default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { @@ -115,11 +119,14 @@ where // Implemented as explicit indexing rather // than zipped iterators for performance reasons. // See PR https://github.com/rust-lang/rust/pull/116846 - for idx in 0..self.len() { + // FIXME(const_hack): make this a `for idx in 0..self.len()` loop. + let mut idx = 0; + while idx < self.len() { // bound checks are optimized away if self[idx] != other[idx] { return false; } + idx += 1; } true @@ -128,9 +135,10 @@ where // When each element can be compared byte-wise, we can compare all the bytes // from the whole size in one call to the intrinsics. -impl SlicePartialEq for [A] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialEq for [A] where - A: BytewiseEq, + A: ~const BytewiseEq, { fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index f725c3fdd94cc..322b3580eded2 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { type Output = I::Output; @@ -19,9 +20,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { #[inline(always)] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -158,6 +160,8 @@ mod private_slice_index { message = "the type `{T}` cannot be indexed by `{Self}`", label = "slice indices are of type `usize` or ranges of `usize`" )] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -208,7 +212,8 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The methods `index` and `index_mut` panic if the index is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -278,7 +283,8 @@ unsafe impl SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range` (which might be `100..3`). -unsafe impl SliceIndex<[T]> for ops::IndexRange { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::IndexRange { type Output = [T]; #[inline] @@ -354,7 +360,8 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -453,7 +460,8 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::Range { type Output = [T]; #[inline] @@ -491,7 +499,8 @@ unsafe impl SliceIndex<[T]> for range::Range { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -529,7 +538,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeTo { /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -574,7 +584,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; #[inline] @@ -611,7 +622,8 @@ unsafe impl SliceIndex<[T]> for range::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -650,7 +662,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFull { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -693,7 +706,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeInclusive { type Output = [T]; #[inline] @@ -731,7 +745,8 @@ unsafe impl SliceIndex<[T]> for range::RangeInclusive { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 40602fa4c5a50..1a38ad5cd61fa 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -572,9 +572,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get(&self, index: I) -> Option<&I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get(self) } @@ -598,9 +599,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get_mut(self) } @@ -637,9 +639,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; // the slice is dereferenceable because `self` is a safe reference. @@ -681,9 +684,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; // the slice is dereferenceable because `self` is a safe reference. @@ -971,7 +975,7 @@ impl [T] { /// assert!(v == [3, 2, 1]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_reverse", issue = "135120")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn reverse(&mut self) { let half_len = self.len() / 2; @@ -1004,6 +1008,7 @@ impl [T] { // this check tells LLVM that the indexing below is // in-bounds. Then after inlining -- once the actual // lengths of the slices are known -- it's removed. + // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]); let (a, _) = a.split_at_mut(n); let (b, _) = b.split_at_mut(n); @@ -5262,7 +5267,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for &[T] { /// Creates an empty slice. fn default() -> Self { @@ -5271,7 +5276,7 @@ impl const Default for &[T] { } #[stable(feature = "mut_slice_default", since = "1.5.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for &mut [T] { /// Creates a mutable empty slice. fn default() -> Self { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 32a2298817538..029abf1753913 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -589,8 +589,9 @@ impl str { /// assert!(v.get(..42).is_none()); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get>(&self, i: I) -> Option<&I::Output> { + pub const fn get>(&self, i: I) -> Option<&I::Output> { i.get(self) } @@ -621,8 +622,9 @@ impl str { /// assert_eq!("HEllo", v); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + pub const fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { i.get_mut(self) } @@ -952,6 +954,7 @@ impl str { /// /// The caller must ensure that `mid` is a valid byte offset from the start /// of the string and falls on the boundary of a UTF-8 code point. + #[inline] const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) { let len = self.len(); let ptr = self.as_ptr(); @@ -2648,7 +2651,6 @@ impl str { /// you're trying to parse into. /// /// `parse` can parse into any type that implements the [`FromStr`] trait. - /// /// # Errors /// @@ -3072,7 +3074,7 @@ impl AsRef<[u8]> for str { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for &str { /// Creates an empty str #[inline] @@ -3082,7 +3084,7 @@ impl const Default for &str { } #[stable(feature = "default_mut_str", since = "1.28.0")] -#[rustc_const_unstable(feature = "const_default", issue = "67792")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] impl const Default for &mut str { /// Creates an empty mutable str #[inline] diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b9559c8317133..d0f2b9226bf6d 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -23,7 +23,8 @@ impl Ord for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for str { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for str { #[inline] fn eq(&self, other: &str) -> bool { self.as_bytes() == other.as_bytes() @@ -49,9 +50,10 @@ impl PartialOrd for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for str where - I: SliceIndex, + I: ~const SliceIndex, { type Output = I::Output; @@ -62,9 +64,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for str where - I: SliceIndex, + I: ~const SliceIndex, { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -92,7 +95,8 @@ const fn str_index_overflow_fail() -> ! { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -156,7 +160,8 @@ unsafe impl SliceIndex for ops::RangeFull { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -260,7 +265,8 @@ unsafe impl SliceIndex for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -431,7 +437,8 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -499,7 +506,8 @@ unsafe impl SliceIndex for ops::RangeTo { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -554,7 +562,8 @@ unsafe impl SliceIndex for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -625,7 +634,8 @@ unsafe impl SliceIndex for range::RangeFrom { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -662,7 +672,8 @@ unsafe impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -713,7 +724,8 @@ unsafe impl SliceIndex for range::RangeInclusive { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 9cf08e74ff692..23a0a6877df77 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -3,7 +3,6 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; use crate::ops::ControlFlow::{self, Break, Continue}; -use crate::random::{Random, RandomSource}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -131,16 +130,6 @@ macro_rules! tuple_impls { } } - maybe_tuple_doc! { - $($T)+ @ - #[unstable(feature = "random", issue = "130703")] - impl<$($T: Random),+> Random for ($($T,)+) { - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { - ($({ let x: $T = Random::random(source); x},)+) - } - } - } - maybe_tuple_doc! { $($T)+ @ #[stable(feature = "array_tuple_conv", since = "1.71.0")] diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 6c217fa2ffaad..8b937ed48b848 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -120,13 +120,25 @@ pub(crate) const fn maybe_is_aligned_and_not_null( align: usize, is_zst: bool, ) -> bool { + // This is just for safety checks so we can const_eval_select. + maybe_is_aligned(ptr, align) && (is_zst || !ptr.is_null()) +} + +/// Checks whether `ptr` is properly aligned with respect to the given alignment. +/// +/// In `const` this is approximate and can fail spuriously. It is primarily intended +/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the +/// check is anyway not executed in `const`. +#[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_aligned(ptr: *const (), align: usize) -> bool { // This is just for safety checks so we can const_eval_select. const_eval_select!( - @capture { ptr: *const (), align: usize, is_zst: bool } -> bool: + @capture { ptr: *const (), align: usize } -> bool: if const { - is_zst || !ptr.is_null() + true } else { - ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) + ptr.is_aligned_to(align) } ) } diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 38df09a91c103..36d6a20a94427 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,9 +1,7 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -38,160 +36,9 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; /// Second pattern over the mantissa const NAN_MASK2: u128 = 0x00005555555555555555555555555555; -#[test] -fn test_num_f128() { - // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` - // function is available on all platforms. - let ten = 10f128; - let two = 2f128; - assert_biteq!(ten.add(two), ten + two); - assert_biteq!(ten.sub(two), ten - two); - assert_biteq!(ten.mul(two), ten * two); - assert_biteq!(ten.div(two), ten / two); - #[cfg(any(miri, target_has_reliable_f128_math))] - assert_biteq!(core::ops::Rem::rem(ten, two), ten % two); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f128 = f128::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f128 = 0.0f128; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f128 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f128 = 1.0f128; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f6749d796cca9..351c008a37bab 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f16)] use std::f16::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -43,151 +42,9 @@ const NAN_MASK1: u16 = 0x02aa; /// Second pattern over the mantissa const NAN_MASK2: u16 = 0x0155; -#[test] -fn test_num_f16() { - super::test_num(10f16, 2f16); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f16 = f16::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f16 = 0.0f16; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f16 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f16 = 1.0f16; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index f5d5723fea455..267b0e4e29434 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,6 +1,5 @@ use core::f32; use core::f32::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -30,148 +29,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_num_f32() { - super::test_num(10f32, 2f32); -} - -#[test] -fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f32 = 0.0f32; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f32 = 1.0f32; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 34af87c241e91..735b7a7651519 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,6 +1,5 @@ use core::f64; use core::f64::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -25,147 +24,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_num_f64() { - super::test_num(10f64, 2f64); -} - -#[test] -fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f64 = 0.0f64; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f64 = 1.0f64; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 36743a7d6df9e..43431bba6954b 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,28 +1,40 @@ -use std::fmt; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Set the default tolerance for float comparison based on the type. -trait Approx { - const LIM: Self; +trait TestableFloat { + /// Set the default tolerance for float comparison based on the type. + const APPROX: Self; + const MIN_POSITIVE_NORMAL: Self; + const MAX_SUBNORMAL: Self; } -impl Approx for f16 { - const LIM: Self = 1e-3; +impl TestableFloat for f16 { + const APPROX: Self = 1e-3; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f32 { - const LIM: Self = 1e-6; + +impl TestableFloat for f32 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f64 { - const LIM: Self = 1e-6; + +impl TestableFloat for f64 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f128 { - const LIM: Self = 1e-9; + +impl TestableFloat for f128 { + const APPROX: Self = 1e-9; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { - T::LIM +const fn lim_for_ty(_x: T) -> T { + T::APPROX } // We have runtime ("rt") and const versions of these macros. @@ -187,9 +199,11 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use super::Approx; + use super::TestableFloat; #[allow(unused)] use std::num::FpCategory as Fp; + #[allow(unused)] + use std::ops::{Add, Div, Mul, Rem, Sub}; // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] use $crate::floats::{ @@ -229,30 +243,42 @@ macro_rules! float_test { }; } -/// Helper function for testing numeric operations -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - mod f128; mod f16; mod f32; mod f64; +float_test! { + name: num, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.add(two), ten + two); + assert_biteq!(ten.sub(two), ten - two); + assert_biteq!(ten.mul(two), ten * two); + assert_biteq!(ten.div(two), ten / two); + } +} + +// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on +// all platforms. +float_test! { + name: num_rem, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.rem(two), ten % two); + } +} + float_test! { name: nan, attrs: { @@ -273,6 +299,213 @@ float_test! { } } +float_test! { + name: infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let inf: Float = Float::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert!(matches!(inf.classify(), Fp::Infinite)); + } +} + +float_test! { + name: neg_infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_inf: Float = Float::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + } +} + +float_test! { + name: zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let zero: Float = 0.0; + assert_biteq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert!(matches!(zero.classify(), Fp::Zero)); + } +} + +float_test! { + name: neg_zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_zero: Float = -0.0; + assert!(0.0 == neg_zero); + assert_biteq!(-0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + } +} + +float_test! { + name: one, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let one: Float = 1.0; + assert_biteq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert!(matches!(one.classify(), Fp::Normal)); + } +} + +float_test! { + name: is_nan, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 5.3; + let neg: Float = -10.732; + assert!(nan.is_nan()); + assert!(!zero.is_nan()); + assert!(!pos.is_nan()); + assert!(!neg.is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } +} + +float_test! { + name: is_infinite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!zero.is_infinite()); + assert!(!pos.is_infinite()); + assert!(!neg.is_infinite()); + } +} + +float_test! { + name: is_finite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(zero.is_finite()); + assert!(pos.is_finite()); + assert!(neg.is_finite()); + } +} + +float_test! { + name: is_normal, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one : Float = 1.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(one.is_normal()); + assert!(Float::MIN_POSITIVE_NORMAL.is_normal()); + assert!(!Float::MAX_SUBNORMAL.is_normal()); + } +} + +float_test! { + name: classify, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one: Float = 1.0; + assert!(matches!(nan.classify(), Fp::Nan)); + assert!(matches!(inf.classify(), Fp::Infinite)); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + assert!(matches!(zero.classify(), Fp::Zero)); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + assert!(matches!(one.classify(), Fp::Normal)); + assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal)); + assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal)); + } +} + float_test! { name: min, attrs: { diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index fbd3864dcac14..4074148436cf6 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -61,7 +61,7 @@ fn clear() { assert_eq!(rbuf.filled().len(), 0); assert_eq!(rbuf.unfilled().capacity(), 16); - assert_eq!(rbuf.unfilled().init_ref(), [255; 16]); + assert_eq!(rbuf.unfilled().init_mut(), [255; 16]); } #[test] @@ -124,7 +124,7 @@ fn reborrow_written() { assert_eq!(cursor2.written(), 32); assert_eq!(cursor.written(), 32); - assert_eq!(buf.unfilled().written(), 0); + assert_eq!(buf.unfilled().written(), 32); assert_eq!(buf.init_len(), 32); assert_eq!(buf.filled().len(), 32); let filled = buf.filled(); @@ -142,9 +142,7 @@ fn cursor_set_init() { } assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); rbuf.unfilled().advance(4); @@ -160,8 +158,42 @@ fn cursor_set_init() { } assert_eq!(rbuf.init_len(), 12); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); } + +#[test] +fn cursor_with_unfilled_buf() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf = BorrowedBuf::from(buf); + let mut cursor = rbuf.unfilled(); + + cursor.with_unfilled_buf(|buf| { + buf.unfilled().append(&[1, 2, 3]); + assert_eq!(buf.filled(), &[1, 2, 3]); + }); + + assert_eq!(cursor.init_mut().len(), 0); + assert_eq!(cursor.written(), 3); + + cursor.with_unfilled_buf(|buf| { + assert_eq!(buf.capacity(), 13); + assert_eq!(buf.init_len(), 0); + + buf.unfilled().ensure_init(); + buf.unfilled().advance(4); + }); + + assert_eq!(cursor.init_mut().len(), 9); + assert_eq!(cursor.written(), 7); + + cursor.with_unfilled_buf(|buf| { + assert_eq!(buf.capacity(), 9); + assert_eq!(buf.init_len(), 9); + }); + + assert_eq!(cursor.init_mut().len(), 9); + assert_eq!(cursor.written(), 7); + + assert_eq!(rbuf.filled(), &[1, 2, 3, 0, 0, 0, 0]); +} diff --git a/library/coretests/tests/iter/adapters/cloned.rs b/library/coretests/tests/iter/adapters/cloned.rs index 78babb7feab18..0a3dd1ce46e81 100644 --- a/library/coretests/tests/iter/adapters/cloned.rs +++ b/library/coretests/tests/iter/adapters/cloned.rs @@ -31,7 +31,8 @@ fn test_cloned_side_effects() { .zip(&[1]); for _ in iter {} } - assert_eq!(count, 2); + // Zip documentation provides some leeway about side-effects + assert!([1, 2].iter().any(|v| *v == count)); } #[test] diff --git a/library/coretests/tests/iter/adapters/zip.rs b/library/coretests/tests/iter/adapters/zip.rs index 70392dca0fa17..063e226a61ce0 100644 --- a/library/coretests/tests/iter/adapters/zip.rs +++ b/library/coretests/tests/iter/adapters/zip.rs @@ -107,9 +107,19 @@ fn test_zip_next_back_side_effects_exhausted() { iter.next(); iter.next(); iter.next(); - iter.next(); + assert_eq!(iter.next(), None); assert_eq!(iter.next_back(), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + + assert!(a.starts_with(&[1, 2, 3])); + let a_len = a.len(); + // Tail-side-effects of forward-iteration are "at most one" per next(). + // And for reverse iteration we don't guarantee much either. + // But we can put some bounds on the possible behaviors. + assert!(a_len <= 6); + assert!(a_len >= 3); + a.sort(); + assert_eq!(a, &[1, 2, 3, 4, 5, 6][..a.len()]); + assert_eq!(b, vec![200, 300, 400]); } @@ -120,7 +130,8 @@ fn test_zip_cloned_sideffectful() { for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - assert_eq!(&xs, &[1, 1, 1, 0][..]); + // Zip documentation permits either case. + assert!([&[1, 1, 1, 0], &[1, 1, 0, 0]].iter().any(|v| &xs == *v)); assert_eq!(&ys, &[1, 1][..]); let xs = [CountClone::new(), CountClone::new()]; @@ -139,7 +150,8 @@ fn test_zip_map_sideffectful() { for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + // Zip documentation permits either case. + assert!([&[1, 1, 1, 1, 1, 0], &[1, 1, 1, 1, 0, 0]].iter().any(|v| &xs == *v)); assert_eq!(&ys, &[1, 1, 1, 1]); let mut xs = [0; 4]; @@ -168,7 +180,8 @@ fn test_zip_map_rev_sideffectful() { { let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - (&mut it).take(5).count(); + // the current impl only trims the tails if the iterator isn't exhausted + (&mut it).take(3).count(); it.next_back(); } assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); @@ -211,9 +224,18 @@ fn test_zip_nth_back_side_effects_exhausted() { iter.next(); iter.next(); iter.next(); - iter.next(); + assert_eq!(iter.next(), None); assert_eq!(iter.nth_back(0), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert!(a.starts_with(&[1, 2, 3])); + let a_len = a.len(); + // Tail-side-effects of forward-iteration are "at most one" per next(). + // And for reverse iteration we don't guarantee much either. + // But we can put some bounds on the possible behaviors. + assert!(a_len <= 6); + assert!(a_len >= 3); + a.sort(); + assert_eq!(a, &[1, 2, 3, 4, 5, 6][..a.len()]); + assert_eq!(b, vec![200, 300, 400]); } @@ -237,32 +259,6 @@ fn test_zip_trusted_random_access_composition() { assert_eq!(z2.next().unwrap(), ((1, 1), 1)); } -#[test] -#[cfg(panic = "unwind")] -fn test_zip_trusted_random_access_next_back_drop() { - use std::panic::{AssertUnwindSafe, catch_unwind}; - - let mut counter = 0; - - let it = [42].iter().map(|e| { - let c = counter; - counter += 1; - if c == 0 { - panic!("bomb"); - } - - e - }); - let it2 = [(); 0].iter(); - let mut zip = it.zip(it2); - catch_unwind(AssertUnwindSafe(|| { - zip.next_back(); - })) - .unwrap_err(); - assert!(zip.next().is_none()); - assert_eq!(counter, 1); -} - #[test] fn test_double_ended_zip() { let xs = [1, 2, 3, 4, 5, 6]; @@ -275,6 +271,63 @@ fn test_double_ended_zip() { assert_eq!(it.next(), None); } +#[test] +#[cfg(panic = "unwind")] +/// Regression test for #137255 +/// A previous implementation of Zip TrustedRandomAccess specializations tried to do a lot of work +/// to preserve side-effects of equalizing the iterator lengths during backwards iteration. +/// This lead to several cases of unsoundness, twice due to being left in an inconsistent state +/// after panics. +/// The new implementation does not try as hard, but we still need panic-safety. +fn test_nested_zip_panic_safety() { + use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; + use std::sync::atomic::{AtomicUsize, Ordering}; + + let mut panic = true; + // keeps track of how often element get visited, must be at most once each + let witness = [8, 9, 10, 11, 12].map(|i| (i, AtomicUsize::new(0))); + let a = witness.as_slice().iter().map(|e| { + e.1.fetch_add(1, Ordering::Relaxed); + if panic { + panic = false; + resume_unwind(Box::new(())) + } + e.0 + }); + // shorter than `a`, so `a` will get trimmed + let b = [1, 2, 3, 4].as_slice().iter().copied(); + // shorter still, so `ab` will get trimmed.` + let c = [5, 6, 7].as_slice().iter().copied(); + + // This will panic during backwards trimming. + let ab = zip(a, b); + // This being Zip + TrustedRandomAccess means it will only call `next_back`` + // during trimming and otherwise do calls `__iterator_get_unchecked` on `ab`. + let mut abc = zip(ab, c); + + assert_eq!(abc.len(), 3); + // This will first trigger backwards trimming before it would normally obtain the + // actual element if it weren't for the panic. + // This used to corrupt the internal state of `abc`, which then lead to + // TrustedRandomAccess safety contract violations in calls to `ab`, + // which ultimately lead to UB. + catch_unwind(AssertUnwindSafe(|| abc.next_back())).ok(); + // check for sane outward behavior after the panic, which indicates a sane internal state. + // Technically these outcomes are not required because a panic frees us from correctness obligations. + assert_eq!(abc.len(), 2); + assert_eq!(abc.next(), Some(((8, 1), 5))); + assert_eq!(abc.next_back(), Some(((9, 2), 6))); + for (i, (_, w)) in witness.iter().enumerate() { + let v = w.load(Ordering::Relaxed); + // required by TRA contract + assert!(v <= 1, "expected idx {i} to be visited at most once, actual: {v}"); + } + // Trimming panicked and should only run once, so this one won't be visited. + // Implementation detail, but not trying to run it again is what keeps + // things simple. + assert_eq!(witness[3].1.load(Ordering::Relaxed), 0); +} + #[test] fn test_issue_82282() { fn overflowed_zip(arr: &[i32]) -> impl Iterator { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index fdef736c0c0f7..4cfac9ecc2ab7 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -19,7 +19,7 @@ #![feature(const_deref)] #![feature(const_destruct)] #![feature(const_eval_select)] -#![feature(const_float_round_methods)] +#![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] #![feature(core_float_math)] diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 8ea92088a84ab..0042a6e8ece58 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.4", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ff326342989bc..162b4fdcc8ae2 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1471,11 +1471,11 @@ impl Literal { let mut error = None; let mut buf = Vec::with_capacity(symbol.len()); - unescape_c_str(symbol, |_span, c| match c { + unescape_c_str(symbol, |_span, res| match res { Ok(MixedUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) + buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes()) } - Ok(MixedUnit::HighByte(b)) => buf.push(b), + Ok(MixedUnit::HighByte(b)) => buf.push(b.get()), Err(err) => { if err.is_fatal() { error = Some(ConversionErrorKind::FailedToUnescape(err)); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7a20d8bc919e7..cde8654e3a0de 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -23,7 +23,7 @@ unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } -std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [ +std_detect = { path = "../stdarch/crates/std_detect", public = true, default-features = false, features = [ 'rustc-dep-of-std', ] } safety = { path = "../contracts/safety" } @@ -93,6 +93,9 @@ backtrace = [ 'object/rustc-dep-of-std', 'miniz_oxide/rustc-dep-of-std', ] +# Disable symbolization in backtraces. For use with -Zbuild-std. +# FIXME: Ideally this should be an additive backtrace-symbolization feature +backtrace-trace-only = [] panic-unwind = ["dep:panic_unwind"] compiler-builtins-c = ["alloc/compiler-builtins-c"] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 17c32d7a571c8..d351ee5e739d3 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -489,7 +489,7 @@ pub(crate) fn default_read_to_end( } }; - let unfilled_but_initialized = cursor.init_ref().len(); + let unfilled_but_initialized = cursor.init_mut().len(); let bytes_read = cursor.written(); let was_fully_initialized = read_buf.init_len() == buf_len; @@ -3053,7 +3053,7 @@ impl Read for Take { // The condition above guarantees that `self.limit` fits in `usize`. let limit = self.limit as usize; - let extra_init = cmp::min(limit, buf.init_ref().len()); + let extra_init = cmp::min(limit, buf.init_mut().len()); // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; @@ -3068,7 +3068,7 @@ impl Read for Take { let mut cursor = sliced_buf.unfilled(); let result = self.inner.read_buf(cursor.reborrow()); - let new_init = cursor.init_ref().len(); + let new_init = cursor.init_mut().len(); let filled = sliced_buf.len(); // cursor / sliced_buf / ibuf must drop here diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d8a60b6ae970a..e5b3c2f34cc48 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -330,7 +330,6 @@ #![feature(bstr_internals)] #![feature(char_internals)] #![feature(clone_to_uninit)] -#![feature(const_float_round_methods)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(duration_constants)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index e79ec2ae966ff..2bff73add33d6 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -44,7 +44,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor(self) -> f32 { core::f32::math::floor(self) @@ -67,7 +67,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil(self) -> f32 { core::f32::math::ceil(self) @@ -96,7 +96,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round(self) -> f32 { core::f32::math::round(self) @@ -123,7 +123,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round_ties_even(self) -> f32 { core::f32::math::round_ties_even(self) @@ -149,7 +149,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trunc(self) -> f32 { core::f32::math::trunc(self) @@ -173,7 +173,7 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn fract(self) -> f32 { core::f32::math::fract(self) diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 853417825f97a..b71e319f4074f 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -44,7 +44,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn floor(self) -> f64 { core::f64::math::floor(self) @@ -67,7 +67,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn ceil(self) -> f64 { core::f64::math::ceil(self) @@ -96,7 +96,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round(self) -> f64 { core::f64::math::round(self) @@ -123,7 +123,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn round_ties_even(self) -> f64 { core::f64::math::round_ties_even(self) @@ -149,7 +149,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trunc(self) -> f64 { core::f64::math::trunc(self) @@ -173,7 +173,7 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn fract(self) -> f64 { core::f64::math::fract(self) diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 69f0335315356..70c1113155656 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -67,7 +67,7 @@ pub use core::prelude::v1::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; -#[unstable(feature = "derive_const", issue = "none")] +#[unstable(feature = "derive_const", issue = "118304")] pub use core::prelude::v1::derive_const; // Do not `doc(no_inline)` either. diff --git a/library/std/src/random.rs b/library/std/src/random.rs index e7d4ab81df0ac..3994c5cfaf6f4 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -1,7 +1,4 @@ //! Random value generation. -//! -//! The [`Random`] trait allows generating a random value for a type using a -//! given [`RandomSource`]. #[unstable(feature = "random", issue = "130703")] pub use core::random::*; @@ -68,18 +65,11 @@ impl RandomSource for DefaultRandomSource { } } -/// Generates a random value with the default random source. +/// Generates a random value from a distribution, using the default random source. /// -/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and -/// will sample according to the same distribution as the underlying [`Random`] -/// trait implementation. See [`DefaultRandomSource`] for more information about -/// how randomness is sourced. -/// -/// **Warning:** Be careful when manipulating random values! The -/// [`random`](Random::random) method on integers samples them with a uniform -/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using -/// modulo operations, some of the resulting values can become more likely than -/// others. Use audited crates when in doubt. +/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and will sample +/// according to the same distribution as the underlying [`Distribution`] trait implementation. See +/// [`DefaultRandomSource`] for more information about how randomness is sourced. /// /// # Examples /// @@ -89,7 +79,7 @@ impl RandomSource for DefaultRandomSource { /// /// use std::random::random; /// -/// let bits: u128 = random(); +/// let bits: u128 = random(..); /// let g1 = (bits >> 96) as u32; /// let g2 = (bits >> 80) as u16; /// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16; @@ -101,6 +91,6 @@ impl RandomSource for DefaultRandomSource { /// /// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) #[unstable(feature = "random", issue = "130703")] -pub fn random() -> T { - T::random(&mut DefaultRandomSource) +pub fn random(dist: impl Distribution) -> T { + dist.sample(&mut DefaultRandomSource) } diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 571f0d14248e1..0c05f152ef84c 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -10,7 +10,7 @@ //! (some invariant is not being upheld). //! //! The specifics of how this "poisoned" state affects other threads -//! depend on the primitive. See [#Overview] bellow. +//! depend on the primitive. See [#Overview] below. //! //! For the alternative implementations that do not employ poisoning, //! see `std::sync::nonpoisoning`. diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index efa6a896dad8f..272d0fa4d1a19 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: return false; } - let mut hit = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; - - // `__rust_end_short_backtrace` means we are done hiding symbols - // for now. Print until we see `__rust_begin_short_backtrace`. - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_end_short_backtrace") { - print = true; - return; - } - if print && sym.contains("__rust_begin_short_backtrace") { - print = false; - return; - } - if !print { - omitted_count += 1; + if cfg!(feature = "backtrace-trace-only") { + const HEX_WIDTH: usize = 2 + 2 * size_of::(); + let frame_ip = frame.ip(); + res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); + } else { + let mut hit = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + + // `__rust_end_short_backtrace` means we are done hiding symbols + // for now. Print until we see `__rust_begin_short_backtrace`. + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_end_short_backtrace") { + print = true; + return; + } + if print && sym.contains("__rust_begin_short_backtrace") { + print = false; + return; + } + if !print { + omitted_count += 1; + } } } - } - if print { - if omitted_count > 0 { - debug_assert!(print_fmt == PrintFmt::Short); - // only print the message between the middle of frames - if !first_omit { - let _ = writeln!( - bt_fmt.formatter(), - " [... omitted {} frame{} ...]", - omitted_count, - if omitted_count > 1 { "s" } else { "" } - ); + if print { + if omitted_count > 0 { + debug_assert!(print_fmt == PrintFmt::Short); + // only print the message between the middle of frames + if !first_omit { + let _ = writeln!( + bt_fmt.formatter(), + " [... omitted {} frame{} ...]", + omitted_count, + if omitted_count > 1 { "s" } else { "" } + ); + } + first_omit = false; + omitted_count = 0; } - first_omit = false; - omitted_count = 0; + res = bt_fmt.frame().symbol(frame, symbol); } - res = bt_fmt.frame().symbol(frame, symbol); + }); + #[cfg(target_os = "nto")] + if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { + if !hit && print { + use crate::backtrace_rs::SymbolName; + res = bt_fmt.frame().print_raw( + frame.ip(), + Some(SymbolName::new("__my_thread_exit".as_bytes())), + None, + None, + ); + } + return false; } - }); - #[cfg(target_os = "nto")] - if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && print { - use crate::backtrace_rs::SymbolName; - res = bt_fmt.frame().print_raw( - frame.ip(), - Some(SymbolName::new("__my_thread_exit".as_bytes())), - None, - None, - ); + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } - return false; - } - if !hit && print { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } idx += 1; diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index ce975bb2289c2..b71d8b1357b5a 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -8,7 +8,8 @@ use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; -use crate::sync::OnceLock; +use crate::sync::atomic::Atomic; +use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; use crate::sys::c; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; @@ -114,33 +115,38 @@ pub(super) mod netc { #[expect(missing_debug_implementations)] pub struct Socket(OwnedSocket); -static WSA_CLEANUP: OnceLock i32> = OnceLock::new(); +static WSA_INITIALIZED: Atomic = Atomic::::new(false); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. +#[inline] pub fn init() { - let _ = WSA_CLEANUP.get_or_init(|| unsafe { + if !WSA_INITIALIZED.load(Relaxed) { + wsa_startup(); + } +} + +#[cold] +fn wsa_startup() { + unsafe { let mut data: c::WSADATA = mem::zeroed(); let ret = c::WSAStartup( 0x202, // version 2.2 &mut data, ); assert_eq!(ret, 0); - - // Only register `WSACleanup` if `WSAStartup` is actually ever called. - // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used. - // See issue #85441. - c::WSACleanup - }); + if WSA_INITIALIZED.swap(true, AcqRel) { + // If another thread raced with us and called WSAStartup first then call + // WSACleanup so it's as though WSAStartup was only called once. + c::WSACleanup(); + } + } } pub fn cleanup() { - // only perform cleanup if network functionality was actually initialized - if let Some(cleanup) = WSA_CLEANUP.get() { - unsafe { - cleanup(); - } - } + // We don't need to call WSACleanup here because exiting the process will cause + // the OS to clean everything for us, which is faster than doing it manually. + // See #141799. } /// Returns the last error from the Windows socket interface. diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index cbdaf439b2847..dea44124f458b 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -2,7 +2,7 @@ use crate::cmp; use crate::io::{ BorrowedCursor, Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult, }; -use crate::random::{DefaultRandomSource, Random}; +use crate::random::random; use crate::time::{Duration, Instant}; pub(crate) mod alloc; @@ -179,7 +179,7 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { // trusted to ensure accurate timeouts. if let Ok(timeout_signed) = i64::try_from(timeout) { let tenth = timeout_signed / 10; - let deviation = i64::random(&mut DefaultRandomSource).checked_rem(tenth).unwrap_or(0); + let deviation = random::(..).checked_rem(tenth).unwrap_or(0); timeout = timeout_signed.saturating_add(deviation) as _; } } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index eee169d410a9c..edac5262a4e9a 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -197,7 +197,7 @@ compat_fn_optional! { pub fn WakeByAddressSingle(address: *const c_void); } -#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))] +#[cfg(any(target_vendor = "win7"))] compat_fn_with_fallback! { pub static NTDLL: &CStr = c"ntdll"; @@ -228,65 +228,14 @@ compat_fn_with_fallback! { ) -> NTSTATUS { panic!("keyed events not available") } +} - // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically. - #[cfg(target_vendor = "uwp")] - pub fn NtCreateFile( - filehandle: *mut HANDLE, - desiredaccess: FILE_ACCESS_RIGHTS, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - allocationsize: *const i64, - fileattributes: FILE_FLAGS_AND_ATTRIBUTES, - shareaccess: FILE_SHARE_MODE, - createdisposition: NTCREATEFILE_CREATE_DISPOSITION, - createoptions: NTCREATEFILE_CREATE_OPTIONS, - eabuffer: *const c_void, - ealength: u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtOpenFile( - filehandle: *mut HANDLE, - desiredaccess: u32, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - shareaccess: u32, - openoptions: u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtReadFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *mut c_void, - length: u32, - byteoffset: *const i64, - key: *const u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtWriteFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *const c_void, - length: u32, - byteoffset: *const i64, - key: *const u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 { - Status as u32 +cfg_if::cfg_if! { + if #[cfg(target_vendor = "uwp")] { + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); } } diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 539f0fe89eaaa..407fdcebcf5cc 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -8,16 +8,18 @@ use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all}; // This means we only need one atomic value with 4 states: /// No initialization has run yet, and no thread is currently using the Once. -const INCOMPLETE: Primitive = 0; +const INCOMPLETE: Primitive = 3; /// Some thread has previously attempted to initialize the Once, but it panicked, /// so the Once is now poisoned. There are no other threads currently accessing /// this Once. -const POISONED: Primitive = 1; +const POISONED: Primitive = 2; /// Some thread is currently attempting to run initialization. It may succeed, /// so all future threads need to wait for it to finish. -const RUNNING: Primitive = 2; +const RUNNING: Primitive = 1; /// Initialization has completed and all future calls should finish immediately. -const COMPLETE: Primitive = 3; +/// By choosing this state as the all-zero state the `is_completed` check can be +/// a bit faster on some platforms. +const COMPLETE: Primitive = 0; // An additional bit indicates whether there are waiting threads: diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 6a2ab0dcf1b33..49e15d65f25a2 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -74,11 +74,12 @@ pub struct OnceState { } // Four states that a Once can be in, encoded into the lower bits of -// `state_and_queue` in the Once structure. -const INCOMPLETE: usize = 0x0; -const POISONED: usize = 0x1; -const RUNNING: usize = 0x2; -const COMPLETE: usize = 0x3; +// `state_and_queue` in the Once structure. By choosing COMPLETE as the all-zero +// state the `is_completed` check can be a bit faster on some platforms. +const INCOMPLETE: usize = 0x3; +const POISONED: usize = 0x2; +const RUNNING: usize = 0x1; +const COMPLETE: usize = 0x0; // Mask to learn about the state. All other bits are the queue of waiters if // this is in the RUNNING state. diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 7cd448733130d..0ad014ccd3e2e 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -469,6 +469,29 @@ impl LocalKey> { pub fn replace(&'static self, value: T) -> T { self.with(|cell| cell.replace(value)) } + + /// Updates the contained value using a function. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_update)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell = const { Cell::new(5) }; + /// } + /// + /// X.update(|x| x + 1); + /// assert_eq!(X.get(), 6); + /// ``` + #[unstable(feature = "local_key_cell_update", issue = "143989")] + pub fn update(&'static self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + self.with(|cell| cell.update(f)) + } } impl LocalKey> { diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 290c2eeed44c6..032f5272a9cd4 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,6 +20,7 @@ test = { path = "../test", public = true } [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] backtrace = ["std/backtrace"] +backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] compiler-builtins-mem = ["std/compiler-builtins-mem"] compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index bce54c5ffcef0..9e82e6a720006 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -7,8 +7,7 @@ #![feature(decl_macro)] #![feature(no_core)] -#[cfg(feature = "windows_raw_dylib")] -pub macro link { +pub macro link_raw_dylib { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))] #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))] @@ -18,6 +17,26 @@ pub macro link { } ) } + +pub macro link_dylib { + ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( + // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't + // have in this repo. So instead we always link kernel32.lib and add the rest of the import + // libraries below by using an empty extern block. This works because extern blocks are not + // connected to the library given in the #[link] attribute. + #[link(name = "kernel32")] + unsafe extern $abi { + $(#[link_name=$link_name])? + pub fn $($function)*; + } + ) +} + +#[cfg(feature = "windows_raw_dylib")] +pub macro link($($tt:tt)*) { + $crate::link_raw_dylib!($($tt)*) +} + #[cfg(not(feature = "windows_raw_dylib"))] pub macro link { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( diff --git a/rust-toolchain.toml b/rust-toolchain.toml index fed6a6a6c8410..82b33738ad241 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,5 +2,5 @@ # standard library we currently track. [toolchain] -channel = "nightly-2025-07-14" +channel = "nightly-2025-07-21" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] diff --git a/tool_config/kani-version.toml b/tool_config/kani-version.toml index a3cb1b760376d..8ad1d860155b6 100644 --- a/tool_config/kani-version.toml +++ b/tool_config/kani-version.toml @@ -2,4 +2,4 @@ # incompatible with the verify-std repo. [kani] -commit = "5af25b54e695e0480887ab2e978cd4dd05b7154c" +commit = "c1648416995a15b6ab33e44829e96c9a65541927"